3 ms·
I'm not sure I follow. If defined as ``` int16_t mod(int16_t i, int16_t N) { return ((i % N) + N) % N; } ``` There do not seem to be any issues all
by MobiusHorizons 5y ago
I'm not sure I follow.
If defined as
```
int16_t mod(int16_t i, int16_t N) {
return ((i % N) + N) % N;
}
```
There do not seem to be any issues all the way up to INT16_MAX. Even with negative values of N, it produces the same value as python does (although I am not certain I understand what modulus means with a negative N)
- klodolph 5y agoLet i=INT_MAX-1, N=INT_MAX. i%N is just i, and then (i%N)+N overflows. The result is undefined. Even on systems where it is defined, the typical result would be incorrect. It’s a bit weird that you chose int16_t for your example… it’s the kind of thing you might do if you were trying to make some point about different integer types, but you didn’t give a reason for using int16_t, so the point is lost. I can’t read your mind.
- MobiusHorizons 5y agoI chose int16 just to make it easier to write an exhaustive search. That is where my assertion that the code works correctly comes from. The case you suppose makes sense, but for some reason does not produce incorrect results when I run it, for instance: N = INT16_MAX - 2: mod(32762, 32765) = 32762 mod(32763, 32765) = 32763 mod(32764, 32765) = 32764 mod(32765, 32765) = 0 mod(32766, 32765) = 1 mod(32767, 32765) = 2 I wonder if the compiler just used the full register. I'll have to check the disassembly.
- klodolph 5y agoINT_MAX and INT16_MAX are not interchangeable. > I wonder if the compiler just used the full register. I'll have to check the disassembly. No need, you'd figure this out just by knowing what the C spec says and by knowing what the value of INT_MAX is. When you compute the remainder in C, the operands first undergo "integer promotion" and then go through the "usual arithmetic conversions". The result is that you end up with two values of the same type, no narrower than int. So in C, the following function: short broken_modulo(short x, short y) { return ((x % y) + y) % y; } Is equivalent to the following, with the implicit casts made explicit: short broken_modulo(short x, short y) { int ix = (int)x; int iy = (int)y; // All int, no short. int result = ((ix % iy) + iy) % iy; return (short)result; } Note that this conversion happens in ALL C implementations, because it is mandated by the spec, and no implementation-defined stuff is happening here. Do note that it is possible for int to be 16-bit, e.g., // Possible. typedef int int16_t; It's just uncommon to see that in this millennium. I used "int" and "short" above rather than "int16_t" because the exact rank of "int16_t" vs "int" with regard to arithmetic conversions is implementation dependent, but the rank of "short" vs "int" is not implementation dependent.
- MobiusHorizons 5y agoThanks for explaining!