| |
| Posted by Timon Gehr in reply to Craig Dillabaugh | PermalinkReply |
|
Timon Gehr
Posted in reply to Craig Dillabaugh
| On 9/23/24 21:52, Craig Dillabaugh wrote:
> Why does the following program:
>
> \<code>
> import std.stdio;
>
> int main(string[] args) {
> uint Q = 7681;
> writeln("Val = ", -1 % Q);
> return 0;
> }
> \</code>
>
> Print
> Val = 5568
>
>
> Was hoping for 1.
>
> I assume it is an integer promotion issue, but I am unsure how to resolve. I tried replacing the Q with to!int(Q) but this gave me -1, which is closer but not right either.
Yes, what this does is to promote `-1` to `uint.max` and the result you are getting is `uint.max % 7686`.
`-1 % 7686` does not work because division rounds towards zero, so the result of modulo may be negative.
In general `a%b` will give you a value between `-abs(b)+1` and `abs(b)-1`, matching the sign of `a` (and ignoring the sign of `b`).
You can use something like `auto r=a%b; if(r<0) r+=abs(b);` or `auto r=(a%b+b)%b;`, depending an your needs (note that those two are not the same for negative `b`, but they match for positive `b`).
This implementation is equivalent to `(a%b+b)%b`, if you want to avoid the second modulo and the compiler is not smart enough:
```d
int floormod(int a,int b){
bool sign=(a<0)^(b<0);
auto r=a%b;
if(sign&&r!=0) r+=b;
return r;
}
```
The interpretation of this is to compute the remainder for a division that rounds to negative infinity.
Sometimes one might also want `a%0 = a`, but this is a special case that has to be checked as the language will give you a division by zero error.
|