My professor says my digit summing code is flawed. Is he right?Modulo operation with negative numbersModulo...
Prove the inequality is true
Non-Legendary Planeswalkers
Type and strength of a typical chain
Is It Possible to Make a Virus That Acts as an Anti-virus?
Is consistent disregard for students' time "normal" in undergraduate research?
What does IKEA-like mean?
Delete line if next line is the same
How to not lose focus after each disruption in flow
Why is lying to Congress a crime?
Numbering like equations for regular text
I'm largest when I'm five, what am I?
How could "aggressor" pilots fly foreign aircraft without speaking the language?
An employee has low self-confidence, and is performing poorly. How can I help?
5v home network
Why is coffee provided during big chess events when it contains a banned substance?
Print the sequence
Does these arithmetic means on Pythagorean triangles converge?
Dedicated solver for convex problems
Should a grammatical article be a part of a web link anchor
How can I make "acts of patience" exciting?
bash - sum numbers in a variable
Is self-defense mutually exclusive of murder?
Does Australia produce unique 'specialty steel'?
Is data science mathematically interesting?
My professor says my digit summing code is flawed. Is he right?
Modulo operation with negative numbersModulo operator with negative valuesHow is if statement evaluated in c++?Does either ANSI C or ISO C specify what -5 % 10 should be?Is negating INT_MIN undefined behaviour?Can I rely on % (modulo) operator in C for negative numbers?Variable leading zeroes in C99 printfSimple Rand() functionsscanf %u not intepreting hexadecimalC - Returning negative value as unsigned sets errno?Normalize random value of _int64strtoul of negative numberHow to get every digit from a number in C?
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty{
margin-bottom:0;
}
I recently had a test in my class. One of the problems was the following:
Given a number n, write a function in C/C++ that returns the sum of the digits of the number squared. (The following is important). The range of n is [ -(10^7), 10^7 ]. Example: If n = 123, your function should return 14 (1^2 + 2^2 + 3^2 = 14).
This is the function that I wrote:
int sum_of_digits_squared(int n)
{
int s = 0, c;
while (n) {
c = n % 10;
s += (c * c);
n /= 10;
}
return s;
}
Looked right to me. So now the test came back and I found that the teacher didn't give me all the points for a reason that I do not understand. According to him, for my function to be complete, I should've have added the following detail:
int sum_of_digits_squared(int n)
{
int s = 0, c;
if (n == 0) { //
return 0; //
} //
// THIS APPARENTLY SHOULD'VE
if (n < 0) { // BEEN IN THE FUNCTION FOR IT
n = n * (-1); // TO BE CORRECT
} //
while (n) {
c = n % 10;
s += (c * c);
n /= 10;
}
return s;
}
The argument for this is that the number n is in the range [-(10^7), 10^7], so it can be a negative number. But I don't see where my own version of the function fails. If I understand correctly, the meaning of while(n)
is while(n != 0)
, not while (n > 0)
, so in my version of the function the number n wouldn't fail to enter the loop. It would work just the same.
Then, I tried both versions of the function on my computer at home and I got exactly the same answers for all the examples that I tried. So, sum_of_digits_squared(-123)
is equal to sum_of_digits_squared(123)
(which again, is equal to 14
) (even without the detail that I apparently should've added). Indeed, if I try to print on the screen the digits of the number (from least to greatest in importance), in the 123
case I get 3 2 1
and in the -123
case I get -3 -2 -1
(which is actually kind of interesting). But in this problem it wouldn't matter since we square the digits.
So, who's wrong?
EDIT: My bad, I forgot to specify and didn't know it was important. The version of C used in our class and tests has to be C99 or newer. So I guess (by reading the comments) that my version would get the correct answer in any way.
c
add a comment
|
I recently had a test in my class. One of the problems was the following:
Given a number n, write a function in C/C++ that returns the sum of the digits of the number squared. (The following is important). The range of n is [ -(10^7), 10^7 ]. Example: If n = 123, your function should return 14 (1^2 + 2^2 + 3^2 = 14).
This is the function that I wrote:
int sum_of_digits_squared(int n)
{
int s = 0, c;
while (n) {
c = n % 10;
s += (c * c);
n /= 10;
}
return s;
}
Looked right to me. So now the test came back and I found that the teacher didn't give me all the points for a reason that I do not understand. According to him, for my function to be complete, I should've have added the following detail:
int sum_of_digits_squared(int n)
{
int s = 0, c;
if (n == 0) { //
return 0; //
} //
// THIS APPARENTLY SHOULD'VE
if (n < 0) { // BEEN IN THE FUNCTION FOR IT
n = n * (-1); // TO BE CORRECT
} //
while (n) {
c = n % 10;
s += (c * c);
n /= 10;
}
return s;
}
The argument for this is that the number n is in the range [-(10^7), 10^7], so it can be a negative number. But I don't see where my own version of the function fails. If I understand correctly, the meaning of while(n)
is while(n != 0)
, not while (n > 0)
, so in my version of the function the number n wouldn't fail to enter the loop. It would work just the same.
Then, I tried both versions of the function on my computer at home and I got exactly the same answers for all the examples that I tried. So, sum_of_digits_squared(-123)
is equal to sum_of_digits_squared(123)
(which again, is equal to 14
) (even without the detail that I apparently should've added). Indeed, if I try to print on the screen the digits of the number (from least to greatest in importance), in the 123
case I get 3 2 1
and in the -123
case I get -3 -2 -1
(which is actually kind of interesting). But in this problem it wouldn't matter since we square the digits.
So, who's wrong?
EDIT: My bad, I forgot to specify and didn't know it was important. The version of C used in our class and tests has to be C99 or newer. So I guess (by reading the comments) that my version would get the correct answer in any way.
c
Comments are not for extended discussion; this conversation has been moved to chat.
– Brad Larson♦
4 hours ago
add a comment
|
I recently had a test in my class. One of the problems was the following:
Given a number n, write a function in C/C++ that returns the sum of the digits of the number squared. (The following is important). The range of n is [ -(10^7), 10^7 ]. Example: If n = 123, your function should return 14 (1^2 + 2^2 + 3^2 = 14).
This is the function that I wrote:
int sum_of_digits_squared(int n)
{
int s = 0, c;
while (n) {
c = n % 10;
s += (c * c);
n /= 10;
}
return s;
}
Looked right to me. So now the test came back and I found that the teacher didn't give me all the points for a reason that I do not understand. According to him, for my function to be complete, I should've have added the following detail:
int sum_of_digits_squared(int n)
{
int s = 0, c;
if (n == 0) { //
return 0; //
} //
// THIS APPARENTLY SHOULD'VE
if (n < 0) { // BEEN IN THE FUNCTION FOR IT
n = n * (-1); // TO BE CORRECT
} //
while (n) {
c = n % 10;
s += (c * c);
n /= 10;
}
return s;
}
The argument for this is that the number n is in the range [-(10^7), 10^7], so it can be a negative number. But I don't see where my own version of the function fails. If I understand correctly, the meaning of while(n)
is while(n != 0)
, not while (n > 0)
, so in my version of the function the number n wouldn't fail to enter the loop. It would work just the same.
Then, I tried both versions of the function on my computer at home and I got exactly the same answers for all the examples that I tried. So, sum_of_digits_squared(-123)
is equal to sum_of_digits_squared(123)
(which again, is equal to 14
) (even without the detail that I apparently should've added). Indeed, if I try to print on the screen the digits of the number (from least to greatest in importance), in the 123
case I get 3 2 1
and in the -123
case I get -3 -2 -1
(which is actually kind of interesting). But in this problem it wouldn't matter since we square the digits.
So, who's wrong?
EDIT: My bad, I forgot to specify and didn't know it was important. The version of C used in our class and tests has to be C99 or newer. So I guess (by reading the comments) that my version would get the correct answer in any way.
c
I recently had a test in my class. One of the problems was the following:
Given a number n, write a function in C/C++ that returns the sum of the digits of the number squared. (The following is important). The range of n is [ -(10^7), 10^7 ]. Example: If n = 123, your function should return 14 (1^2 + 2^2 + 3^2 = 14).
This is the function that I wrote:
int sum_of_digits_squared(int n)
{
int s = 0, c;
while (n) {
c = n % 10;
s += (c * c);
n /= 10;
}
return s;
}
Looked right to me. So now the test came back and I found that the teacher didn't give me all the points for a reason that I do not understand. According to him, for my function to be complete, I should've have added the following detail:
int sum_of_digits_squared(int n)
{
int s = 0, c;
if (n == 0) { //
return 0; //
} //
// THIS APPARENTLY SHOULD'VE
if (n < 0) { // BEEN IN THE FUNCTION FOR IT
n = n * (-1); // TO BE CORRECT
} //
while (n) {
c = n % 10;
s += (c * c);
n /= 10;
}
return s;
}
The argument for this is that the number n is in the range [-(10^7), 10^7], so it can be a negative number. But I don't see where my own version of the function fails. If I understand correctly, the meaning of while(n)
is while(n != 0)
, not while (n > 0)
, so in my version of the function the number n wouldn't fail to enter the loop. It would work just the same.
Then, I tried both versions of the function on my computer at home and I got exactly the same answers for all the examples that I tried. So, sum_of_digits_squared(-123)
is equal to sum_of_digits_squared(123)
(which again, is equal to 14
) (even without the detail that I apparently should've added). Indeed, if I try to print on the screen the digits of the number (from least to greatest in importance), in the 123
case I get 3 2 1
and in the -123
case I get -3 -2 -1
(which is actually kind of interesting). But in this problem it wouldn't matter since we square the digits.
So, who's wrong?
EDIT: My bad, I forgot to specify and didn't know it was important. The version of C used in our class and tests has to be C99 or newer. So I guess (by reading the comments) that my version would get the correct answer in any way.
c
c
edited 4 hours ago
klutt
11.8k11 gold badges28 silver badges50 bronze badges
11.8k11 gold badges28 silver badges50 bronze badges
asked 9 hours ago
Bogdan VladBogdan Vlad
856 bronze badges
856 bronze badges
Comments are not for extended discussion; this conversation has been moved to chat.
– Brad Larson♦
4 hours ago
add a comment
|
Comments are not for extended discussion; this conversation has been moved to chat.
– Brad Larson♦
4 hours ago
Comments are not for extended discussion; this conversation has been moved to chat.
– Brad Larson♦
4 hours ago
Comments are not for extended discussion; this conversation has been moved to chat.
– Brad Larson♦
4 hours ago
add a comment
|
7 Answers
7
active
oldest
votes
Summarizing a discussion that's been percolating in the comments:
- There is no good reason to test in advance for
n == 0
. Thewhile(n)
test will handle that case perfectly. - It's likely your teacher is still used to earlier times, when the result of
%
with negative operands was differently defined. On some old systems (including, notably, early Unix on a PDP-11, where Dennis Ritchie originally developed C), the result ofa % b
was always in the range[0 .. b-1]
, meaning that -123 % 10 was 7. On such a system, the test in advance forn < 0
would be necessary.
But the second bullet applies only to earlier times. In the current versions of both the C and C++ standards, integer division is defined to truncate towards 0, so it turns out that n % 10
is guaranteed to give you the (possibly negative) last digit of n
even when n
is negative.
So the answer to the question "What is the meaning of while(n)
?" is "Exactly the same as while(n != 0)
", and the answer to "Will this code work properly for negative as well as positive n
?" is "Yes, under any modern, Standards-confirming compiler." The answer to the question "Then why did the instructor mark it down?" is probably that they're not aware of a significant language redefinition that happened to C in 1999 and to C++ in 2010 or so.
I edited my question. Forgot to mention the version. It's C99 or a newer version of C.
– Bogdan Vlad
8 hours ago
add a comment
|
Your code is perfectly fine
You are absolutely correct and your teacher is wrong. There is absolutely no reason at all to add that extra complexity, since it does not affect the result at all. It even introduces a bug. (See below)
First, the check if n
is zero is obviously completely unnecessary and this is very easy to realize. To be honest, I actually question your teachers competence if he have objections about this. But I guess everybody can have brain farts from time to time.
The second one is a bit more understandable, but he is still wrong.
This is what the C11 standard 6.5.5.p6 says:
If the quotient a/b is representable, the expression (a/b)*b + a%b shall equal a; otherwise, the behavior of both a/b and a%b is undefined.
Actually, even C89 says the same and I cannot imagine that you're using an older C-version than that.
And in your case c/n
is defined for all c
and n
. It would only be undefined if n=0
but since n!=0
is the condition for entering the loop, it's fine. According to the standard, this implies that c%n
is defined for all c
and n
.
So there's absolutely nothing wrong with doing modulo with negative numbers. And since you're squaring the result, there is no problem at all.
Your teachers code is flawed
Yes, it actually is. If the input is INT_MIN
and the architecture is using two's complement AND if the bit pattern where the sign bit is 1 and all value bits are 0 is NOT a trap value (using two's complement without trap values is very common) then your teachers code will yield undefined behavior. Your code is - if even so slightly - better than his. And considering introducing a small bug by making the code unnecessary complex and gaining absolutely zero value, I'd say that your code is MUCH better.
But then again, your teacher explicitly says that n
should be in the range [-(10^7), 10^7]. So that could have saved him, if it were not for the case that int
is not necessarily a 32 bit integer. If you compile it for a 16-bit architecture, both of your code snippets are flawed. To avoid this, you can use int32_t
instead. Then you will be safe.
EDIT:
As pointed out by Andrew Henle in comments, int32_t
is not required by the standard, so to be 100% portable, use int_least32_t
or int_fast32_t
instead.
If the input isINT_MIN
and the architecture is using two's complement (which is very common) then your teachers code will yield undefined behavior. Ouch. That will leave a mark. ;-)
– Andrew Henle
5 hours ago
@AndrewHenle Yeah, I got really happy when that train of thought came through my brain. I'm so hoping OP will show that to his teacher. XD
– klutt
5 hours ago
That's some really nice bug spotting, too. I'm just hoping the teacher isn't one of THOSE that punish students for proving them wrong.
– Andrew Henle
5 hours ago
1
@AndrewHenle I agree. That's a theoretical matter. But look one more time. I spotted that the teachers (and OP:s) used a data type that is not guaranteed to be able to represent all the values in the input set. :D
– klutt
4 hours ago
1
Another good catch. I think you could make a good living selling your services doing code reviews. ;-) But pedantically,int32_t
is an optional type -int_least32_t
andint_fast32_t
are required types.
– Andrew Henle
3 hours ago
|
show 5 more comments
I don't completely like either your version or your teacher's. Your teacher's version does the extra tests that you correctly point out are unnecessary. C's mod operator is not a proper mathematical mod: a negative number mod 10 will produce a negative result (proper mathematical modulus is always non-negative). But since you're squaring it anyway, no difference.
But this is far from obvious, so I would add to your code not the checks of your teacher, but a big comment that explains why it works. E.g.:
/* NOTE: This works for negative values, because the modulus gets squared */
add a comment
|
A while loop in almost every programming languge checks if the value given by the express is "truthy". In C and C++ "truthy" is defined as non-zero. For the most part although it can different some circumstances while(n)
is the same thing as saying while(n != 0)
which uses an expression n != 0
that evaluates to either 1 or 0 based on the truth of the expression.
New contributor
What about the negative modulus issue? Are you siding with the OP or the professor?
– John Kugelman
8 hours ago
1
"although it can different some circumstances while(n) is the same thing as saying while(n != 0)
" -- Under what circumstances would they not be equivalent?
– Carey Gregory
8 hours ago
@CareyGregory In C++while(n)
could end up calling a user-defined conversion function such as a member functionexplicit operator bool() { ... }
– Kevin
8 hours ago
@Kevin Oh, with C++ sure, but I was thinking C since this question is tagged C.
– Carey Gregory
3 hours ago
@CareyGregory It was previously also tagged C++
– Kevin
3 hours ago
add a comment
|
NOTE: AS I was writing this answer, you did clarify that you are using C. The majority of my answer is about C++. However, since your title still has C++ and the question is still tagged C++, I have chosen to answer anyway in case this is still useful to other people, especially since most of the answers I've seen till now are mostly unsatisfactory.
In modern C++ (Note: I don't really know where C stands on this), your professor seems to be wrong on both counts.
First is this part right here:
if (n == 0) {
return 0;
}
In C++, this is basically the same thing as:
if (!n) {
return 0;
}
That means your while is equivalent to something like this:
while(n != 0) {
// some implementation
}
That means since you are merely exiting in your if when the while wouldn't execute anyway, there really isn't a reason to put this if here, since what you are doing after the loop and in the if are equivalent anyway. Although I should say that is for some reason these were different, you'd need to have this if.
So really, this if statement isn't particularly useful unless I'm mistaken.
The second part is where things get hairy:
if (n < 0) {
n = n * (-1);
}
The heart of the issue is is what the output of the modulus of a negative number outputs.
In modern C++, this seems to be mostly well defined:
The binary / operator yields the quotient, and the binary % operator yields the remainder from the division of the first expression by the second. If the second operand of / or % is zero the behavior is undefined. For integral operands the / operator yields the algebraic quotient with any fractional part discarded; if the quotient a/b is representable in the type of the result, (a/b)*b + a%b is equal to a.
And later:
If both operands are nonnegative then the remainder is nonnegative; if not, the sign of the remainder is implementation-defined.
As the poster of the quoted answer correctly points out, the important part of this equation right here:
(a/b)*b + a%b
Taking an example of your case, you'd get something like this:
-13/ 10 = -1 (integer truncation)
-1 * 10 = -10
-13 - (-10) = -13 + 10 = -3
The only catch is that last line:
If both operands are nonnegative then the remainder is nonnegative; if not, the sign of the remainder is implementation-defined.
That means that in a case like this, only the sign seems to be implementation-defined. That shouldn't be a problem in your case because, because you are squaring this value anyway.
That said, keep in mind that this doesn't necessarily apply to earlier versions of C++, or C99. If that is what your professor is using, that could be why.
EDIT: Nope, I'm wrong. This seems to be the case for C99 or later as well:
C99 requires that when a/b is representable:
(a/b) * b + a%b shall equal a
And another place:
When integers are divided and the division is inexact, if both operands are positive the result of the / operator is the largest integer less than the algebraic quotient and the result of the % operator is positive. If either operand is negative, whether the result of the / operator is the largest integer less than the algebraic quotient or the smallest integer greater than the algebraic quotient is implementation-defined, as is the sign of the result of the % operator. If the quotient a/b is representable, the expression (a/b)*b + a%b shall equal a.
Does either ANSI C or ISO C specify what -5 % 10 should be?
So, yeah. Even in C99, this doesn't seem to affect you. The equation is the same.
add a comment
|
What Conner Wallace wrote was correct.
Basically inside,
while ( x ) {} -- means:
run loop as long as
- x is not 0 or 0.0
- not null
- not end of string terminator ()
that is "x" can be integer, float, char , char *, void * etc... but you can use single form!!
For experienced users, it is easily understandable, convenient instead of comparing to explicit data of each type accordingly.
Also consider simplicity:
int sum(int n) {
int sum=0;
for(int i=1;i<=n;i++)
sum += i;
return sum;
}
`
To :
//Basically same loop backwards, but less elements
int sum(int n) {
int sum=n;
while ( n-- )
sum += n;
return sum;
}
add a comment
|
while(n) basically means to execute the body of the loop until the value of n>0 because any value other than 0 means true.
Let's say, initially n=123
Step 1- while(123)=>while(true) so enters into the body
c= 123%10 =3 s=0+(3*3)=9 n=123/10=12
Step 2- while(12) =>while(true)
c= 12%10 =2 s = 9+4 = 13 n=12/10=1
Step 3- while(1)=> while(true)
c= 1%10 = 1 s=13+1 =14 n=1/10=0
Step 4- while(0)=> while(False) so loop will terminate
2
What are you getting at? It sounds like you're just restating the OP's case thatwhile (n)
is fine. Except, as they point out, it's equivalent towhile (n != 0)
notwhile (n > 0)
.
– John Kugelman
8 hours ago
add a comment
|
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/4.0/"u003ecc by-sa 4.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f58224638%2fmy-professor-says-my-digit-summing-code-is-flawed-is-he-right%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
7 Answers
7
active
oldest
votes
7 Answers
7
active
oldest
votes
active
oldest
votes
active
oldest
votes
Summarizing a discussion that's been percolating in the comments:
- There is no good reason to test in advance for
n == 0
. Thewhile(n)
test will handle that case perfectly. - It's likely your teacher is still used to earlier times, when the result of
%
with negative operands was differently defined. On some old systems (including, notably, early Unix on a PDP-11, where Dennis Ritchie originally developed C), the result ofa % b
was always in the range[0 .. b-1]
, meaning that -123 % 10 was 7. On such a system, the test in advance forn < 0
would be necessary.
But the second bullet applies only to earlier times. In the current versions of both the C and C++ standards, integer division is defined to truncate towards 0, so it turns out that n % 10
is guaranteed to give you the (possibly negative) last digit of n
even when n
is negative.
So the answer to the question "What is the meaning of while(n)
?" is "Exactly the same as while(n != 0)
", and the answer to "Will this code work properly for negative as well as positive n
?" is "Yes, under any modern, Standards-confirming compiler." The answer to the question "Then why did the instructor mark it down?" is probably that they're not aware of a significant language redefinition that happened to C in 1999 and to C++ in 2010 or so.
I edited my question. Forgot to mention the version. It's C99 or a newer version of C.
– Bogdan Vlad
8 hours ago
add a comment
|
Summarizing a discussion that's been percolating in the comments:
- There is no good reason to test in advance for
n == 0
. Thewhile(n)
test will handle that case perfectly. - It's likely your teacher is still used to earlier times, when the result of
%
with negative operands was differently defined. On some old systems (including, notably, early Unix on a PDP-11, where Dennis Ritchie originally developed C), the result ofa % b
was always in the range[0 .. b-1]
, meaning that -123 % 10 was 7. On such a system, the test in advance forn < 0
would be necessary.
But the second bullet applies only to earlier times. In the current versions of both the C and C++ standards, integer division is defined to truncate towards 0, so it turns out that n % 10
is guaranteed to give you the (possibly negative) last digit of n
even when n
is negative.
So the answer to the question "What is the meaning of while(n)
?" is "Exactly the same as while(n != 0)
", and the answer to "Will this code work properly for negative as well as positive n
?" is "Yes, under any modern, Standards-confirming compiler." The answer to the question "Then why did the instructor mark it down?" is probably that they're not aware of a significant language redefinition that happened to C in 1999 and to C++ in 2010 or so.
I edited my question. Forgot to mention the version. It's C99 or a newer version of C.
– Bogdan Vlad
8 hours ago
add a comment
|
Summarizing a discussion that's been percolating in the comments:
- There is no good reason to test in advance for
n == 0
. Thewhile(n)
test will handle that case perfectly. - It's likely your teacher is still used to earlier times, when the result of
%
with negative operands was differently defined. On some old systems (including, notably, early Unix on a PDP-11, where Dennis Ritchie originally developed C), the result ofa % b
was always in the range[0 .. b-1]
, meaning that -123 % 10 was 7. On such a system, the test in advance forn < 0
would be necessary.
But the second bullet applies only to earlier times. In the current versions of both the C and C++ standards, integer division is defined to truncate towards 0, so it turns out that n % 10
is guaranteed to give you the (possibly negative) last digit of n
even when n
is negative.
So the answer to the question "What is the meaning of while(n)
?" is "Exactly the same as while(n != 0)
", and the answer to "Will this code work properly for negative as well as positive n
?" is "Yes, under any modern, Standards-confirming compiler." The answer to the question "Then why did the instructor mark it down?" is probably that they're not aware of a significant language redefinition that happened to C in 1999 and to C++ in 2010 or so.
Summarizing a discussion that's been percolating in the comments:
- There is no good reason to test in advance for
n == 0
. Thewhile(n)
test will handle that case perfectly. - It's likely your teacher is still used to earlier times, when the result of
%
with negative operands was differently defined. On some old systems (including, notably, early Unix on a PDP-11, where Dennis Ritchie originally developed C), the result ofa % b
was always in the range[0 .. b-1]
, meaning that -123 % 10 was 7. On such a system, the test in advance forn < 0
would be necessary.
But the second bullet applies only to earlier times. In the current versions of both the C and C++ standards, integer division is defined to truncate towards 0, so it turns out that n % 10
is guaranteed to give you the (possibly negative) last digit of n
even when n
is negative.
So the answer to the question "What is the meaning of while(n)
?" is "Exactly the same as while(n != 0)
", and the answer to "Will this code work properly for negative as well as positive n
?" is "Yes, under any modern, Standards-confirming compiler." The answer to the question "Then why did the instructor mark it down?" is probably that they're not aware of a significant language redefinition that happened to C in 1999 and to C++ in 2010 or so.
edited 4 hours ago
answered 8 hours ago
Steve SummitSteve Summit
22.3k2 gold badges29 silver badges53 bronze badges
22.3k2 gold badges29 silver badges53 bronze badges
I edited my question. Forgot to mention the version. It's C99 or a newer version of C.
– Bogdan Vlad
8 hours ago
add a comment
|
I edited my question. Forgot to mention the version. It's C99 or a newer version of C.
– Bogdan Vlad
8 hours ago
I edited my question. Forgot to mention the version. It's C99 or a newer version of C.
– Bogdan Vlad
8 hours ago
I edited my question. Forgot to mention the version. It's C99 or a newer version of C.
– Bogdan Vlad
8 hours ago
add a comment
|
Your code is perfectly fine
You are absolutely correct and your teacher is wrong. There is absolutely no reason at all to add that extra complexity, since it does not affect the result at all. It even introduces a bug. (See below)
First, the check if n
is zero is obviously completely unnecessary and this is very easy to realize. To be honest, I actually question your teachers competence if he have objections about this. But I guess everybody can have brain farts from time to time.
The second one is a bit more understandable, but he is still wrong.
This is what the C11 standard 6.5.5.p6 says:
If the quotient a/b is representable, the expression (a/b)*b + a%b shall equal a; otherwise, the behavior of both a/b and a%b is undefined.
Actually, even C89 says the same and I cannot imagine that you're using an older C-version than that.
And in your case c/n
is defined for all c
and n
. It would only be undefined if n=0
but since n!=0
is the condition for entering the loop, it's fine. According to the standard, this implies that c%n
is defined for all c
and n
.
So there's absolutely nothing wrong with doing modulo with negative numbers. And since you're squaring the result, there is no problem at all.
Your teachers code is flawed
Yes, it actually is. If the input is INT_MIN
and the architecture is using two's complement AND if the bit pattern where the sign bit is 1 and all value bits are 0 is NOT a trap value (using two's complement without trap values is very common) then your teachers code will yield undefined behavior. Your code is - if even so slightly - better than his. And considering introducing a small bug by making the code unnecessary complex and gaining absolutely zero value, I'd say that your code is MUCH better.
But then again, your teacher explicitly says that n
should be in the range [-(10^7), 10^7]. So that could have saved him, if it were not for the case that int
is not necessarily a 32 bit integer. If you compile it for a 16-bit architecture, both of your code snippets are flawed. To avoid this, you can use int32_t
instead. Then you will be safe.
EDIT:
As pointed out by Andrew Henle in comments, int32_t
is not required by the standard, so to be 100% portable, use int_least32_t
or int_fast32_t
instead.
If the input isINT_MIN
and the architecture is using two's complement (which is very common) then your teachers code will yield undefined behavior. Ouch. That will leave a mark. ;-)
– Andrew Henle
5 hours ago
@AndrewHenle Yeah, I got really happy when that train of thought came through my brain. I'm so hoping OP will show that to his teacher. XD
– klutt
5 hours ago
That's some really nice bug spotting, too. I'm just hoping the teacher isn't one of THOSE that punish students for proving them wrong.
– Andrew Henle
5 hours ago
1
@AndrewHenle I agree. That's a theoretical matter. But look one more time. I spotted that the teachers (and OP:s) used a data type that is not guaranteed to be able to represent all the values in the input set. :D
– klutt
4 hours ago
1
Another good catch. I think you could make a good living selling your services doing code reviews. ;-) But pedantically,int32_t
is an optional type -int_least32_t
andint_fast32_t
are required types.
– Andrew Henle
3 hours ago
|
show 5 more comments
Your code is perfectly fine
You are absolutely correct and your teacher is wrong. There is absolutely no reason at all to add that extra complexity, since it does not affect the result at all. It even introduces a bug. (See below)
First, the check if n
is zero is obviously completely unnecessary and this is very easy to realize. To be honest, I actually question your teachers competence if he have objections about this. But I guess everybody can have brain farts from time to time.
The second one is a bit more understandable, but he is still wrong.
This is what the C11 standard 6.5.5.p6 says:
If the quotient a/b is representable, the expression (a/b)*b + a%b shall equal a; otherwise, the behavior of both a/b and a%b is undefined.
Actually, even C89 says the same and I cannot imagine that you're using an older C-version than that.
And in your case c/n
is defined for all c
and n
. It would only be undefined if n=0
but since n!=0
is the condition for entering the loop, it's fine. According to the standard, this implies that c%n
is defined for all c
and n
.
So there's absolutely nothing wrong with doing modulo with negative numbers. And since you're squaring the result, there is no problem at all.
Your teachers code is flawed
Yes, it actually is. If the input is INT_MIN
and the architecture is using two's complement AND if the bit pattern where the sign bit is 1 and all value bits are 0 is NOT a trap value (using two's complement without trap values is very common) then your teachers code will yield undefined behavior. Your code is - if even so slightly - better than his. And considering introducing a small bug by making the code unnecessary complex and gaining absolutely zero value, I'd say that your code is MUCH better.
But then again, your teacher explicitly says that n
should be in the range [-(10^7), 10^7]. So that could have saved him, if it were not for the case that int
is not necessarily a 32 bit integer. If you compile it for a 16-bit architecture, both of your code snippets are flawed. To avoid this, you can use int32_t
instead. Then you will be safe.
EDIT:
As pointed out by Andrew Henle in comments, int32_t
is not required by the standard, so to be 100% portable, use int_least32_t
or int_fast32_t
instead.
If the input isINT_MIN
and the architecture is using two's complement (which is very common) then your teachers code will yield undefined behavior. Ouch. That will leave a mark. ;-)
– Andrew Henle
5 hours ago
@AndrewHenle Yeah, I got really happy when that train of thought came through my brain. I'm so hoping OP will show that to his teacher. XD
– klutt
5 hours ago
That's some really nice bug spotting, too. I'm just hoping the teacher isn't one of THOSE that punish students for proving them wrong.
– Andrew Henle
5 hours ago
1
@AndrewHenle I agree. That's a theoretical matter. But look one more time. I spotted that the teachers (and OP:s) used a data type that is not guaranteed to be able to represent all the values in the input set. :D
– klutt
4 hours ago
1
Another good catch. I think you could make a good living selling your services doing code reviews. ;-) But pedantically,int32_t
is an optional type -int_least32_t
andint_fast32_t
are required types.
– Andrew Henle
3 hours ago
|
show 5 more comments
Your code is perfectly fine
You are absolutely correct and your teacher is wrong. There is absolutely no reason at all to add that extra complexity, since it does not affect the result at all. It even introduces a bug. (See below)
First, the check if n
is zero is obviously completely unnecessary and this is very easy to realize. To be honest, I actually question your teachers competence if he have objections about this. But I guess everybody can have brain farts from time to time.
The second one is a bit more understandable, but he is still wrong.
This is what the C11 standard 6.5.5.p6 says:
If the quotient a/b is representable, the expression (a/b)*b + a%b shall equal a; otherwise, the behavior of both a/b and a%b is undefined.
Actually, even C89 says the same and I cannot imagine that you're using an older C-version than that.
And in your case c/n
is defined for all c
and n
. It would only be undefined if n=0
but since n!=0
is the condition for entering the loop, it's fine. According to the standard, this implies that c%n
is defined for all c
and n
.
So there's absolutely nothing wrong with doing modulo with negative numbers. And since you're squaring the result, there is no problem at all.
Your teachers code is flawed
Yes, it actually is. If the input is INT_MIN
and the architecture is using two's complement AND if the bit pattern where the sign bit is 1 and all value bits are 0 is NOT a trap value (using two's complement without trap values is very common) then your teachers code will yield undefined behavior. Your code is - if even so slightly - better than his. And considering introducing a small bug by making the code unnecessary complex and gaining absolutely zero value, I'd say that your code is MUCH better.
But then again, your teacher explicitly says that n
should be in the range [-(10^7), 10^7]. So that could have saved him, if it were not for the case that int
is not necessarily a 32 bit integer. If you compile it for a 16-bit architecture, both of your code snippets are flawed. To avoid this, you can use int32_t
instead. Then you will be safe.
EDIT:
As pointed out by Andrew Henle in comments, int32_t
is not required by the standard, so to be 100% portable, use int_least32_t
or int_fast32_t
instead.
Your code is perfectly fine
You are absolutely correct and your teacher is wrong. There is absolutely no reason at all to add that extra complexity, since it does not affect the result at all. It even introduces a bug. (See below)
First, the check if n
is zero is obviously completely unnecessary and this is very easy to realize. To be honest, I actually question your teachers competence if he have objections about this. But I guess everybody can have brain farts from time to time.
The second one is a bit more understandable, but he is still wrong.
This is what the C11 standard 6.5.5.p6 says:
If the quotient a/b is representable, the expression (a/b)*b + a%b shall equal a; otherwise, the behavior of both a/b and a%b is undefined.
Actually, even C89 says the same and I cannot imagine that you're using an older C-version than that.
And in your case c/n
is defined for all c
and n
. It would only be undefined if n=0
but since n!=0
is the condition for entering the loop, it's fine. According to the standard, this implies that c%n
is defined for all c
and n
.
So there's absolutely nothing wrong with doing modulo with negative numbers. And since you're squaring the result, there is no problem at all.
Your teachers code is flawed
Yes, it actually is. If the input is INT_MIN
and the architecture is using two's complement AND if the bit pattern where the sign bit is 1 and all value bits are 0 is NOT a trap value (using two's complement without trap values is very common) then your teachers code will yield undefined behavior. Your code is - if even so slightly - better than his. And considering introducing a small bug by making the code unnecessary complex and gaining absolutely zero value, I'd say that your code is MUCH better.
But then again, your teacher explicitly says that n
should be in the range [-(10^7), 10^7]. So that could have saved him, if it were not for the case that int
is not necessarily a 32 bit integer. If you compile it for a 16-bit architecture, both of your code snippets are flawed. To avoid this, you can use int32_t
instead. Then you will be safe.
EDIT:
As pointed out by Andrew Henle in comments, int32_t
is not required by the standard, so to be 100% portable, use int_least32_t
or int_fast32_t
instead.
edited 3 hours ago
answered 8 hours ago
kluttklutt
11.8k11 gold badges28 silver badges50 bronze badges
11.8k11 gold badges28 silver badges50 bronze badges
If the input isINT_MIN
and the architecture is using two's complement (which is very common) then your teachers code will yield undefined behavior. Ouch. That will leave a mark. ;-)
– Andrew Henle
5 hours ago
@AndrewHenle Yeah, I got really happy when that train of thought came through my brain. I'm so hoping OP will show that to his teacher. XD
– klutt
5 hours ago
That's some really nice bug spotting, too. I'm just hoping the teacher isn't one of THOSE that punish students for proving them wrong.
– Andrew Henle
5 hours ago
1
@AndrewHenle I agree. That's a theoretical matter. But look one more time. I spotted that the teachers (and OP:s) used a data type that is not guaranteed to be able to represent all the values in the input set. :D
– klutt
4 hours ago
1
Another good catch. I think you could make a good living selling your services doing code reviews. ;-) But pedantically,int32_t
is an optional type -int_least32_t
andint_fast32_t
are required types.
– Andrew Henle
3 hours ago
|
show 5 more comments
If the input isINT_MIN
and the architecture is using two's complement (which is very common) then your teachers code will yield undefined behavior. Ouch. That will leave a mark. ;-)
– Andrew Henle
5 hours ago
@AndrewHenle Yeah, I got really happy when that train of thought came through my brain. I'm so hoping OP will show that to his teacher. XD
– klutt
5 hours ago
That's some really nice bug spotting, too. I'm just hoping the teacher isn't one of THOSE that punish students for proving them wrong.
– Andrew Henle
5 hours ago
1
@AndrewHenle I agree. That's a theoretical matter. But look one more time. I spotted that the teachers (and OP:s) used a data type that is not guaranteed to be able to represent all the values in the input set. :D
– klutt
4 hours ago
1
Another good catch. I think you could make a good living selling your services doing code reviews. ;-) But pedantically,int32_t
is an optional type -int_least32_t
andint_fast32_t
are required types.
– Andrew Henle
3 hours ago
If the input is
INT_MIN
and the architecture is using two's complement (which is very common) then your teachers code will yield undefined behavior. Ouch. That will leave a mark. ;-)– Andrew Henle
5 hours ago
If the input is
INT_MIN
and the architecture is using two's complement (which is very common) then your teachers code will yield undefined behavior. Ouch. That will leave a mark. ;-)– Andrew Henle
5 hours ago
@AndrewHenle Yeah, I got really happy when that train of thought came through my brain. I'm so hoping OP will show that to his teacher. XD
– klutt
5 hours ago
@AndrewHenle Yeah, I got really happy when that train of thought came through my brain. I'm so hoping OP will show that to his teacher. XD
– klutt
5 hours ago
That's some really nice bug spotting, too. I'm just hoping the teacher isn't one of THOSE that punish students for proving them wrong.
– Andrew Henle
5 hours ago
That's some really nice bug spotting, too. I'm just hoping the teacher isn't one of THOSE that punish students for proving them wrong.
– Andrew Henle
5 hours ago
1
1
@AndrewHenle I agree. That's a theoretical matter. But look one more time. I spotted that the teachers (and OP:s) used a data type that is not guaranteed to be able to represent all the values in the input set. :D
– klutt
4 hours ago
@AndrewHenle I agree. That's a theoretical matter. But look one more time. I spotted that the teachers (and OP:s) used a data type that is not guaranteed to be able to represent all the values in the input set. :D
– klutt
4 hours ago
1
1
Another good catch. I think you could make a good living selling your services doing code reviews. ;-) But pedantically,
int32_t
is an optional type - int_least32_t
and int_fast32_t
are required types.– Andrew Henle
3 hours ago
Another good catch. I think you could make a good living selling your services doing code reviews. ;-) But pedantically,
int32_t
is an optional type - int_least32_t
and int_fast32_t
are required types.– Andrew Henle
3 hours ago
|
show 5 more comments
I don't completely like either your version or your teacher's. Your teacher's version does the extra tests that you correctly point out are unnecessary. C's mod operator is not a proper mathematical mod: a negative number mod 10 will produce a negative result (proper mathematical modulus is always non-negative). But since you're squaring it anyway, no difference.
But this is far from obvious, so I would add to your code not the checks of your teacher, but a big comment that explains why it works. E.g.:
/* NOTE: This works for negative values, because the modulus gets squared */
add a comment
|
I don't completely like either your version or your teacher's. Your teacher's version does the extra tests that you correctly point out are unnecessary. C's mod operator is not a proper mathematical mod: a negative number mod 10 will produce a negative result (proper mathematical modulus is always non-negative). But since you're squaring it anyway, no difference.
But this is far from obvious, so I would add to your code not the checks of your teacher, but a big comment that explains why it works. E.g.:
/* NOTE: This works for negative values, because the modulus gets squared */
add a comment
|
I don't completely like either your version or your teacher's. Your teacher's version does the extra tests that you correctly point out are unnecessary. C's mod operator is not a proper mathematical mod: a negative number mod 10 will produce a negative result (proper mathematical modulus is always non-negative). But since you're squaring it anyway, no difference.
But this is far from obvious, so I would add to your code not the checks of your teacher, but a big comment that explains why it works. E.g.:
/* NOTE: This works for negative values, because the modulus gets squared */
I don't completely like either your version or your teacher's. Your teacher's version does the extra tests that you correctly point out are unnecessary. C's mod operator is not a proper mathematical mod: a negative number mod 10 will produce a negative result (proper mathematical modulus is always non-negative). But since you're squaring it anyway, no difference.
But this is far from obvious, so I would add to your code not the checks of your teacher, but a big comment that explains why it works. E.g.:
/* NOTE: This works for negative values, because the modulus gets squared */
answered 8 hours ago
Lee Daniel CrockerLee Daniel Crocker
10.8k1 gold badge21 silver badges42 bronze badges
10.8k1 gold badge21 silver badges42 bronze badges
add a comment
|
add a comment
|
A while loop in almost every programming languge checks if the value given by the express is "truthy". In C and C++ "truthy" is defined as non-zero. For the most part although it can different some circumstances while(n)
is the same thing as saying while(n != 0)
which uses an expression n != 0
that evaluates to either 1 or 0 based on the truth of the expression.
New contributor
What about the negative modulus issue? Are you siding with the OP or the professor?
– John Kugelman
8 hours ago
1
"although it can different some circumstances while(n) is the same thing as saying while(n != 0)
" -- Under what circumstances would they not be equivalent?
– Carey Gregory
8 hours ago
@CareyGregory In C++while(n)
could end up calling a user-defined conversion function such as a member functionexplicit operator bool() { ... }
– Kevin
8 hours ago
@Kevin Oh, with C++ sure, but I was thinking C since this question is tagged C.
– Carey Gregory
3 hours ago
@CareyGregory It was previously also tagged C++
– Kevin
3 hours ago
add a comment
|
A while loop in almost every programming languge checks if the value given by the express is "truthy". In C and C++ "truthy" is defined as non-zero. For the most part although it can different some circumstances while(n)
is the same thing as saying while(n != 0)
which uses an expression n != 0
that evaluates to either 1 or 0 based on the truth of the expression.
New contributor
What about the negative modulus issue? Are you siding with the OP or the professor?
– John Kugelman
8 hours ago
1
"although it can different some circumstances while(n) is the same thing as saying while(n != 0)
" -- Under what circumstances would they not be equivalent?
– Carey Gregory
8 hours ago
@CareyGregory In C++while(n)
could end up calling a user-defined conversion function such as a member functionexplicit operator bool() { ... }
– Kevin
8 hours ago
@Kevin Oh, with C++ sure, but I was thinking C since this question is tagged C.
– Carey Gregory
3 hours ago
@CareyGregory It was previously also tagged C++
– Kevin
3 hours ago
add a comment
|
A while loop in almost every programming languge checks if the value given by the express is "truthy". In C and C++ "truthy" is defined as non-zero. For the most part although it can different some circumstances while(n)
is the same thing as saying while(n != 0)
which uses an expression n != 0
that evaluates to either 1 or 0 based on the truth of the expression.
New contributor
A while loop in almost every programming languge checks if the value given by the express is "truthy". In C and C++ "truthy" is defined as non-zero. For the most part although it can different some circumstances while(n)
is the same thing as saying while(n != 0)
which uses an expression n != 0
that evaluates to either 1 or 0 based on the truth of the expression.
New contributor
New contributor
answered 8 hours ago
conner wallaceconner wallace
211 bronze badge
211 bronze badge
New contributor
New contributor
What about the negative modulus issue? Are you siding with the OP or the professor?
– John Kugelman
8 hours ago
1
"although it can different some circumstances while(n) is the same thing as saying while(n != 0)
" -- Under what circumstances would they not be equivalent?
– Carey Gregory
8 hours ago
@CareyGregory In C++while(n)
could end up calling a user-defined conversion function such as a member functionexplicit operator bool() { ... }
– Kevin
8 hours ago
@Kevin Oh, with C++ sure, but I was thinking C since this question is tagged C.
– Carey Gregory
3 hours ago
@CareyGregory It was previously also tagged C++
– Kevin
3 hours ago
add a comment
|
What about the negative modulus issue? Are you siding with the OP or the professor?
– John Kugelman
8 hours ago
1
"although it can different some circumstances while(n) is the same thing as saying while(n != 0)
" -- Under what circumstances would they not be equivalent?
– Carey Gregory
8 hours ago
@CareyGregory In C++while(n)
could end up calling a user-defined conversion function such as a member functionexplicit operator bool() { ... }
– Kevin
8 hours ago
@Kevin Oh, with C++ sure, but I was thinking C since this question is tagged C.
– Carey Gregory
3 hours ago
@CareyGregory It was previously also tagged C++
– Kevin
3 hours ago
What about the negative modulus issue? Are you siding with the OP or the professor?
– John Kugelman
8 hours ago
What about the negative modulus issue? Are you siding with the OP or the professor?
– John Kugelman
8 hours ago
1
1
"
although it can different some circumstances while(n) is the same thing as saying while(n != 0)
" -- Under what circumstances would they not be equivalent?– Carey Gregory
8 hours ago
"
although it can different some circumstances while(n) is the same thing as saying while(n != 0)
" -- Under what circumstances would they not be equivalent?– Carey Gregory
8 hours ago
@CareyGregory In C++
while(n)
could end up calling a user-defined conversion function such as a member function explicit operator bool() { ... }
– Kevin
8 hours ago
@CareyGregory In C++
while(n)
could end up calling a user-defined conversion function such as a member function explicit operator bool() { ... }
– Kevin
8 hours ago
@Kevin Oh, with C++ sure, but I was thinking C since this question is tagged C.
– Carey Gregory
3 hours ago
@Kevin Oh, with C++ sure, but I was thinking C since this question is tagged C.
– Carey Gregory
3 hours ago
@CareyGregory It was previously also tagged C++
– Kevin
3 hours ago
@CareyGregory It was previously also tagged C++
– Kevin
3 hours ago
add a comment
|
NOTE: AS I was writing this answer, you did clarify that you are using C. The majority of my answer is about C++. However, since your title still has C++ and the question is still tagged C++, I have chosen to answer anyway in case this is still useful to other people, especially since most of the answers I've seen till now are mostly unsatisfactory.
In modern C++ (Note: I don't really know where C stands on this), your professor seems to be wrong on both counts.
First is this part right here:
if (n == 0) {
return 0;
}
In C++, this is basically the same thing as:
if (!n) {
return 0;
}
That means your while is equivalent to something like this:
while(n != 0) {
// some implementation
}
That means since you are merely exiting in your if when the while wouldn't execute anyway, there really isn't a reason to put this if here, since what you are doing after the loop and in the if are equivalent anyway. Although I should say that is for some reason these were different, you'd need to have this if.
So really, this if statement isn't particularly useful unless I'm mistaken.
The second part is where things get hairy:
if (n < 0) {
n = n * (-1);
}
The heart of the issue is is what the output of the modulus of a negative number outputs.
In modern C++, this seems to be mostly well defined:
The binary / operator yields the quotient, and the binary % operator yields the remainder from the division of the first expression by the second. If the second operand of / or % is zero the behavior is undefined. For integral operands the / operator yields the algebraic quotient with any fractional part discarded; if the quotient a/b is representable in the type of the result, (a/b)*b + a%b is equal to a.
And later:
If both operands are nonnegative then the remainder is nonnegative; if not, the sign of the remainder is implementation-defined.
As the poster of the quoted answer correctly points out, the important part of this equation right here:
(a/b)*b + a%b
Taking an example of your case, you'd get something like this:
-13/ 10 = -1 (integer truncation)
-1 * 10 = -10
-13 - (-10) = -13 + 10 = -3
The only catch is that last line:
If both operands are nonnegative then the remainder is nonnegative; if not, the sign of the remainder is implementation-defined.
That means that in a case like this, only the sign seems to be implementation-defined. That shouldn't be a problem in your case because, because you are squaring this value anyway.
That said, keep in mind that this doesn't necessarily apply to earlier versions of C++, or C99. If that is what your professor is using, that could be why.
EDIT: Nope, I'm wrong. This seems to be the case for C99 or later as well:
C99 requires that when a/b is representable:
(a/b) * b + a%b shall equal a
And another place:
When integers are divided and the division is inexact, if both operands are positive the result of the / operator is the largest integer less than the algebraic quotient and the result of the % operator is positive. If either operand is negative, whether the result of the / operator is the largest integer less than the algebraic quotient or the smallest integer greater than the algebraic quotient is implementation-defined, as is the sign of the result of the % operator. If the quotient a/b is representable, the expression (a/b)*b + a%b shall equal a.
Does either ANSI C or ISO C specify what -5 % 10 should be?
So, yeah. Even in C99, this doesn't seem to affect you. The equation is the same.
add a comment
|
NOTE: AS I was writing this answer, you did clarify that you are using C. The majority of my answer is about C++. However, since your title still has C++ and the question is still tagged C++, I have chosen to answer anyway in case this is still useful to other people, especially since most of the answers I've seen till now are mostly unsatisfactory.
In modern C++ (Note: I don't really know where C stands on this), your professor seems to be wrong on both counts.
First is this part right here:
if (n == 0) {
return 0;
}
In C++, this is basically the same thing as:
if (!n) {
return 0;
}
That means your while is equivalent to something like this:
while(n != 0) {
// some implementation
}
That means since you are merely exiting in your if when the while wouldn't execute anyway, there really isn't a reason to put this if here, since what you are doing after the loop and in the if are equivalent anyway. Although I should say that is for some reason these were different, you'd need to have this if.
So really, this if statement isn't particularly useful unless I'm mistaken.
The second part is where things get hairy:
if (n < 0) {
n = n * (-1);
}
The heart of the issue is is what the output of the modulus of a negative number outputs.
In modern C++, this seems to be mostly well defined:
The binary / operator yields the quotient, and the binary % operator yields the remainder from the division of the first expression by the second. If the second operand of / or % is zero the behavior is undefined. For integral operands the / operator yields the algebraic quotient with any fractional part discarded; if the quotient a/b is representable in the type of the result, (a/b)*b + a%b is equal to a.
And later:
If both operands are nonnegative then the remainder is nonnegative; if not, the sign of the remainder is implementation-defined.
As the poster of the quoted answer correctly points out, the important part of this equation right here:
(a/b)*b + a%b
Taking an example of your case, you'd get something like this:
-13/ 10 = -1 (integer truncation)
-1 * 10 = -10
-13 - (-10) = -13 + 10 = -3
The only catch is that last line:
If both operands are nonnegative then the remainder is nonnegative; if not, the sign of the remainder is implementation-defined.
That means that in a case like this, only the sign seems to be implementation-defined. That shouldn't be a problem in your case because, because you are squaring this value anyway.
That said, keep in mind that this doesn't necessarily apply to earlier versions of C++, or C99. If that is what your professor is using, that could be why.
EDIT: Nope, I'm wrong. This seems to be the case for C99 or later as well:
C99 requires that when a/b is representable:
(a/b) * b + a%b shall equal a
And another place:
When integers are divided and the division is inexact, if both operands are positive the result of the / operator is the largest integer less than the algebraic quotient and the result of the % operator is positive. If either operand is negative, whether the result of the / operator is the largest integer less than the algebraic quotient or the smallest integer greater than the algebraic quotient is implementation-defined, as is the sign of the result of the % operator. If the quotient a/b is representable, the expression (a/b)*b + a%b shall equal a.
Does either ANSI C or ISO C specify what -5 % 10 should be?
So, yeah. Even in C99, this doesn't seem to affect you. The equation is the same.
add a comment
|
NOTE: AS I was writing this answer, you did clarify that you are using C. The majority of my answer is about C++. However, since your title still has C++ and the question is still tagged C++, I have chosen to answer anyway in case this is still useful to other people, especially since most of the answers I've seen till now are mostly unsatisfactory.
In modern C++ (Note: I don't really know where C stands on this), your professor seems to be wrong on both counts.
First is this part right here:
if (n == 0) {
return 0;
}
In C++, this is basically the same thing as:
if (!n) {
return 0;
}
That means your while is equivalent to something like this:
while(n != 0) {
// some implementation
}
That means since you are merely exiting in your if when the while wouldn't execute anyway, there really isn't a reason to put this if here, since what you are doing after the loop and in the if are equivalent anyway. Although I should say that is for some reason these were different, you'd need to have this if.
So really, this if statement isn't particularly useful unless I'm mistaken.
The second part is where things get hairy:
if (n < 0) {
n = n * (-1);
}
The heart of the issue is is what the output of the modulus of a negative number outputs.
In modern C++, this seems to be mostly well defined:
The binary / operator yields the quotient, and the binary % operator yields the remainder from the division of the first expression by the second. If the second operand of / or % is zero the behavior is undefined. For integral operands the / operator yields the algebraic quotient with any fractional part discarded; if the quotient a/b is representable in the type of the result, (a/b)*b + a%b is equal to a.
And later:
If both operands are nonnegative then the remainder is nonnegative; if not, the sign of the remainder is implementation-defined.
As the poster of the quoted answer correctly points out, the important part of this equation right here:
(a/b)*b + a%b
Taking an example of your case, you'd get something like this:
-13/ 10 = -1 (integer truncation)
-1 * 10 = -10
-13 - (-10) = -13 + 10 = -3
The only catch is that last line:
If both operands are nonnegative then the remainder is nonnegative; if not, the sign of the remainder is implementation-defined.
That means that in a case like this, only the sign seems to be implementation-defined. That shouldn't be a problem in your case because, because you are squaring this value anyway.
That said, keep in mind that this doesn't necessarily apply to earlier versions of C++, or C99. If that is what your professor is using, that could be why.
EDIT: Nope, I'm wrong. This seems to be the case for C99 or later as well:
C99 requires that when a/b is representable:
(a/b) * b + a%b shall equal a
And another place:
When integers are divided and the division is inexact, if both operands are positive the result of the / operator is the largest integer less than the algebraic quotient and the result of the % operator is positive. If either operand is negative, whether the result of the / operator is the largest integer less than the algebraic quotient or the smallest integer greater than the algebraic quotient is implementation-defined, as is the sign of the result of the % operator. If the quotient a/b is representable, the expression (a/b)*b + a%b shall equal a.
Does either ANSI C or ISO C specify what -5 % 10 should be?
So, yeah. Even in C99, this doesn't seem to affect you. The equation is the same.
NOTE: AS I was writing this answer, you did clarify that you are using C. The majority of my answer is about C++. However, since your title still has C++ and the question is still tagged C++, I have chosen to answer anyway in case this is still useful to other people, especially since most of the answers I've seen till now are mostly unsatisfactory.
In modern C++ (Note: I don't really know where C stands on this), your professor seems to be wrong on both counts.
First is this part right here:
if (n == 0) {
return 0;
}
In C++, this is basically the same thing as:
if (!n) {
return 0;
}
That means your while is equivalent to something like this:
while(n != 0) {
// some implementation
}
That means since you are merely exiting in your if when the while wouldn't execute anyway, there really isn't a reason to put this if here, since what you are doing after the loop and in the if are equivalent anyway. Although I should say that is for some reason these were different, you'd need to have this if.
So really, this if statement isn't particularly useful unless I'm mistaken.
The second part is where things get hairy:
if (n < 0) {
n = n * (-1);
}
The heart of the issue is is what the output of the modulus of a negative number outputs.
In modern C++, this seems to be mostly well defined:
The binary / operator yields the quotient, and the binary % operator yields the remainder from the division of the first expression by the second. If the second operand of / or % is zero the behavior is undefined. For integral operands the / operator yields the algebraic quotient with any fractional part discarded; if the quotient a/b is representable in the type of the result, (a/b)*b + a%b is equal to a.
And later:
If both operands are nonnegative then the remainder is nonnegative; if not, the sign of the remainder is implementation-defined.
As the poster of the quoted answer correctly points out, the important part of this equation right here:
(a/b)*b + a%b
Taking an example of your case, you'd get something like this:
-13/ 10 = -1 (integer truncation)
-1 * 10 = -10
-13 - (-10) = -13 + 10 = -3
The only catch is that last line:
If both operands are nonnegative then the remainder is nonnegative; if not, the sign of the remainder is implementation-defined.
That means that in a case like this, only the sign seems to be implementation-defined. That shouldn't be a problem in your case because, because you are squaring this value anyway.
That said, keep in mind that this doesn't necessarily apply to earlier versions of C++, or C99. If that is what your professor is using, that could be why.
EDIT: Nope, I'm wrong. This seems to be the case for C99 or later as well:
C99 requires that when a/b is representable:
(a/b) * b + a%b shall equal a
And another place:
When integers are divided and the division is inexact, if both operands are positive the result of the / operator is the largest integer less than the algebraic quotient and the result of the % operator is positive. If either operand is negative, whether the result of the / operator is the largest integer less than the algebraic quotient or the smallest integer greater than the algebraic quotient is implementation-defined, as is the sign of the result of the % operator. If the quotient a/b is representable, the expression (a/b)*b + a%b shall equal a.
Does either ANSI C or ISO C specify what -5 % 10 should be?
So, yeah. Even in C99, this doesn't seem to affect you. The equation is the same.
edited 7 hours ago
answered 7 hours ago
ChipsterChipster
2,5162 gold badges7 silver badges25 bronze badges
2,5162 gold badges7 silver badges25 bronze badges
add a comment
|
add a comment
|
What Conner Wallace wrote was correct.
Basically inside,
while ( x ) {} -- means:
run loop as long as
- x is not 0 or 0.0
- not null
- not end of string terminator ()
that is "x" can be integer, float, char , char *, void * etc... but you can use single form!!
For experienced users, it is easily understandable, convenient instead of comparing to explicit data of each type accordingly.
Also consider simplicity:
int sum(int n) {
int sum=0;
for(int i=1;i<=n;i++)
sum += i;
return sum;
}
`
To :
//Basically same loop backwards, but less elements
int sum(int n) {
int sum=n;
while ( n-- )
sum += n;
return sum;
}
add a comment
|
What Conner Wallace wrote was correct.
Basically inside,
while ( x ) {} -- means:
run loop as long as
- x is not 0 or 0.0
- not null
- not end of string terminator ()
that is "x" can be integer, float, char , char *, void * etc... but you can use single form!!
For experienced users, it is easily understandable, convenient instead of comparing to explicit data of each type accordingly.
Also consider simplicity:
int sum(int n) {
int sum=0;
for(int i=1;i<=n;i++)
sum += i;
return sum;
}
`
To :
//Basically same loop backwards, but less elements
int sum(int n) {
int sum=n;
while ( n-- )
sum += n;
return sum;
}
add a comment
|
What Conner Wallace wrote was correct.
Basically inside,
while ( x ) {} -- means:
run loop as long as
- x is not 0 or 0.0
- not null
- not end of string terminator ()
that is "x" can be integer, float, char , char *, void * etc... but you can use single form!!
For experienced users, it is easily understandable, convenient instead of comparing to explicit data of each type accordingly.
Also consider simplicity:
int sum(int n) {
int sum=0;
for(int i=1;i<=n;i++)
sum += i;
return sum;
}
`
To :
//Basically same loop backwards, but less elements
int sum(int n) {
int sum=n;
while ( n-- )
sum += n;
return sum;
}
What Conner Wallace wrote was correct.
Basically inside,
while ( x ) {} -- means:
run loop as long as
- x is not 0 or 0.0
- not null
- not end of string terminator ()
that is "x" can be integer, float, char , char *, void * etc... but you can use single form!!
For experienced users, it is easily understandable, convenient instead of comparing to explicit data of each type accordingly.
Also consider simplicity:
int sum(int n) {
int sum=0;
for(int i=1;i<=n;i++)
sum += i;
return sum;
}
`
To :
//Basically same loop backwards, but less elements
int sum(int n) {
int sum=n;
while ( n-- )
sum += n;
return sum;
}
answered 8 hours ago
Jay Kumar RJay Kumar R
4132 silver badges7 bronze badges
4132 silver badges7 bronze badges
add a comment
|
add a comment
|
while(n) basically means to execute the body of the loop until the value of n>0 because any value other than 0 means true.
Let's say, initially n=123
Step 1- while(123)=>while(true) so enters into the body
c= 123%10 =3 s=0+(3*3)=9 n=123/10=12
Step 2- while(12) =>while(true)
c= 12%10 =2 s = 9+4 = 13 n=12/10=1
Step 3- while(1)=> while(true)
c= 1%10 = 1 s=13+1 =14 n=1/10=0
Step 4- while(0)=> while(False) so loop will terminate
2
What are you getting at? It sounds like you're just restating the OP's case thatwhile (n)
is fine. Except, as they point out, it's equivalent towhile (n != 0)
notwhile (n > 0)
.
– John Kugelman
8 hours ago
add a comment
|
while(n) basically means to execute the body of the loop until the value of n>0 because any value other than 0 means true.
Let's say, initially n=123
Step 1- while(123)=>while(true) so enters into the body
c= 123%10 =3 s=0+(3*3)=9 n=123/10=12
Step 2- while(12) =>while(true)
c= 12%10 =2 s = 9+4 = 13 n=12/10=1
Step 3- while(1)=> while(true)
c= 1%10 = 1 s=13+1 =14 n=1/10=0
Step 4- while(0)=> while(False) so loop will terminate
2
What are you getting at? It sounds like you're just restating the OP's case thatwhile (n)
is fine. Except, as they point out, it's equivalent towhile (n != 0)
notwhile (n > 0)
.
– John Kugelman
8 hours ago
add a comment
|
while(n) basically means to execute the body of the loop until the value of n>0 because any value other than 0 means true.
Let's say, initially n=123
Step 1- while(123)=>while(true) so enters into the body
c= 123%10 =3 s=0+(3*3)=9 n=123/10=12
Step 2- while(12) =>while(true)
c= 12%10 =2 s = 9+4 = 13 n=12/10=1
Step 3- while(1)=> while(true)
c= 1%10 = 1 s=13+1 =14 n=1/10=0
Step 4- while(0)=> while(False) so loop will terminate
while(n) basically means to execute the body of the loop until the value of n>0 because any value other than 0 means true.
Let's say, initially n=123
Step 1- while(123)=>while(true) so enters into the body
c= 123%10 =3 s=0+(3*3)=9 n=123/10=12
Step 2- while(12) =>while(true)
c= 12%10 =2 s = 9+4 = 13 n=12/10=1
Step 3- while(1)=> while(true)
c= 1%10 = 1 s=13+1 =14 n=1/10=0
Step 4- while(0)=> while(False) so loop will terminate
answered 8 hours ago
PRAKHAR GUPTAPRAKHAR GUPTA
133 bronze badges
133 bronze badges
2
What are you getting at? It sounds like you're just restating the OP's case thatwhile (n)
is fine. Except, as they point out, it's equivalent towhile (n != 0)
notwhile (n > 0)
.
– John Kugelman
8 hours ago
add a comment
|
2
What are you getting at? It sounds like you're just restating the OP's case thatwhile (n)
is fine. Except, as they point out, it's equivalent towhile (n != 0)
notwhile (n > 0)
.
– John Kugelman
8 hours ago
2
2
What are you getting at? It sounds like you're just restating the OP's case that
while (n)
is fine. Except, as they point out, it's equivalent to while (n != 0)
not while (n > 0)
.– John Kugelman
8 hours ago
What are you getting at? It sounds like you're just restating the OP's case that
while (n)
is fine. Except, as they point out, it's equivalent to while (n != 0)
not while (n > 0)
.– John Kugelman
8 hours ago
add a comment
|
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f58224638%2fmy-professor-says-my-digit-summing-code-is-flawed-is-he-right%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Comments are not for extended discussion; this conversation has been moved to chat.
– Brad Larson♦
4 hours ago