Get correct sign of a MOD b when (a > 0) and (b < 0).

Reported by me in https://github.com/davidgiven/ack/issues/60

This doesn't change DIV.  Right now a DIV b does floor division and
a MOD b has the sign of b.  This is the same as Lua, Python, Ruby,
Tcl; but is different from other Modula-2 implementations.
This commit is contained in:
George Koehler 2017-10-28 19:55:06 -04:00
parent 649410bb27
commit 038fb6fb55
2 changed files with 30 additions and 21 deletions

View file

@ -159,22 +159,29 @@ cstibin(expp)
break; break;
case DIV: case DIV:
case MOD:
if (o2 == 0) { if (o2 == 0) {
node_error(exp, exp->nd_symb == DIV ? node_error(exp, "division by 0");
"division by 0" :
"modulo by 0");
return; return;
} }
if ((o1 < 0) != (o2 < 0)) { if ((o1 < 0) != (o2 < 0)) {
if (o1 < 0) o1 = -o1; if (o1 < 0) o1 = -o1;
else o2 = -o2; else o2 = -o2;
if (exp->nd_symb == DIV) o1 = -((o1+o2-1)/o2); o1 = -((o1+o2-1)/o2);
else o1 = ((o1+o2-1)/o2) * o2 - o1;
} }
else { else o1 /= o2;
if (exp->nd_symb == DIV) o1 /= o2; break;
else o1 %= o2;
case MOD:
if (o2 == 0) {
node_error(exp, "modulo by 0");
return;
}
{
arith m = o1 % o2;
if (m != 0 && (o1 < 0) != (o2 < 0))
o1 = m + o2;
else
o1 = m;
} }
break; break;

View file

@ -43,26 +43,28 @@ int
rmi(j,i) rmi(j,i)
int j,i; int j,i;
{ {
int m;
if (j == 0) TRP(EIDIVZ); if (j == 0) TRP(EIDIVZ);
if (i == 0) return 0; if (i == 0) return 0;
if ((i < 0) != (j < 0)) {
if (i < 0) i = -i; m = i % j;
else j = -j; if (m != 0 && (i < 0) != (j < 0))
return j*((i+j-1)/j)-i; m += j;
} return m;
else return i%j;
} }
long long
rmil(j,i) rmil(j,i)
long j,i; long j,i;
{ {
long m;
if (j == 0) TRP(EIDIVZ); if (j == 0) TRP(EIDIVZ);
if (i == 0) return 0L; if (i == 0) return 0L;
if ((i < 0) != (j < 0)) {
if (i < 0) i = -i; m = i % j;
else j = -j; if (m != 0 && (i < 0) != (j < 0))
return j*((i+j-1)/j)-i; m += j;
} return m;
else return i%j;
} }