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;
case DIV:
case MOD:
if (o2 == 0) {
node_error(exp, exp->nd_symb == DIV ?
"division by 0" :
"modulo by 0");
node_error(exp, "division by 0");
return;
}
if ((o1 < 0) != (o2 < 0)) {
if (o1 < 0) o1 = -o1;
else o2 = -o2;
if (exp->nd_symb == DIV) o1 = -((o1+o2-1)/o2);
else o1 = ((o1+o2-1)/o2) * o2 - o1;
o1 = -((o1+o2-1)/o2);
}
else {
if (exp->nd_symb == DIV) o1 /= o2;
else o1 %= o2;
else o1 /= o2;
break;
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;

View file

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