summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog18
-rw-r--r--generic/tclExecute.c190
-rw-r--r--tests/expr.test970
3 files changed, 1128 insertions, 50 deletions
diff --git a/ChangeLog b/ChangeLog
index 7bbb62a..00c06a4 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,21 @@
+2005-07-08 Mo DeJong <mdejong@users.sourceforge.net>
+
+ * generic/tclExecute.c (TclExecuteByteCode):
+ Reimplement long and wide type integer division
+ and modulus operations so that the smallest
+ and largest integer values are handled properly.
+ The divide operation is more efficient since
+ it no longer does a modulus or negation and
+ only checks for a remainder when the quotient
+ will be a negative number. The modulus operation
+ is now a bit more complex because of a number of
+ special cases dealing with the smallest and
+ largest integers.
+ * tests/expr.test: Add test cases for division
+ and modulus operations on the smallest and
+ largest integer values for 32 and 64 bit types.
+ [Patch 1230205]
+
2005-07-06 Don Porter <dgp@users.sourceforge.net>
* generic/tclLink.c: Simplified LinkTraceProc [Bug 1208108].
diff --git a/generic/tclExecute.c b/generic/tclExecute.c
index 06456d3..90ee259 100644
--- a/generic/tclExecute.c
+++ b/generic/tclExecute.c
@@ -11,7 +11,7 @@
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
- * RCS: @(#) $Id: tclExecute.c,v 1.193 2005/06/29 03:29:00 mdejong Exp $
+ * RCS: @(#) $Id: tclExecute.c,v 1.194 2005/07/09 00:27:32 mdejong Exp $
*/
#include "tclInt.h"
@@ -3556,7 +3556,7 @@ TclExecuteByteCode(interp, codePtr)
* Only integers are allowed. We compute value op value2.
*/
- long i = 0, i2 = 0, rem, negative;
+ long i = 0, i2 = 0, rem, neg_divisor = 0;
long iResult = 0; /* Init. avoids compiler warning. */
Tcl_WideInt w, w2, wResult = W0;
int doWide = 0;
@@ -3599,8 +3599,9 @@ TclExecuteByteCode(interp, codePtr)
case INST_MOD:
/*
* This code is tricky: C doesn't guarantee much about
- * the quotient or remainder, but Tcl does. The
- * remainder always has the same sign as the divisor and
+ * the quotient or remainder, and results with a negative
+ * divisor are not specified. Tcl guarantees that the
+ * remainder will have the same sign as the divisor and
* a smaller absolute value.
*/
if (value2Ptr->typePtr == &tclWideIntType && w2 == W0) {
@@ -3619,7 +3620,6 @@ TclExecuteByteCode(interp, codePtr)
}
goto divideByZero;
}
- negative = 0;
if (valuePtr->typePtr == &tclWideIntType
|| value2Ptr->typePtr == &tclWideIntType) {
Tcl_WideInt wRemainder;
@@ -3631,32 +3631,102 @@ TclExecuteByteCode(interp, codePtr)
} else if (value2Ptr->typePtr == &tclIntType) {
w2 = Tcl_LongAsWide(i2);
}
- if (w2 < 0) {
- w2 = -w2;
- w = -w;
- negative = 1;
- }
- wRemainder = w % w2;
- if (wRemainder < 0) {
- wRemainder += w2;
+ if ( w == LLONG_MIN && w2 == -1 ) {
+ /* Integer overflow could happen with
+ * (LLONG_MIN % -1) even though it
+ * is not possible in the code below. */
+ wRemainder = 0;
+ } else if ( w == LLONG_MIN && w2 == LLONG_MAX ) {
+ wRemainder = LLONG_MAX - 1;
+ } else if ( w2 == LLONG_MIN ) {
+ /* In C, a modulus operation is not well
+ * defined when the divisor is a negative
+ * number. So w % LLONG_MIN is not well
+ * defined in the code below because
+ * -LLONG_MIN is still a negative number.
+ */
+ if (w == 0 || w == LLONG_MIN) {
+ wRemainder = 0;
+ } else if (w < 0) {
+ wRemainder = w;
+ } else {
+ wRemainder = LLONG_MIN + w;
+ }
+ neg_divisor = 1;
+ } else {
+ if (w2 < 0) {
+ w2 = -w2;
+ w = -w; /* Note: -LLONG_MIN == LLONG_MIN */
+ neg_divisor = 1;
+ }
+ wRemainder = w % w2;
+
+ /*
+ * remainder is (remainder + divisor) when the
+ * remainder is negative. Watch out for the
+ * special case of a LLONG_MIN dividend and
+ * a negative divisor. Don't add the divisor
+ * in that case because the remainder should
+ * not be negative.
+ */
+ if (wRemainder < 0 && !(neg_divisor && (w == LLONG_MIN))) {
+ wRemainder += w2;
+ }
}
- if (negative) {
+ if ((neg_divisor && (wRemainder > 0)) ||
+ (!neg_divisor && (wRemainder < 0))) {
wRemainder = -wRemainder;
}
wResult = wRemainder;
doWide = 1;
break;
}
- if (i2 < 0) {
- i2 = -i2;
- i = -i;
- negative = 1;
- }
- rem = i % i2;
- if (rem < 0) {
- rem += i2;
+
+ if ( i == LONG_MIN && i2 == -1 ) {
+ /* Integer overflow could happen with
+ * (LONG_MIN % -1) even though it
+ * is not possible in the code below. */
+ rem = 0;
+ } else if ( i == LONG_MIN && i2 == LONG_MAX ) {
+ rem = LONG_MAX - 1;
+ } else if ( i2 == LONG_MIN ) {
+ /* In C, a modulus operation is not well
+ * defined when the divisor is a negative
+ * number. So i % LONG_MIN is not well
+ * defined in the code below because
+ * -LONG_MIN is still a negative number.
+ */
+ if (i == 0 || i == LONG_MIN) {
+ rem = 0;
+ } else if (i < 0) {
+ rem = i;
+ } else {
+ rem = LONG_MIN + i;
+ }
+ neg_divisor = 1;
+ } else {
+ if (i2 < 0) {
+ i2 = -i2;
+ i = -i; /* Note: -LONG_MIN == LONG_MIN */
+ neg_divisor = 1;
+ }
+ rem = i % i2;
+
+ /*
+ * remainder is (remainder + divisor) when the
+ * remainder is negative. Watch out for the
+ * special case of a LONG_MIN dividend and
+ * a negative divisor. Don't add the divisor
+ * in that case because the remainder should
+ * not be negative.
+ */
+ if (rem < 0 && !(neg_divisor && (i == LONG_MIN))) {
+ rem += i2;
+ }
}
- if (negative) {
+
+ if ((neg_divisor && (rem > 0)) ||
+ (!neg_divisor && (rem < 0))) {
rem = -rem;
}
iResult = rem;
@@ -3863,12 +3933,12 @@ TclExecuteByteCode(interp, codePtr)
*/
Tcl_ObjType *t1Ptr, *t2Ptr;
- long i = 0, i2 = 0, quot, rem; /* Init. avoids compiler warning. */
+ long i = 0, i2 = 0, quot; /* Init. avoids compiler warning. */
double d1, d2;
long iResult = 0; /* Init. avoids compiler warning. */
double dResult = 0.0; /* Init. avoids compiler warning. */
int doDouble = 0; /* 1 if doing floating arithmetic */
- Tcl_WideInt w, w2, wquot, wrem;
+ Tcl_WideInt w, w2, wquot;
Tcl_WideInt wResult = W0; /* Init. avoids compiler warning. */
int doWide = 0; /* 1 if doing wide arithmetic. */
Tcl_Obj *valuePtr,*value2Ptr;
@@ -4025,23 +4095,34 @@ TclExecuteByteCode(interp, codePtr)
break;
case INST_DIV:
/*
- * This code is tricky: C doesn't guarantee much
- * about the quotient or remainder, but Tcl does.
- * The remainder always has the same sign as the
- * divisor and a smaller absolute value.
+ * When performing integer division, protect
+ * against integer overflow. Round towards zero
+ * when the quotient is positive, otherwise
+ * round towards -Infinity.
*/
if (w2 == W0) {
TRACE((LLD" "LLD" => DIVIDE BY ZERO\n", w, w2));
goto divideByZero;
}
- if (w2 < 0) {
- w2 = -w2;
- w = -w;
- }
- wquot = w / w2;
- wrem = w % w2;
- if (wrem < W0) {
- wquot -= 1;
+ if (w == LLONG_MIN && w2 == -1) {
+ /* Avoid integer overflow on (LLONG_MIN / -1) */
+ wquot = LLONG_MIN;
+ } else {
+ wquot = w / w2;
+ /* Round down to a smaller negative number if
+ * there is a remainder and the quotient is
+ * negative or zero and the signs don't match.
+ * Note that we don't use a modulus to find the
+ * remainder since it is not well defined in C
+ * when the divisor is negative.
+ */
+ if (((wquot < 0) ||
+ ((wquot == 0) &&
+ (((w < 0) && (w2 > 0)) ||
+ ((w > 0) && (w2 < 0))))) &&
+ ((wquot * w2) != w)) {
+ wquot -= 1;
+ }
}
wResult = wquot;
break;
@@ -4072,23 +4153,34 @@ TclExecuteByteCode(interp, codePtr)
break;
case INST_DIV:
/*
- * This code is tricky: C doesn't guarantee much
- * about the quotient or remainder, but Tcl does.
- * The remainder always has the same sign as the
- * divisor and a smaller absolute value.
+ * When performing integer division, protect
+ * against integer overflow. Round towards zero
+ * when the quotient is positive, otherwise
+ * round towards -Infinity.
*/
if (i2 == 0) {
TRACE(("%ld %ld => DIVIDE BY ZERO\n", i, i2));
goto divideByZero;
}
- if (i2 < 0) {
- i2 = -i2;
- i = -i;
- }
- quot = i / i2;
- rem = i % i2;
- if (rem < 0) {
- quot -= 1;
+ if (i == LONG_MIN && i2 == -1) {
+ /* Avoid integer overflow on (LONG_MIN / -1) */
+ quot = LONG_MIN;
+ } else {
+ quot = i / i2;
+ /* Round down to a smaller negative number if
+ * there is a remainder and the quotient is
+ * negative or zero and the signs don't match.
+ * Note that we don't use a modulus to find the
+ * remainder since it is not well defined in C
+ * when the divisor is negative.
+ */
+ if (((quot < 0) ||
+ ((quot == 0) &&
+ (((i < 0) && (i2 > 0)) ||
+ ((i > 0) && (i2 < 0))))) &&
+ ((quot * i2) != i)) {
+ quot -= 1;
+ }
}
iResult = quot;
break;
diff --git a/tests/expr.test b/tests/expr.test
index a7ea152..781eb8e 100644
--- a/tests/expr.test
+++ b/tests/expr.test
@@ -10,7 +10,7 @@
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
-# RCS: @(#) $Id: expr.test,v 1.34 2005/06/29 03:29:02 mdejong Exp $
+# RCS: @(#) $Id: expr.test,v 1.35 2005/07/09 00:27:33 mdejong Exp $
if {[lsearch [namespace children] ::tcltest] == -1} {
package require tcltest 2.1
@@ -5495,10 +5495,978 @@ test expr-33.4 {parse smallest wide value} {wideis64bit} {
} {-9223372036854775808 -9223372036854775808 -9223372036854775808 -9223372036854775808 1 1}
+set min -2147483648
+set max 2147483647
+
+test expr-34.1 {expr edge cases} {longis32bit} {
+ expr {$min / $min}
+} {1}
+
+test expr-34.2 {expr edge cases} {longis32bit} {
+ expr {$min % $min}
+} {0}
+
+test expr-34.3 {expr edge cases} {longis32bit} {
+ expr {$min / ($min + 1)}
+} {1}
+
+test expr-34.4 {expr edge cases} {longis32bit} {
+ expr {$min % ($min + 1)}
+} {-1}
+
+test expr-34.5 {expr edge cases} {longis32bit} {
+ expr {$min / ($min + 2)}
+} {1}
+
+test expr-34.6 {expr edge cases} {longis32bit} {
+ expr {$min % ($min + 2)}
+} {-2}
+
+test expr-34.7 {expr edge cases} {longis32bit} {
+ expr {$min / ($min + 3)}
+} {1}
+
+test expr-34.8 {expr edge cases} {longis32bit} {
+ expr {$min % ($min + 3)}
+} {-3}
+
+test expr-34.9 {expr edge cases} {longis32bit} {
+ expr {$min / -3}
+} {715827882}
+
+test expr-34.10 {expr edge cases} {longis32bit} {
+ expr {$min % -3}
+} {-2}
+
+test expr-34.11 {expr edge cases} {longis32bit} {
+ expr {$min / -2}
+} {1073741824}
+
+test expr-34.12 {expr edge cases} {longis32bit} {
+ expr {$min % -2}
+} {0}
+
+test expr-34.13 {expr edge cases} {longis32bit} {
+ expr {$min / -1}
+} {-2147483648}
+
+test expr-34.14 {expr edge cases} {longis32bit} {
+ expr {$min % -1}
+} {0}
+
+test expr-34.15 {expr edge cases} {longis32bit} {
+ expr {$min * -1}
+} $min
+
+test expr-34.16 {expr edge cases} {longis32bit} {
+ expr {-$min}
+} $min
+
+test expr-34.17 {expr edge cases} {longis32bit} {
+ expr {$min / 1}
+} $min
+
+test expr-34.18 {expr edge cases} {longis32bit} {
+ expr {$min % 1}
+} {0}
+
+test expr-34.19 {expr edge cases} {longis32bit} {
+ expr {$min / 2}
+} {-1073741824}
+
+test expr-34.20 {expr edge cases} {longis32bit} {
+ expr {$min % 2}
+} {0}
+
+test expr-34.21 {expr edge cases} {longis32bit} {
+ expr {$min / 3}
+} {-715827883}
+
+test expr-34.22 {expr edge cases} {longis32bit} {
+ expr {$min % 3}
+} {1}
+
+test expr-34.23 {expr edge cases} {longis32bit} {
+ expr {$min / ($max - 3)}
+} {-2}
+
+test expr-34.24 {expr edge cases} {longis32bit} {
+ expr {$min % ($max - 3)}
+} {2147483640}
+
+test expr-34.25 {expr edge cases} {longis32bit} {
+ expr {$min / ($max - 2)}
+} {-2}
+
+test expr-34.26 {expr edge cases} {longis32bit} {
+ expr {$min % ($max - 2)}
+} {2147483642}
+
+test expr-34.27 {expr edge cases} {longis32bit} {
+ expr {$min / ($max - 1)}
+} {-2}
+
+test expr-34.28 {expr edge cases} {longis32bit} {
+ expr {$min % ($max - 1)}
+} {2147483644}
+
+test expr-34.29 {expr edge cases} {longis32bit} {
+ expr {$min / $max}
+} {-2}
+
+test expr-34.30 {expr edge cases} {longis32bit} {
+ expr {$min % $max}
+} {2147483646}
+
+test expr-34.31 {expr edge cases} {longis32bit} {
+ expr {$max / $max}
+} {1}
+
+test expr-34.32 {expr edge cases} {longis32bit} {
+ expr {$max % $max}
+} {0}
+
+test expr-34.33 {expr edge cases} {longis32bit} {
+ expr {$max / ($max - 1)}
+} {1}
+
+test expr-34.34 {expr edge cases} {longis32bit} {
+ expr {$max % ($max - 1)}
+} {1}
+
+test expr-34.35 {expr edge cases} {longis32bit} {
+ expr {$max / ($max - 2)}
+} {1}
+
+test expr-34.36 {expr edge cases} {longis32bit} {
+ expr {$max % ($max - 2)}
+} {2}
+
+test expr-34.37 {expr edge cases} {longis32bit} {
+ expr {$max / ($max - 3)}
+} {1}
+
+test expr-34.38 {expr edge cases} {longis32bit} {
+ expr {$max % ($max - 3)}
+} {3}
+
+test expr-34.39 {expr edge cases} {longis32bit} {
+ expr {$max / 3}
+} {715827882}
+
+test expr-34.40 {expr edge cases} {longis32bit} {
+ expr {$max % 3}
+} {1}
+
+test expr-34.41 {expr edge cases} {longis32bit} {
+ expr {$max / 2}
+} {1073741823}
+
+test expr-34.42 {expr edge cases} {longis32bit} {
+ expr {$max % 2}
+} {1}
+
+test expr-34.43 {expr edge cases} {longis32bit} {
+ expr {$max / 1}
+} $max
+
+test expr-34.44 {expr edge cases} {longis32bit} {
+ expr {$max % 1}
+} {0}
+
+test expr-34.45 {expr edge cases} {longis32bit} {
+ expr {$max / -1}
+} "-$max"
+
+test expr-34.46 {expr edge cases} {longis32bit} {
+ expr {$max % -1}
+} {0}
+
+test expr-34.47 {expr edge cases} {longis32bit} {
+ expr {$max / -2}
+} {-1073741824}
+
+test expr-34.48 {expr edge cases} {longis32bit} {
+ expr {$max % -2}
+} {-1}
+
+test expr-34.49 {expr edge cases} {longis32bit} {
+ expr {$max / -3}
+} {-715827883}
+
+test expr-34.50 {expr edge cases} {longis32bit} {
+ expr {$max % -3}
+} {-2}
+
+test expr-34.51 {expr edge cases} {longis32bit} {
+ expr {$max / ($min + 3)}
+} {-2}
+
+test expr-34.52 {expr edge cases} {longis32bit} {
+ expr {$max % ($min + 3)}
+} {-2147483643}
+
+test expr-34.53 {expr edge cases} {longis32bit} {
+ expr {$max / ($min + 2)}
+} {-2}
+
+test expr-34.54 {expr edge cases} {longis32bit} {
+ expr {$max % ($min + 2)}
+} {-2147483645}
+
+test expr-34.55 {expr edge cases} {longis32bit} {
+ expr {$max / ($min + 1)}
+} {-1}
+
+test expr-34.56 {expr edge cases} {longis32bit} {
+ expr {$max % ($min + 1)}
+} {0}
+
+test expr-34.57 {expr edge cases} {longis32bit} {
+ expr {$max / $min}
+} {-1}
+
+test expr-34.58 {expr edge cases} {longis32bit} {
+ expr {$max % $min}
+} {-1}
+
+test expr-34.59 {expr edge cases} {longis32bit} {
+ expr {($min + 1) / ($max - 1)}
+} {-2}
+
+test expr-34.60 {expr edge cases} {longis32bit} {
+ expr {($min + 1) % ($max - 1)}
+} {2147483645}
+
+test expr-34.61 {expr edge cases} {longis32bit} {
+ expr {($max - 1) / ($min + 1)}
+} {-1}
+
+test expr-34.62 {expr edge cases} {longis32bit} {
+ expr {($max - 1) % ($min + 1)}
+} {-1}
+
+test expr-34.63 {expr edge cases} {longis32bit} {
+ expr {($max - 1) / $min}
+} {-1}
+
+test expr-34.64 {expr edge cases} {longis32bit} {
+ expr {($max - 1) % $min}
+} {-2}
+
+test expr-34.65 {expr edge cases} {longis32bit} {
+ expr {($max - 2) / $min}
+} {-1}
+
+test expr-34.66 {expr edge cases} {longis32bit} {
+ expr {($max - 2) % $min}
+} {-3}
+
+test expr-34.67 {expr edge cases} {longis32bit} {
+ expr {($max - 3) / $min}
+} {-1}
+
+test expr-34.68 {expr edge cases} {longis32bit} {
+ expr {($max - 3) % $min}
+} {-4}
+
+test expr-34.69 {expr edge cases} {longis32bit} {
+ expr {-3 / $min}
+} {0}
+
+test expr-34.70 {expr edge cases} {longis32bit} {
+ expr {-3 % $min}
+} {-3}
+
+test expr-34.71 {expr edge cases} {longis32bit} {
+ expr {-2 / $min}
+} {0}
+
+test expr-34.72 {expr edge cases} {longis32bit} {
+ expr {-2 % $min}
+} {-2}
+
+test expr-34.73 {expr edge cases} {longis32bit} {
+ expr {-1 / $min}
+} {0}
+
+test expr-34.74 {expr edge cases} {longis32bit} {
+ expr {-1 % $min}
+} {-1}
+
+test expr-34.75 {expr edge cases} {longis32bit} {
+ expr {0 / $min}
+} {0}
+
+test expr-34.76 {expr edge cases} {longis32bit} {
+ expr {0 % $min}
+} {0}
+
+test expr-34.77 {expr edge cases} {longis32bit} {
+ expr {0 / ($min + 1)}
+} {0}
+
+test expr-34.78 {expr edge cases} {longis32bit} {
+ expr {0 % ($min + 1)}
+} {0}
+
+test expr-34.79 {expr edge cases} {longis32bit} {
+ expr {1 / $min}
+} {-1}
+
+test expr-34.80 {expr edge cases} {longis32bit} {
+ expr {1 % $min}
+} {-2147483647}
+
+test expr-34.81 {expr edge cases} {longis32bit} {
+ expr {1 / ($min + 1)}
+} {-1}
+
+test expr-34.82 {expr edge cases} {longis32bit} {
+ expr {1 % ($min + 1)}
+} {-2147483646}
+
+test expr-34.83 {expr edge cases} {longis32bit} {
+ expr {2 / $min}
+} {-1}
+
+test expr-34.84 {expr edge cases} {longis32bit} {
+ expr {2 % $min}
+} {-2147483646}
+
+test expr-34.85 {expr edge cases} {longis32bit} {
+ expr {2 / ($min + 1)}
+} {-1}
+
+test expr-34.86 {expr edge cases} {longis32bit} {
+ expr {2 % ($min + 1)}
+} {-2147483645}
+
+test expr-34.87 {expr edge cases} {longis32bit} {
+ expr {3 / $min}
+} {-1}
+
+test expr-34.88 {expr edge cases} {longis32bit} {
+ expr {3 % $min}
+} {-2147483645}
+
+test expr-34.89 {expr edge cases} {longis32bit} {
+ expr {3 / ($min + 1)}
+} {-1}
+
+test expr-34.90 {expr edge cases} {longis32bit} {
+ expr {3 % ($min + 1)}
+} {-2147483644}
+
+# Euclidean property:
+# quotient * divisor + remainder = dividend
+
+test expr-35.1 {expr edge cases} {longis32bit} {
+ set dividend $max
+ set divisor 2
+ set q [expr {$dividend / $divisor}]
+ set r [expr {$dividend % $divisor}]
+ list $q * $divisor + $r = [expr {($divisor * $q) + $r}]
+} {1073741823 * 2 + 1 = 2147483647}
+
+test expr-35.2 {expr edge cases} {longis32bit} {
+ set dividend [expr {$max - 1}]
+ set divisor 2
+ set q [expr {$dividend / $divisor}]
+ set r [expr {$dividend % $divisor}]
+ list $q * $divisor + $r = [expr {($q * $divisor) + $r}]
+} {1073741823 * 2 + 0 = 2147483646}
+
+test expr-35.3 {expr edge cases} {longis32bit} {
+ set dividend [expr {$max - 2}]
+ set divisor 2
+ set q [expr {$dividend / $divisor}]
+ set r [expr {$dividend % $divisor}]
+ list $q * $divisor + $r = [expr {($q * $divisor) + $r}]
+} {1073741822 * 2 + 1 = 2147483645}
+
+test expr-35.4 {expr edge cases} {longis32bit} {
+ set dividend $max
+ set divisor 3
+ set q [expr {$dividend / $divisor}]
+ set r [expr {$dividend % $divisor}]
+ list $q * $divisor + $r = [expr {($q * $divisor) + $r}]
+} {715827882 * 3 + 1 = 2147483647}
+
+test expr-35.5 {expr edge cases} {longis32bit} {
+ set dividend [expr {$max - 1}]
+ set divisor 3
+ set q [expr {$dividend / $divisor}]
+ set r [expr {$dividend % $divisor}]
+ list $q * $divisor + $r = [expr {($q * $divisor) + $r}]
+} {715827882 * 3 + 0 = 2147483646}
+
+test expr-35.6 {expr edge cases} {longis32bit} {
+ set dividend [expr {$max - 2}]
+ set divisor 3
+ set q [expr {$dividend / $divisor}]
+ set r [expr {$dividend % $divisor}]
+ list $q * $divisor + $r = [expr {($q * $divisor) + $r}]
+} {715827881 * 3 + 2 = 2147483645}
+
+test expr-35.7 {expr edge cases} {longis32bit} {
+ set dividend $min
+ set divisor 2
+ set q [expr {$dividend / $divisor}]
+ set r [expr {$dividend % $divisor}]
+ list $q * $divisor + $r = [expr {($q * $divisor) + $r}]
+} {-1073741824 * 2 + 0 = -2147483648}
+
+test expr-35.8 {expr edge cases} {longis32bit} {
+ set dividend [expr {$min + 1}]
+ set divisor 2
+ set q [expr {$dividend / $divisor}]
+ set r [expr {$dividend % $divisor}]
+ list $q * $divisor + $r = [expr {($q * $divisor) + $r}]
+} {-1073741824 * 2 + 1 = -2147483647}
+
+test expr-35.9 {expr edge cases} {longis32bit} {
+ set dividend [expr {$min + 2}]
+ set divisor 2
+ set q [expr {$dividend / $divisor}]
+ set r [expr {$dividend % $divisor}]
+ list $q * $divisor + $r = [expr {($q * $divisor) + $r}]
+} {-1073741823 * 2 + 0 = -2147483646}
+
+test expr-35.10 {expr edge cases} {longis32bit} {
+ # Two things could happen here. The multiplication
+ # could overflow a 32 bit type, so that when
+ # 1 is added it overflows again back to min.
+ # The multiplication could also use a wide type
+ # to hold ($min - 1) until 1 is added and
+ # the number becomes $min again.
+ set dividend $min
+ set divisor 3
+ set q [expr {$dividend / $divisor}]
+ set r [expr {$dividend % $divisor}]
+ list $q * $divisor + $r = [expr {($q * $divisor) + $r}]
+} {-715827883 * 3 + 1 = -2147483648}
+
+test expr-35.11 {expr edge cases} {longis32bit} {
+ set dividend $min
+ set divisor -3
+ set q [expr {$dividend / $divisor}]
+ set r [expr {$dividend % $divisor}]
+ list $q * $divisor + $r = [expr {($q * $divisor) + $r}]
+} {715827882 * -3 + -2 = -2147483648}
+
+test expr-35.12 {expr edge cases} {longis32bit} {
+ set dividend $min
+ set divisor $min
+ set q [expr {$dividend / $divisor}]
+ set r [expr {$dividend % $divisor}]
+ list $q * $divisor + $r = [expr {($q * $divisor) + $r}]
+} {1 * -2147483648 + 0 = -2147483648}
+
+test expr-35.13 {expr edge cases} {longis32bit} {
+ set dividend $min
+ set divisor [expr {$min + 1}]
+ set q [expr {$dividend / $divisor}]
+ set r [expr {$dividend % $divisor}]
+ list $q * $divisor + $r = [expr {($q * $divisor) + $r}]
+} {1 * -2147483647 + -1 = -2147483648}
+
+test expr-35.14 {expr edge cases} {longis32bit} {
+ set dividend $min
+ set divisor [expr {$min + 2}]
+ set q [expr {$dividend / $divisor}]
+ set r [expr {$dividend % $divisor}]
+ list $q * $divisor + $r = [expr {($q * $divisor) + $r}]
+} {1 * -2147483646 + -2 = -2147483648}
+
+# 64bit wide integer checks
+
+set min -9223372036854775808
+set max 9223372036854775807
+
+test expr-36.1 {expr edge cases} {wideis64bit} {
+ expr {$min / $min}
+} {1}
+
+test expr-36.2 {expr edge cases} {wideis64bit} {
+ expr {$min % $min}
+} {0}
+
+test expr-36.3 {expr edge cases} {wideis64bit} {
+ expr {$min / ($min + 1)}
+} {1}
+
+test expr-36.4 {expr edge cases} {wideis64bit} {
+ expr {$min % ($min + 1)}
+} {-1}
+
+test expr-36.5 {expr edge cases} {wideis64bit} {
+ expr {$min / ($min + 2)}
+} {1}
+
+test expr-36.6 {expr edge cases} {wideis64bit} {
+ expr {$min % ($min + 2)}
+} {-2}
+
+test expr-36.7 {expr edge cases} {wideis64bit} {
+ expr {$min / ($min + 3)}
+} {1}
+
+test expr-36.8 {expr edge cases} {wideis64bit} {
+ expr {$min % ($min + 3)}
+} {-3}
+
+test expr-36.9 {expr edge cases} {wideis64bit} {
+ expr {$min / -3}
+} {3074457345618258602}
+
+test expr-36.10 {expr edge cases} {wideis64bit} {
+ expr {$min % -3}
+} {-2}
+
+test expr-36.11 {expr edge cases} {wideis64bit} {
+ expr {$min / -2}
+} {4611686018427387904}
+
+test expr-36.12 {expr edge cases} {wideis64bit} {
+ expr {$min % -2}
+} {0}
+
+test expr-36.13 {expr edge cases} {wideis64bit} {
+ expr {$min / -1}
+} $min
+
+test expr-36.14 {expr edge cases} {wideis64bit} {
+ expr {$min % -1}
+} {0}
+
+test expr-36.15 {expr edge cases} {wideis64bit} {
+ expr {$min * -1}
+} $min
+
+test expr-36.16 {expr edge cases} {wideis64bit} {
+ expr {-$min}
+} $min
+
+test expr-36.17 {expr edge cases} {wideis64bit} {
+ expr {$min / 1}
+} $min
+
+test expr-36.18 {expr edge cases} {wideis64bit} {
+ expr {$min % 1}
+} {0}
+
+test expr-36.19 {expr edge cases} {wideis64bit} {
+ expr {$min / 2}
+} {-4611686018427387904}
+
+test expr-36.20 {expr edge cases} {wideis64bit} {
+ expr {$min % 2}
+} {0}
+
+test expr-36.21 {expr edge cases} {wideis64bit} {
+ expr {$min / 3}
+} {-3074457345618258603}
+
+test expr-36.22 {expr edge cases} {wideis64bit} {
+ expr {$min % 3}
+} {1}
+
+test expr-36.23 {expr edge cases} {wideis64bit} {
+ expr {$min / ($max - 3)}
+} {-2}
+
+test expr-36.24 {expr edge cases} {wideis64bit} {
+ expr {$min % ($max - 3)}
+} {9223372036854775800}
+
+test expr-36.25 {expr edge cases} {wideis64bit} {
+ expr {$min / ($max - 2)}
+} {-2}
+
+test expr-36.26 {expr edge cases} {wideis64bit} {
+ expr {$min % ($max - 2)}
+} {9223372036854775802}
+
+test expr-36.27 {expr edge cases} {wideis64bit} {
+ expr {$min / ($max - 1)}
+} {-2}
+
+test expr-36.28 {expr edge cases} {wideis64bit} {
+ expr {$min % ($max - 1)}
+} {9223372036854775804}
+
+test expr-36.29 {expr edge cases} {wideis64bit} {
+ expr {$min / $max}
+} {-2}
+
+test expr-36.30 {expr edge cases} {wideis64bit} {
+ expr {$min % $max}
+} {9223372036854775806}
+
+test expr-36.31 {expr edge cases} {wideis64bit} {
+ expr {$max / $max}
+} {1}
+
+test expr-36.32 {expr edge cases} {wideis64bit} {
+ expr {$max % $max}
+} {0}
+
+test expr-36.33 {expr edge cases} {wideis64bit} {
+ expr {$max / ($max - 1)}
+} {1}
+
+test expr-36.34 {expr edge cases} {wideis64bit} {
+ expr {$max % ($max - 1)}
+} {1}
+
+test expr-36.35 {expr edge cases} {wideis64bit} {
+ expr {$max / ($max - 2)}
+} {1}
+
+test expr-36.36 {expr edge cases} {wideis64bit} {
+ expr {$max % ($max - 2)}
+} {2}
+
+test expr-36.37 {expr edge cases} {wideis64bit} {
+ expr {$max / ($max - 3)}
+} {1}
+
+test expr-36.38 {expr edge cases} {wideis64bit} {
+ expr {$max % ($max - 3)}
+} {3}
+
+test expr-36.39 {expr edge cases} {wideis64bit} {
+ expr {$max / 3}
+} {3074457345618258602}
+
+test expr-36.40 {expr edge cases} {wideis64bit} {
+ expr {$max % 3}
+} {1}
+
+test expr-36.41 {expr edge cases} {wideis64bit} {
+ expr {$max / 2}
+} {4611686018427387903}
+
+test expr-36.42 {expr edge cases} {wideis64bit} {
+ expr {$max % 2}
+} {1}
+
+test expr-36.43 {expr edge cases} {wideis64bit} {
+ expr {$max / 1}
+} $max
+
+test expr-36.44 {expr edge cases} {wideis64bit} {
+ expr {$max % 1}
+} {0}
+
+test expr-36.45 {expr edge cases} {wideis64bit} {
+ expr {$max / -1}
+} "-$max"
+
+test expr-36.46 {expr edge cases} {wideis64bit} {
+ expr {$max % -1}
+} {0}
+
+test expr-36.47 {expr edge cases} {wideis64bit} {
+ expr {$max / -2}
+} {-4611686018427387904}
+
+test expr-36.48 {expr edge cases} {wideis64bit} {
+ expr {$max % -2}
+} {-1}
+
+test expr-36.49 {expr edge cases} {wideis64bit} {
+ expr {$max / -3}
+} {-3074457345618258603}
+
+test expr-36.50 {expr edge cases} {wideis64bit} {
+ expr {$max % -3}
+} {-2}
+
+test expr-36.51 {expr edge cases} {wideis64bit} {
+ expr {$max / ($min + 3)}
+} {-2}
+
+test expr-36.52 {expr edge cases} {wideis64bit} {
+ expr {$max % ($min + 3)}
+} {-9223372036854775803}
+
+test expr-36.53 {expr edge cases} {wideis64bit} {
+ expr {$max / ($min + 2)}
+} {-2}
+
+test expr-36.54 {expr edge cases} {wideis64bit} {
+ expr {$max % ($min + 2)}
+} {-9223372036854775805}
+
+test expr-36.55 {expr edge cases} {wideis64bit} {
+ expr {$max / ($min + 1)}
+} {-1}
+
+test expr-36.56 {expr edge cases} {wideis64bit} {
+ expr {$max % ($min + 1)}
+} {0}
+
+test expr-36.57 {expr edge cases} {wideis64bit} {
+ expr {$max / $min}
+} {-1}
+
+test expr-36.58 {expr edge cases} {wideis64bit} {
+ expr {$max % $min}
+} {-1}
+
+test expr-36.59 {expr edge cases} {wideis64bit} {
+ expr {($min + 1) / ($max - 1)}
+} {-2}
+
+test expr-36.60 {expr edge cases} {wideis64bit} {
+ expr {($min + 1) % ($max - 1)}
+} {9223372036854775805}
+
+test expr-36.61 {expr edge cases} {wideis64bit} {
+ expr {($max - 1) / ($min + 1)}
+} {-1}
+
+test expr-36.62 {expr edge cases} {wideis64bit} {
+ expr {($max - 1) % ($min + 1)}
+} {-1}
+
+test expr-36.63 {expr edge cases} {wideis64bit} {
+ expr {($max - 1) / $min}
+} {-1}
+
+test expr-36.64 {expr edge cases} {wideis64bit} {
+ expr {($max - 1) % $min}
+} {-2}
+
+test expr-36.65 {expr edge cases} {wideis64bit} {
+ expr {($max - 2) / $min}
+} {-1}
+
+test expr-36.66 {expr edge cases} {wideis64bit} {
+ expr {($max - 2) % $min}
+} {-3}
+
+test expr-36.67 {expr edge cases} {wideis64bit} {
+ expr {($max - 3) / $min}
+} {-1}
+
+test expr-36.68 {expr edge cases} {wideis64bit} {
+ expr {($max - 3) % $min}
+} {-4}
+
+test expr-36.69 {expr edge cases} {wideis64bit} {
+ expr {-3 / $min}
+} {0}
+
+test expr-36.70 {expr edge cases} {wideis64bit} {
+ expr {-3 % $min}
+} {-3}
+
+test expr-36.71 {expr edge cases} {wideis64bit} {
+ expr {-2 / $min}
+} {0}
+
+test expr-36.72 {expr edge cases} {wideis64bit} {
+ expr {-2 % $min}
+} {-2}
+
+test expr-36.73 {expr edge cases} {wideis64bit} {
+ expr {-1 / $min}
+} {0}
+
+test expr-36.74 {expr edge cases} {wideis64bit} {
+ expr {-1 % $min}
+} {-1}
+
+test expr-36.75 {expr edge cases} {wideis64bit} {
+ expr {0 / $min}
+} {0}
+
+test expr-36.76 {expr edge cases} {wideis64bit} {
+ expr {0 % $min}
+} {0}
+
+test expr-36.77 {expr edge cases} {wideis64bit} {
+ expr {0 / ($min + 1)}
+} {0}
+
+test expr-36.78 {expr edge cases} {wideis64bit} {
+ expr {0 % ($min + 1)}
+} {0}
+
+test expr-36.79 {expr edge cases} {wideis64bit} {
+ expr {1 / $min}
+} {-1}
+
+test expr-36.80 {expr edge cases} {wideis64bit} {
+ expr {1 % $min}
+} {-9223372036854775807}
+
+test expr-36.81 {expr edge cases} {wideis64bit} {
+ expr {1 / ($min + 1)}
+} {-1}
+
+test expr-36.82 {expr edge cases} {wideis64bit} {
+ expr {1 % ($min + 1)}
+} {-9223372036854775806}
+
+test expr-36.83 {expr edge cases} {wideis64bit} {
+ expr {2 / $min}
+} {-1}
+
+test expr-36.84 {expr edge cases} {wideis64bit} {
+ expr {2 % $min}
+} {-9223372036854775806}
+
+test expr-36.85 {expr edge cases} {wideis64bit} {
+ expr {2 / ($min + 1)}
+} {-1}
+
+test expr-36.86 {expr edge cases} {wideis64bit} {
+ expr {2 % ($min + 1)}
+} {-9223372036854775805}
+
+test expr-36.87 {expr edge cases} {wideis64bit} {
+ expr {3 / $min}
+} {-1}
+
+test expr-36.88 {expr edge cases} {wideis64bit} {
+ expr {3 % $min}
+} {-9223372036854775805}
+
+test expr-36.89 {expr edge cases} {wideis64bit} {
+ expr {3 / ($min + 1)}
+} {-1}
+
+test expr-36.90 {expr edge cases} {wideis64bit} {
+ expr {3 % ($min + 1)}
+} {-9223372036854775804}
+
+
+test expr-37.1 {expr edge cases} {wideis64bit} {
+ set dividend $max
+ set divisor 2
+ set q [expr {$dividend / $divisor}]
+ set r [expr {$dividend % $divisor}]
+ list $q * $divisor + $r = [expr {($divisor * $q) + $r}]
+} {4611686018427387903 * 2 + 1 = 9223372036854775807}
+
+test expr-37.2 {expr edge cases} {wideis64bit} {
+ set dividend [expr {$max - 1}]
+ set divisor 2
+ set q [expr {$dividend / $divisor}]
+ set r [expr {$dividend % $divisor}]
+ list $q * $divisor + $r = [expr {($q * $divisor) + $r}]
+} {4611686018427387903 * 2 + 0 = 9223372036854775806}
+
+test expr-37.3 {expr edge cases} {wideis64bit} {
+ set dividend [expr {$max - 2}]
+ set divisor 2
+ set q [expr {$dividend / $divisor}]
+ set r [expr {$dividend % $divisor}]
+ list $q * $divisor + $r = [expr {($q * $divisor) + $r}]
+} {4611686018427387902 * 2 + 1 = 9223372036854775805}
+
+test expr-37.4 {expr edge cases} {wideis64bit} {
+ set dividend $max
+ set divisor 3
+ set q [expr {$dividend / $divisor}]
+ set r [expr {$dividend % $divisor}]
+ list $q * $divisor + $r = [expr {($q * $divisor) + $r}]
+} {3074457345618258602 * 3 + 1 = 9223372036854775807}
+
+test expr-37.5 {expr edge cases} {wideis64bit} {
+ set dividend [expr {$max - 1}]
+ set divisor 3
+ set q [expr {$dividend / $divisor}]
+ set r [expr {$dividend % $divisor}]
+ list $q * $divisor + $r = [expr {($q * $divisor) + $r}]
+} {3074457345618258602 * 3 + 0 = 9223372036854775806}
+
+test expr-37.6 {expr edge cases} {wideis64bit} {
+ set dividend [expr {$max - 2}]
+ set divisor 3
+ set q [expr {$dividend / $divisor}]
+ set r [expr {$dividend % $divisor}]
+ list $q * $divisor + $r = [expr {($q * $divisor) + $r}]
+} {3074457345618258601 * 3 + 2 = 9223372036854775805}
+
+test expr-37.7 {expr edge cases} {wideis64bit} {
+ set dividend $min
+ set divisor 2
+ set q [expr {$dividend / $divisor}]
+ set r [expr {$dividend % $divisor}]
+ list $q * $divisor + $r = [expr {($q * $divisor) + $r}]
+} {-4611686018427387904 * 2 + 0 = -9223372036854775808}
+
+test expr-37.8 {expr edge cases} {wideis64bit} {
+ set dividend [expr {$min + 1}]
+ set divisor 2
+ set q [expr {$dividend / $divisor}]
+ set r [expr {$dividend % $divisor}]
+ list $q * $divisor + $r = [expr {($q * $divisor) + $r}]
+} {-4611686018427387904 * 2 + 1 = -9223372036854775807}
+
+test expr-37.9 {expr edge cases} {wideis64bit} {
+ set dividend [expr {$min + 2}]
+ set divisor 2
+ set q [expr {$dividend / $divisor}]
+ set r [expr {$dividend % $divisor}]
+ list $q * $divisor + $r = [expr {($q * $divisor) + $r}]
+} {-4611686018427387903 * 2 + 0 = -9223372036854775806}
+
+test expr-37.10 {expr edge cases} {wideis64bit} {
+ # Multiplication overflows 64 bit type here,
+ # so when the 1 is added it overflows
+ # again and we end up back at min.
+ set dividend $min
+ set divisor 3
+ set q [expr {$dividend / $divisor}]
+ set r [expr {$dividend % $divisor}]
+ list $q * $divisor + $r = [expr {($q * $divisor) + $r}]
+} {-3074457345618258603 * 3 + 1 = -9223372036854775808}
+
+test expr-37.11 {expr edge cases} {wideis64bit} {
+ set dividend $min
+ set divisor -3
+ set q [expr {$dividend / $divisor}]
+ set r [expr {$dividend % $divisor}]
+ list $q * $divisor + $r = [expr {($q * $divisor) + $r}]
+} {3074457345618258602 * -3 + -2 = -9223372036854775808}
+
+test expr-37.12 {expr edge cases} {wideis64bit} {
+ set dividend $min
+ set divisor $min
+ set q [expr {$dividend / $divisor}]
+ set r [expr {$dividend % $divisor}]
+ list $q * $divisor + $r = [expr {($q * $divisor) + $r}]
+} {1 * -9223372036854775808 + 0 = -9223372036854775808}
+
+test expr-37.13 {expr edge cases} {wideis64bit} {
+ set dividend $min
+ set divisor [expr {$min + 1}]
+ set q [expr {$dividend / $divisor}]
+ set r [expr {$dividend % $divisor}]
+ list $q * $divisor + $r = [expr {($q * $divisor) + $r}]
+} {1 * -9223372036854775807 + -1 = -9223372036854775808}
+
+test expr-37.14 {expr edge cases} {wideis64bit} {
+ set dividend $min
+ set divisor [expr {$min + 2}]
+ set q [expr {$dividend / $divisor}]
+ set r [expr {$dividend % $divisor}]
+ list $q * $divisor + $r = [expr {($q * $divisor) + $r}]
+} {1 * -9223372036854775806 + -2 = -9223372036854775808}
+
+
# cleanup
if {[info exists a]} {
unset a
}
+catch {unset min}
+catch {unset max}
::tcltest::cleanupTests
return