Get correct sign of a MOD b when (a > 0) and (b < 0).
authorGeorge Koehler <xkernigh@netscape.net>
Sat, 28 Oct 2017 23:55:06 +0000 (19:55 -0400)
committerGeorge Koehler <xkernigh@netscape.net>
Sat, 28 Oct 2017 23:55:06 +0000 (19:55 -0400)
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.

lang/m2/comp/cstoper.c
lang/m2/libm2/dvi.c

index 7629098..9d7fea0 100644 (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;
 
index 900e785..4f85cf6 100644 (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;
 }