ඔබේ කේතය ඉතා හොඳයි
ඔබ නියත වශයෙන්ම නිවැරදි වන අතර ඔබේ ගුරුවරයා වැරදිය. එම අතිරේක සංකීර්ණතාව එක් කිරීමට කිසිසේත්ම හේතුවක් නැත, මන්ද එය ප්රති result ලයට කිසිසේත් බලපාන්නේ නැත. එය දෝෂයක් පවා හඳුන්වා දෙයි. (පහත බලන්න)
පළමුව, n
ශුන්ය නම් වෙනම චෙක්පත පැහැදිලිවම සම්පූර්ණයෙන්ම අනවශ්ය වන අතර මෙය අවබෝධ කර ගැනීම ඉතා පහසුය. ඇත්තම කිව්වොත්, ඇත්ත වශයෙන්ම මම මේ ගැන ඔබේ ගුරුවරුන්ගේ විරෝධය ඇත්දැයි ප්රශ්න කරමි. නමුත් මම හිතන්නේ සෑම කෙනෙකුටම වරින් වර මොළයේ දුරක් තිබිය හැකිය. කෙසේ වෙතත්, while(n)
එය වෙනස් කළ යුතු යැයි මම සිතන්නේ while(n != 0)
එය අතිරේක රේඛාවක් පවා වැය නොකර ටිකක් පැහැදිලි බවක් එක් කරන බැවිනි. එය සුළු දෙයක් වුවද.
දෙවැන්න තව ටිකක් තේරුම් ගත හැකි නමුත් ඔහු තවමත් වැරදිය.
මෙය කුමක් ද C11 සම්මත 6.5.5.p6 පවසයි:
A / b යන අගය නිරූපණය කළ හැකි නම්, (a / b) * b + a% b ප්රකාශනය a ට සමාන වේ; එසේ නොමැතිනම්, a / b සහ% b යන දෙවර්ගයේම හැසිරීම නිර්වචනය කර නැත.
පාදසටහන මෙය පවසයි:
මෙය බොහෝ විට "ශුන්ය දෙසට කප්පාදු කිරීම" ලෙස හැඳින්වේ.
අදහස් ශුන්ය කරා කවලම් පරම අගය බව a/b
පරම අගය සමාන වේ (-a)/b
සියලු a
හාb
, අනෙක් අතට මාධ්යයන්ගේ ඔබේ කේතය සම්පූර්ණයෙන්ම ඒක යහපත් දෙයක්.
මොඩියුලෝ පහසු ගණිතය, නමුත් ප්රතිවිරුද්ධ විය හැකිය
කෙසේ වෙතත්, ඔබේ ගුරුවරයාට ඔබ පරෙස්සම් විය යුතු කරුණක් ඇත, මන්ද ඔබ ප්රති result ලය වර්ග කර තිබීම ඇත්ත වශයෙන්ම මෙහි තීරණාත්මක ය. a%b
ඉහත අර්ථ දැක්වීම අනුව ගණනය කිරීම පහසු ගණිතයකි, නමුත් එය ඔබගේ ප්රතිභාවට පටහැනි විය හැකිය. ගුණ කිරීම හා බෙදීම සඳහා, ඔපෙරන්ඩ් වලට සමාන ලකුණක් තිබේ නම් ප්රති result ලය ධනාත්මක වේ. නමුත් මොඩියුලෝ සම්බන්ධයෙන් ගත් කල, ප්රති result ලය පළමු ඔපෙරන්ඩ් එකට සමාන ලකුණක් ඇත . දෙවන ක්රියාකාරිත්වය ලකුණට කිසිසේත් බලපාන්නේ නැත. උදාහරණයක් ලෙස, 7%3==1
නමුත් (-7)%(-3)==(-1)
.
මෙන්න එය නිරූපණය කරන කුඩා කොටසක්:
$ cat > main.c
#include <stdio.h>
void f(int a, int b)
{
printf("a: %2d b: %2d a/b: %2d a\%b: %2d (a%b)^2: %2d (a/b)*b+a%b==a: %5s\n",
a, b ,a/b, a%b, (a%b)*(a%b), (a/b)*b+a%b == a ? "true" : "false");
}
int main(void)
{
int a=7, b=3;
f(a,b);
f(-a,b);
f(a,-b);
f(-a,-b);
}
$ gcc main.c -Wall -Wextra -pedantic -std=c99
$ ./a.out
a: 7 b: 3 a/b: 2 a%b: 1 (a%b)^2: 1 (a/b)*b+a%b==a: true
a: -7 b: 3 a/b: -2 a%b: -1 (a%b)^2: 1 (a/b)*b+a%b==a: true
a: 7 b: -3 a/b: -2 a%b: 1 (a%b)^2: 1 (a/b)*b+a%b==a: true
a: -7 b: -3 a/b: 2 a%b: -1 (a%b)^2: 1 (a/b)*b+a%b==a: true
ඉතින්, උත්ප්රාසාත්මක ලෙස, ඔබේ ගුරුවරයා ඔහුගේ කාරණය වැරදි බව ඔප්පු කළේය.
ඔබේ ගුරුවරයාගේ කේතය දෝෂ සහිතය
ඔව්, එය ඇත්තෙන්ම ය. ආදානය INT_MIN
සහ ගෘහ නිර්මාණ ශිල්පය දෙකේ අනුපූරකයක් නම් සහ සං bit ා බිට් 1 වන බිට් රටාව සහ සියලු අගය බිටු 0 යනු උගුල් අගයක් නොවේ (උගුල් අගයන් නොමැතිව දෙදෙනෙකුගේ අනුපූරකය භාවිතා කිරීම ඉතා සුලභ ය) එවිට ඔබේ ගුරුවරයාගේ කේතය නිර්වචනය නොකළ හැසිරීමක් ලබා දෙනු ඇත පේළියේ n = n * (-1)
. ඔබේ කේතය - කවදා හෝ තරමක් නම් - ඔහුට වඩා හොඳයි . කේතය අනවශ්ය ලෙස සංකීර්ණ කර නිරපේක්ෂ ශුන්ය අගයක් ලබා ගැනීමෙන් කුඩා දෝෂයක් හඳුන්වා දීම ගැන සලකා බැලීමේදී, ඔබේ කේතය වඩා හොඳ යැයි මම කියමි.
වෙනත් වචන වලින් කිවහොත්, INT_MIN = -32768 (එහි ප්රති function ලයක් ලෙස ලැබෙන ශ්රිතයට <-32768 හෝ> 32767 වන ආදානයක් ලැබිය නොහැකි වුවද), -32768 හි වලංගු ආදානය නිර්වචනය නොකළ හැසිරීමට හේතු වේ, මන්ද එහි ප්රති result ලය - (- 32768i16) බිටු 16 ක පූර්ණ සංඛ්යාවක් ලෙස ප්රකාශ කළ නොහැක. .
නමුත් ඔබේ ගුරුවරයා පැහැදිලිවම කියා සිටියේ n
එය [-10 ^ 7 පරාසයේ විය හැකි බවයි; 10 ^ 7]. බිටු 16 ක පූර්ණ සංඛ්යාවක් ඉතා කුඩා ය; ඔබට [අවම වශයෙන්] බිටු 32 ක පූර්ණ සංඛ්යාවක් භාවිතා කිරීමට සිදුවේ. භාවිතා int
කිරීම ඔහුගේ කේතය ආරක්ෂිත බව පෙනේ, int
එය අනිවාර්යයෙන්ම බිටු 32 ක පූර්ණ සංඛ්යාවක් නොවේ. ඔබ බිට් 16 ගෘහ නිර්මාණ ශිල්පයක් සඳහා සම්පාදනය කරන්නේ නම්, ඔබේ කේත ස්නිපෙට් දෙකම දෝෂ සහිතය. නමුත් ඔබේ කේතය තවමත් වඩා හොඳය, මන්ද මෙම තත්වය INT_MIN
ඔහුගේ අනුවාදය සමඟ ඉහත සඳහන් කළ දෝෂය නැවත හඳුන්වා දෙයි . මෙය වළක්වා ගැනීම සඳහා, ඔබට long
ඒ වෙනුවට ලිවිය හැකිය int
, එය ගෘහ නිර්මාණ ශිල්පය මත බිටු 32 ක පූර්ණ සංඛ්යාවක් වේ. long
[-2147483647 පරාසය තුළ ඕනෑම අගයක් රඳවා ගැනීමට A ට සහතික වේ; 2147483647]. C11 සම්මත 5.2.4.2.1 LONG_MIN
බොහෝ විට වේ-2147483648
නමුත් අවසර දී ඇති උපරිම අගය (ඔව්, උපරිම, එය negative ණ සංඛ්යාවක්) LONG_MIN
වේ 2147483647
.
මම ඔබේ කේතයේ කුමන වෙනස්කම් කරන්නද?
ඔබේ කේතය එයම හොඳයි, එබැවින් මේවා ඇත්ත වශයෙන්ම පැමිණිලි නොවේ. එය වඩාත් සමාන වන්නේ මට ඔබේ කේතය ගැන ඇත්ත වශයෙන්ම යමක් පැවසීමට අවශ්ය නම්, එය ඉතා සුළු වශයෙන් පැහැදිලි කළ හැකි කුඩා දේවල් කිහිපයක් තිබේ.
- විචල්යයන්ගේ නම් ටිකක් හොඳ විය හැකිය, නමුත් එය තේරුම් ගැනීමට පහසු කෙටි කාර්යයකි, එබැවින් එය විශාල ගනුදෙනුවක් නොවේ.
- ඔබ තත්ත්වය වෙනස් විය හැකි
n
කිරීමට n!=0
. අර්ථාන්විතව, එය 100% සමාන වේ, නමුත් එය ටිකක් පැහැදිලි කරයි.
- ප්රකාශය එහි භාවිතා කර ඇති බැවින්
c
(මම නැවත නම් කරන ලද digit
) කාල ලූපය තුළට ගෙන යන්න.
long
සම්පූර්ණ ආදාන කට්ටලය හැසිරවිය හැකි බව සහතික කිරීම සඳහා තර්ක වර්ගය වෙනස් කරන්න .
int sum_of_digits_squared(long n)
{
long sum = 0;
while (n != 0) {
int digit = n % 10;
sum += (digit * digit);
n /= 10;
}
return sum;
}
ඇත්ත වශයෙන්ම, මෙය ටිකක් නොමඟ යවන සුළු විය හැකිය - මන්ද ඉහත සඳහන් කළ පරිදි - විචල්යයට digit
negative ණ අගයක් ලබා ගත හැකි නමුත් ඉලක්කම් කිසි විටෙකත් ධනාත්මක හෝ .ණාත්මක නොවේ. මේ සඳහා ක්රම කිහිපයක් තිබේ, නමුත් මෙය සැබවින්ම නට්පික් කිරීමකි, එවැනි කුඩා විස්තර සඳහා මම තැකීමක් නොකරමි. විශේෂයෙන් අවසාන ඉලක්කම් සඳහා වෙනම ශ්රිතය එය බොහෝ දුරට ගෙන යයි. හාස්යයට කරුණක් නම්, මෙය ඔබගේ ගුරුවරුන්ගේ කේතය සැබවින්ම විසඳන එක් කරුණකි.
- විචල්යය සම්පූර්ණයෙන්ම වෙනස්
sum += (digit * digit)
කර sum += ((n%10)*(n%10))
මඟ හරින්න digit
.
- .ණ නම් ලකුණ වෙනස් කරන්න
digit
. නමුත් විචල්ය නාමයක් අර්ථවත් කිරීම සඳහා කේතය වඩාත් සංකීර්ණ කිරීමට එරෙහිව මම තරයේ අවවාද කරමි. එය ඉතා ශක්තිමත් කේත සුවඳකි.
- අවසාන ඉලක්කම් උපුටා ගන්නා වෙනම ශ්රිතයක් සාදන්න.
int last_digit(long n) { int digit=n%10; if (digit>=0) return digit; else return -digit; }
ඔබට එම ශ්රිතය වෙනත් තැනක භාවිතා කිරීමට අවශ්ය නම් මෙය ප්රයෝජනවත් වේ.
c
ඔබ මුලින් කරන ආකාරයටම එය නම් කරන්න. එම විචල්ය නාමය කිසිදු ප්රයෝජනවත් තොරතුරක් ලබා නොදෙන අතර අනෙක් අතට එය නොමඟ යවන සුළු නොවේ.
නමුත් අවංක වීමට නම්, මේ අවස්ථාවේදී ඔබ වඩාත් වැදගත් කාර්යයකට යා යුතුය. :)
n = n * (-1)
ලිවීමට හාස්යජනක ක්රමයකිn = -n
; ඒ ගැන සිතන්නේ පවා ශාස්ත්ර ic යෙකු පමණි. අතිරික්ත වරහන් එකතු කිරීමට ඉඩ දෙන්න.