Updated 2016-04-01 16:52:52 by juef

/ is the division operator in expr, requiring a dividend on its left and a divisor on its right. It's also available as ::tcl::mathop::/, which, when provided with only one argument, uses that argument as the divisor, and 1.0 as the dividend.

Description  edit

When applied to integers, the division and remainder operators can be considered to partition the number line into a sequence of equal-sized adjacent non-overlapping pieces where each piece is the size of the divisor; the division result identifies which piece the dividend lies within, and the remainder result identifies where within that piece the dividend lies. Therefore, -57 / 10 evaluates to -6, and the -57 % 10 evaluates to 3.

AMG: In Tcl, integer division always rounds down, even in the face of negative numbers.
expr { 20 /  6}  ;#  3
expr { 20 / -6}  ;# -4
expr {-20 /  6}  ;# -4
expr {-20 / -6}  ;#  3

C does not provide this guarantee. On all platforms, GCC defines negative integer division to round toward zero, which is not mathematically useful. Portably, the div() [1] family of functions can be used to get this same wonky but predictable behavior. To get nice round-down behavior, fix up the result of div():
#include <stdlib.h>
int mydiv(int num, int den)
{
    div_t result = div(num, den);
    if (result.rem < 0) {
        return result.quot - 1;
    } else {
        return result.quot;
    }
}

Or avoid div() and take matters into your own hands:
int mydiv(int num, int den)
{
    switch (((num < 0) << 1) | (den < 0)) {
    case 0: return num / den;                  /* +/+ */
    case 1: return -((num - den - 1) / -den);  /* +/- */
    case 2: return -((-num + den - 1) / den);  /* -/+ */
    case 3: return -num / -den;                /* -/- */
    }
}

Here's how Tcl does it (see tclExecute.c [2]):
quot = num / den;
if (((quot < 0) || ((quot == 0) &&
    ((num < 0 && den > 0) || (num > 0 && den < 0)))) &&
    ((quot * den) != num)) {
    quot -= 1;
}
return quot;

I don't quite understand this. It appears to assume that C division rounds toward zero, then decrements negative results to instead round down. But what if C division rounds down? Maybe Tcl simply doesn't support any compilers that allow this behavior. I hear a rumor that recent compilers all round toward zero, for instance GCC.

RS 2013-11-08 In the following case, Tcl's behavior first appears strange:
 % expr -1/2
 -1

However, there is good reason behind it. Integer division forms a "team" together with modulo (%, "remainder"). Let
 (a)    A / B = C
 (b)    A % B = D

then the inverse operation, so to speak, should be
 (c)    C * B + D == A

In the example,
   -1 * 2 + 1 == -1

The "rounding toward zero" way would have to allow negative remainders. Programming languages disagree here, obviously: "This means that, if the remainder is nonzero, there are two possible choices for the remainder, one negative and the other positive, and there are also two possible choices for the quotient. Usually, in number theory, the positive remainder is always chosen, but programming languages choose depending on the language and the signs of a and n.[4] Pascal and Algol68 give a positive remainder (or 0) even for negative divisors, and some programming languages, such as C89, don't even define a result if either of n or a is negative." [3] Some languages give to the remainder the sign of the dividend, some of the divisor, some always non-negative, some undefined...

Here are C's answers (dividend sign):
 $ cat mod.c
 #include <stdio.h>
 int main() {
   printf("-1/2 = %d  -1%%2 = %d\n", -1/2, -1%2);
   printf("1/-2 = %d  1%%-2 = %d\n", 1/-2, 1%-2);
   return 0;
 }
 $ ./a.exe
 -1/2 = 0  -1%2 = -1
 1/-2 = 0  1%-2 = 1
 $ gcc --version
 2.95.3-5

In contrast, Tcl applies divisor sign:
 -1/2 = -1   -1%2 = 1
 1/-2 = -1   1%-2 = -1

and there rule (c) above does no longer hold:
 -1 * -2 + -1 = 1   not -1 !!

Is this a bug?