, 11 min read
What the heck is the value of “-n % n” in programming languages?
18 thoughts on “What the heck is the value of “-n % n” in programming languages?”
, 11 min read
18 thoughts on “What the heck is the value of “-n % n” in programming languages?”
Sorry, but I miss the point of such code, then. If the value of -range % range is always 0, what’s the intent?
It is only zero when you have signed types. It is non trivial when you have unsigned types. You should be able to test it out for yourself.
Petite coquille : “just by examining just”
I reckon a whole series of posts could be inspired by that statement.
That resonated with me, it’s the opposite of “software should be readable like proze” which always sounded odd to me.
Tiny amendment: % is the percent sign, not the ampersand (that’s &).
This is a neat trick! But I found something surprising with
unsigned short
: https://gcc.godbolt.org/z/4xWo1G. It looks like-n
is type-promoted (probably to a signed integer? I haven’t checked the standard) so unless you re-cast it (I’m not sure that cast isn’t UB…) you don’t get the expected result.You do an excellent job of explaining what this seemingly odd construction does, but it might be good to mention in the intro why “-n %n” is a common construction in the first place. Stealing from an HN comment making the same suggestions, “It computes (2^b) % n, assuming n is an unsigned b-bit integer. You can’t do this directly, since 2^b itself doesn’t fit into a b-bit integer.”
Yes, this fault in my blog post was pointed out to me on twitter.
A nit: I believe you meant to write ‘percent’ (%) and not ‘ampersand’ (&). cheers.
I dont understand. I tried it in C# and printed out the result of -8%8 and i got 0 so i dont get what is supposed to be happening
In C#, try (4294967295 - n + 1) % n if n is of type uint.
I noticed unexpected results with unsigned short and unsigned char. It’s worth noting that -n will be converted to a signed int if n is a narrower type.
I’m finding out the hard way that gcc 10 seems to optimize this expression to 0 for unsigned values. I’m having to cast to signed to get the unary minus to take effect, and then cast back to unsigned for the modulo to work the way it should. YMMV.
See my reference to the standard C++ library in my blog post. It is used in GCC 10.
This sentence is a bit confusing to read. If unsigned integers cannot overflow (i.e. unsigned overflow doesn’t exist), then there can be no (unsigned) additive inverse.
By the way, I expected this post to discuss something else entirely. In Python, you have the following:
>>> (-3) % 5
2
>>> (-3) % (-5)
-3
>>> 3 % (-5)
-2
But in C (and presumably other C-like languages), the results are -3, -3, 3 respectively.
I agree. I rephrased it as “wrap around”.
The division and remainder (modulo) between signed integers are defined differently depending on the programming. E.g., we all agree that 4/3 is 1. But what is -4/3? It could be -2 or -1. You can round toward zero or toward minus infinity.