5 ms·
That makes sense (sort of). Better to use unsigned if you are trying to do modular arithmetic. Signed integers have some weirdness attached. The number that's
by mtdewcmu 12y ago
That makes sense (sort of). Better to use unsigned if you are trying to do modular arithmetic.
Signed integers have some weirdness attached. The number that's one followed by all zeroes in binary (INT_MIN in limits.h) is defined as negative, because the sign bit is set. But, the rules for 2's complement arithmetic predict that -INT_MIN == INT_MIN. So it's not a normal number.
- hornetblack 12y agoIn some programs I like to have something like this to catch potential bugs: int abs_s(int x) { assert(x != INT_MIN); return (x >= 0) ? x : -x; }
- ygra 12y agoThis assumes two's complement, though. With one's complement even `INT_MIN` would be fine to negate ;) (On that note: Are there even machines left to write code for that don't use two's complement? Or 8 bits per byte?)
- nitrogen 12y agoIt has been mentioned on HN before that there are DSPs that use the same size for byte, short, and int, and that size is not 8 bits.
- mikeash 12y agoSimilarly amusing, INT_MIN / -1 will throw a "division by zero" on Intel CPUs, even though there isn't a zero anywhere in sight. INT_MIN * -1 is fine, of course (according to the CPU, even if not the language spec).
- oofabz 12y agoINT_MIN / -1 works fine for me on amd64 with gcc 4.9. It produces INT_MIN, just as you would expect. INT_MIN * -1 is also INT_MIN. #include <limits.h> #include <stdio.h> void main(void) { int x = INT_MIN; printf("INT_MIN = %d\n", x); printf("INT_MIN * -1 = %d\n", x * -1); printf("INT_MIN / -1 = %d\n", x / -1); }
- lauraura 12y agoYour arithmetic is being optimized out by the compiler; https://ideone.com/KmTSUB https://ideone.com/KmTSUB crashes for example.
- e12e 12y agoLooks like you're right (re my sibling comment above): $ gcc -std=c99 -S intmin.c -o intmin.s $ clang -std=c99 -S intmin.c -o intmin.sc $ grep -i div intmin.s* intmin.sc: idivl %esi (No idivl in the gcc version)
- e12e 12y ago$ clang --version Debian clang version 3.5-1~exp1 (trunk) (based on LLVM 3.5) Target: x86_64-pc-linux-gnu Thread model: posix $ clang -o intmin_c -std=c99 intmin.c $ ./intmin_c INT_MIN = -2147483648 INT_MIN * -1 = -2147483648 Floating point exception $ gcc --version gcc-4.7.real (Debian 4.7.2-5) 4.7.2 (...) $ gcc -o intmin -std=c99 intmin.c $ ./intmin INT_MIN = -2147483648 INT_MIN * -1 = -2147483648 INT_MIN / -1 = -2147483648 $ tcc -v tcc version 0.9.25 $ tcc -run intmin.c INT_MIN = -2147483648 INT_MIN * -1 = -2147483648 Floating point exception $ cat intmin.c #include <limits.h> #include <stdio.h> int main(void) { // Change from void to int for c99 int x = INT_MIN; printf(" INT_MIN = %d\n", x); printf("INT_MIN * -1 = %d\n", x * -1); printf("INT_MIN / -1 = %d\n", x / -1); return 0; // return 0 - c99 } So, is this a gcc thing?
- mikeash 12y agoThis is a good reminder that "undefined behavior" includes "doing what I want it to do". It's also a good example of how undefined behavior allows for optimizations. The compiler is able to evaluate your expression at compile time rather than emitting a division instruction, even though this changes how the program behaves. C sure is fun.
- pdw 12y agoBecause it's undefined, the compiler is allowed to do anything: including giving the expected result.