summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--generic/tclExecute.c469
-rw-r--r--generic/tclStubInit.c8
-rw-r--r--generic/tclTomMath.decls15
-rw-r--r--generic/tclTomMathDecls.h39
-rw-r--r--tests/mathop.test30
-rw-r--r--unix/Makefile.in19
-rw-r--r--win/Makefile.in4
-rw-r--r--win/makefile.vc4
8 files changed, 287 insertions, 301 deletions
diff --git a/generic/tclExecute.c b/generic/tclExecute.c
index 112924a..189832f 100644
--- a/generic/tclExecute.c
+++ b/generic/tclExecute.c
@@ -8222,6 +8222,126 @@ FinalizeOONextFilter(
}
/*
+ * LongPwrSmallExpon -- , WidePwrSmallExpon --
+ *
+ * Helpers to calculate small powers of integers whose result is long or wide.
+ */
+static inline long
+LongPwrSmallExpon(long l1, long exponent) {
+
+ long lResult;
+
+ lResult = l1 * l1; /* b**2 */
+ switch (exponent) {
+ case 2:
+ break;
+ case 3:
+ lResult *= l1; /* b**3 */
+ break;
+ case 4:
+ lResult *= lResult; /* b**4 */
+ break;
+ case 5:
+ lResult *= lResult; /* b**4 */
+ lResult *= l1; /* b**5 */
+ break;
+ case 6:
+ lResult *= l1; /* b**3 */
+ lResult *= lResult; /* b**6 */
+ break;
+ case 7:
+ lResult *= l1; /* b**3 */
+ lResult *= lResult; /* b**6 */
+ lResult *= l1; /* b**7 */
+ break;
+ case 8:
+ lResult *= lResult; /* b**4 */
+ lResult *= lResult; /* b**8 */
+ break;
+ }
+ return lResult;
+}
+static inline Tcl_WideInt
+WidePwrSmallExpon(Tcl_WideInt w1, long exponent) {
+
+ Tcl_WideInt wResult;
+
+ wResult = w1 * w1; /* b**2 */
+ switch (exponent) {
+ case 2:
+ break;
+ case 3:
+ wResult *= w1; /* b**3 */
+ break;
+ case 4:
+ wResult *= wResult; /* b**4 */
+ break;
+ case 5:
+ wResult *= wResult; /* b**4 */
+ wResult *= w1; /* b**5 */
+ break;
+ case 6:
+ wResult *= w1; /* b**3 */
+ wResult *= wResult; /* b**6 */
+ break;
+ case 7:
+ wResult *= w1; /* b**3 */
+ wResult *= wResult; /* b**6 */
+ wResult *= w1; /* b**7 */
+ break;
+ case 8:
+ wResult *= wResult; /* b**4 */
+ wResult *= wResult; /* b**8 */
+ break;
+ case 9:
+ wResult *= wResult; /* b**4 */
+ wResult *= wResult; /* b**8 */
+ wResult *= w1; /* b**9 */
+ break;
+ case 10:
+ wResult *= wResult; /* b**4 */
+ wResult *= w1; /* b**5 */
+ wResult *= wResult; /* b**10 */
+ break;
+ case 11:
+ wResult *= wResult; /* b**4 */
+ wResult *= w1; /* b**5 */
+ wResult *= wResult; /* b**10 */
+ wResult *= w1; /* b**11 */
+ break;
+ case 12:
+ wResult *= w1; /* b**3 */
+ wResult *= wResult; /* b**6 */
+ wResult *= wResult; /* b**12 */
+ break;
+ case 13:
+ wResult *= w1; /* b**3 */
+ wResult *= wResult; /* b**6 */
+ wResult *= wResult; /* b**12 */
+ wResult *= w1; /* b**13 */
+ break;
+ case 14:
+ wResult *= w1; /* b**3 */
+ wResult *= wResult; /* b**6 */
+ wResult *= w1; /* b**7 */
+ wResult *= wResult; /* b**14 */
+ break;
+ case 15:
+ wResult *= w1; /* b**3 */
+ wResult *= wResult; /* b**6 */
+ wResult *= w1; /* b**7 */
+ wResult *= wResult; /* b**14 */
+ wResult *= w1; /* b**15 */
+ break;
+ case 16:
+ wResult *= wResult; /* b**4 */
+ wResult *= wResult; /* b**8 */
+ wResult *= wResult; /* b**16 */
+ break;
+ }
+ return wResult;
+}
+/*
*----------------------------------------------------------------------
*
* ExecuteExtendedBinaryMathOp, ExecuteExtendedUnaryMathOp --
@@ -8292,7 +8412,7 @@ ExecuteExtendedBinaryMathOp(
Tcl_WideInt w1, w2, wResult;
mp_int big1, big2, bigResult, bigRemainder;
Tcl_Obj *objResultPtr;
- int invalid, numPos, zero;
+ int invalid, zero;
long shift;
(void) GetNumberFromObj(NULL, valuePtr, &ptr1, &type1);
@@ -8321,7 +8441,7 @@ ExecuteExtendedBinaryMathOp(
w1 = *((const Tcl_WideInt *)ptr1);
if (type2 != TCL_NUMBER_BIG) {
Tcl_WideInt wQuotient, wRemainder;
- Tcl_GetWideIntFromObj(NULL, value2Ptr, &w2);
+ TclGetWideIntFromObj(NULL, value2Ptr, &w2);
wQuotient = w1 / w2;
/*
@@ -8520,16 +8640,7 @@ ExecuteExtendedBinaryMathOp(
if (opcode == INST_LSHIFT) {
mp_mul_2d(&big1, shift, &bigResult);
} else {
- mp_init(&bigRemainder);
- mp_div_2d(&big1, shift, &bigResult, &bigRemainder);
- if (mp_cmp_d(&bigRemainder, 0) == MP_LT) {
- /*
- * Convert to Tcl's integer division rules.
- */
-
- mp_sub_d(&bigResult, 1, &bigResult);
- }
- mp_clear(&bigRemainder);
+ mp_tc_div_2d(&big1, shift, &bigResult);
}
mp_clear(&big1);
BIG_RESULT(&bigResult);
@@ -8539,138 +8650,22 @@ ExecuteExtendedBinaryMathOp(
case INST_BITXOR:
case INST_BITAND:
if ((type1 == TCL_NUMBER_BIG) || (type2 == TCL_NUMBER_BIG)) {
- mp_int *First, *Second;
-
Tcl_TakeBignumFromObj(NULL, valuePtr, &big1);
Tcl_TakeBignumFromObj(NULL, value2Ptr, &big2);
- /*
- * Count how many positive arguments we have. If only one of the
- * arguments is negative, store it in 'Second'.
- */
-
- if (mp_cmp_d(&big1, 0) != MP_LT) {
- numPos = 1 + (mp_cmp_d(&big2, 0) != MP_LT);
- First = &big1;
- Second = &big2;
- } else {
- First = &big2;
- Second = &big1;
- numPos = (mp_cmp_d(First, 0) != MP_LT);
- }
mp_init(&bigResult);
switch (opcode) {
case INST_BITAND:
- switch (numPos) {
- case 2:
- /*
- * Both arguments positive, base case.
- */
-
- mp_and(First, Second, &bigResult);
- break;
- case 1:
- /*
- * First is positive; second negative:
- * P & N = P & ~~N = P&~(-N-1) = P & (P ^ (-N-1))
- */
-
- mp_neg(Second, Second);
- mp_sub_d(Second, 1, Second);
- mp_xor(First, Second, &bigResult);
- mp_and(First, &bigResult, &bigResult);
- break;
- case 0:
- /*
- * Both arguments negative:
- * a & b = ~ (~a | ~b) = -(-a-1|-b-1)-1
- */
-
- mp_neg(First, First);
- mp_sub_d(First, 1, First);
- mp_neg(Second, Second);
- mp_sub_d(Second, 1, Second);
- mp_or(First, Second, &bigResult);
- mp_neg(&bigResult, &bigResult);
- mp_sub_d(&bigResult, 1, &bigResult);
- break;
- }
+ mp_tc_and(&big1, &big2, &bigResult);
break;
case INST_BITOR:
- switch (numPos) {
- case 2:
- /*
- * Both arguments positive, base case.
- */
-
- mp_or(First, Second, &bigResult);
- break;
- case 1:
- /*
- * First is positive; second negative:
- * N|P = ~(~N&~P) = ~((-N-1)&~P) = -((-N-1)&((-N-1)^P))-1
- */
-
- mp_neg(Second, Second);
- mp_sub_d(Second, 1, Second);
- mp_xor(First, Second, &bigResult);
- mp_and(Second, &bigResult, &bigResult);
- mp_neg(&bigResult, &bigResult);
- mp_sub_d(&bigResult, 1, &bigResult);
- break;
- case 0:
- /*
- * Both arguments negative:
- * a | b = ~ (~a & ~b) = -(-a-1&-b-1)-1
- */
-
- mp_neg(First, First);
- mp_sub_d(First, 1, First);
- mp_neg(Second, Second);
- mp_sub_d(Second, 1, Second);
- mp_and(First, Second, &bigResult);
- mp_neg(&bigResult, &bigResult);
- mp_sub_d(&bigResult, 1, &bigResult);
- break;
- }
+ mp_tc_or(&big1, &big2, &bigResult);
break;
case INST_BITXOR:
- switch (numPos) {
- case 2:
- /*
- * Both arguments positive, base case.
- */
-
- mp_xor(First, Second, &bigResult);
- break;
- case 1:
- /*
- * First is positive; second negative:
- * P^N = ~(P^~N) = -(P^(-N-1))-1
- */
-
- mp_neg(Second, Second);
- mp_sub_d(Second, 1, Second);
- mp_xor(First, Second, &bigResult);
- mp_neg(&bigResult, &bigResult);
- mp_sub_d(&bigResult, 1, &bigResult);
- break;
- case 0:
- /*
- * Both arguments negative:
- * a ^ b = (~a ^ ~b) = (-a-1^-b-1)
- */
-
- mp_neg(First, First);
- mp_sub_d(First, 1, First);
- mp_neg(Second, Second);
- mp_sub_d(Second, 1, Second);
- mp_xor(First, Second, &bigResult);
- break;
- }
+ mp_tc_xor(&big1, &big2, &bigResult);
break;
}
@@ -8735,8 +8730,11 @@ ExecuteExtendedBinaryMathOp(
goto doubleResult;
}
l1 = l2 = 0;
- if (type2 == TCL_NUMBER_LONG) {
+ w1 = w2 = 0; /* to silence compiler warning (maybe-uninitialized) */
+ switch (type2) {
+ case TCL_NUMBER_LONG:
l2 = *((const long *) ptr2);
+ pwrLongExpon:
if (l2 == 0) {
/*
* Anything to the zero power is 1.
@@ -8750,16 +8748,18 @@ ExecuteExtendedBinaryMathOp(
return NULL;
}
- }
-
- switch (type2) {
- case TCL_NUMBER_LONG:
negativeExponent = (l2 < 0);
oddExponent = (int) (l2 & 1);
break;
#ifndef TCL_WIDE_INT_IS_LONG
case TCL_NUMBER_WIDE:
w2 = *((const Tcl_WideInt *)ptr2);
+ /* check it fits in long */
+ l2 = (long)w2;
+ if (w2 == l2) {
+ type2 = TCL_NUMBER_LONG;
+ goto pwrLongExpon;
+ }
negativeExponent = (w2 < 0);
oddExponent = (int) (w2 & (Tcl_WideInt)1);
break;
@@ -8773,48 +8773,18 @@ ExecuteExtendedBinaryMathOp(
break;
}
- if (type1 == TCL_NUMBER_LONG) {
+ switch (type1) {
+ case TCL_NUMBER_LONG:
l1 = *((const long *)ptr1);
- }
- if (negativeExponent) {
- if (type1 == TCL_NUMBER_LONG) {
- switch (l1) {
- case 0:
- /*
- * Zero to a negative power is div by zero error.
- */
-
- return EXPONENT_OF_ZERO;
- case -1:
- if (oddExponent) {
- LONG_RESULT(-1);
- }
- /* fallthrough */
- case 1:
- /*
- * 1 to any power is 1.
- */
-
- return constants[1];
- }
- }
-
- /*
- * Integers with magnitude greater than 1 raise to a negative
- * power yield the answer zero (see TIP 123).
- */
-
- return constants[0];
- }
-
- if (type1 == TCL_NUMBER_LONG) {
+ pwrLongBase:
switch (l1) {
case 0:
/*
* Zero to a positive power is zero.
+ * Zero to a negative power is div by zero error.
*/
- return constants[0];
+ return (!negativeExponent) ? constants[0] : EXPONENT_OF_ZERO;
case 1:
/*
* 1 to any power is 1.
@@ -8822,11 +8792,44 @@ ExecuteExtendedBinaryMathOp(
return constants[1];
case -1:
- if (!oddExponent) {
- return constants[1];
+ if (!negativeExponent) {
+ if (!oddExponent) {
+ return constants[1];
+ }
+ LONG_RESULT(-1);
}
- LONG_RESULT(-1);
+ /* negativeExponent */
+ if (oddExponent) {
+ LONG_RESULT(-1);
+ }
+ return constants[1];
}
+ break;
+#ifndef TCL_WIDE_INT_IS_LONG
+ case TCL_NUMBER_WIDE:
+ w1 = *((const Tcl_WideInt *) ptr1);
+ /* check it fits in long */
+ l1 = (long)w1;
+ if (w1 == l1) {
+ type1 = TCL_NUMBER_LONG;
+ goto pwrLongBase;
+ }
+ break;
+#endif
+ }
+ if (negativeExponent) {
+
+ /*
+ * Integers with magnitude greater than 1 raise to a negative
+ * power yield the answer zero (see TIP 123).
+ */
+
+ return constants[0];
+ }
+
+
+ if (type1 == TCL_NUMBER_BIG) {
+ goto overflowExpon;
}
/*
@@ -8844,6 +8847,8 @@ ExecuteExtendedBinaryMathOp(
return GENERAL_ARITHMETIC_ERROR;
}
+ /* From here (up to overflowExpon) exponent is long (l2). */
+
if (type1 == TCL_NUMBER_LONG) {
if (l1 == 2) {
/*
@@ -8884,35 +8889,8 @@ ExecuteExtendedBinaryMathOp(
/*
* Small powers of 32-bit integers.
*/
+ lResult = LongPwrSmallExpon(l1, l2);
- lResult = l1 * l1; /* b**2 */
- switch (l2) {
- case 2:
- break;
- case 3:
- lResult *= l1; /* b**3 */
- break;
- case 4:
- lResult *= lResult; /* b**4 */
- break;
- case 5:
- lResult *= lResult; /* b**4 */
- lResult *= l1; /* b**5 */
- break;
- case 6:
- lResult *= l1; /* b**3 */
- lResult *= lResult; /* b**6 */
- break;
- case 7:
- lResult *= l1; /* b**3 */
- lResult *= lResult; /* b**6 */
- lResult *= l1; /* b**7 */
- break;
- case 8:
- lResult *= lResult; /* b**4 */
- lResult *= lResult; /* b**8 */
- break;
- }
LONG_RESULT(lResult);
}
@@ -8945,97 +8923,24 @@ ExecuteExtendedBinaryMathOp(
}
}
#endif
- }
#if (LONG_MAX > 0x7fffffff) || !defined(TCL_WIDE_INT_IS_LONG)
- if (type1 == TCL_NUMBER_LONG) {
+ /* Code below (up to overflowExpon) works with wide-int base */
w1 = l1;
-#ifndef TCL_WIDE_INT_IS_LONG
- } else if (type1 == TCL_NUMBER_WIDE) {
- w1 = *((const Tcl_WideInt *) ptr1);
#endif
- } else {
- goto overflowExpon;
}
+
+#if (LONG_MAX > 0x7fffffff) || !defined(TCL_WIDE_INT_IS_LONG)
+
+ /* From here (up to overflowExpon) base is wide-int (w1). */
+
if (l2 - 2 < (long)MaxBase64Size
&& w1 <= MaxBase64[l2 - 2]
&& w1 >= -MaxBase64[l2 - 2]) {
/*
* Small powers of integers whose result is wide.
*/
+ wResult = WidePwrSmallExpon(w1, l2);
- wResult = w1 * w1; /* b**2 */
- switch (l2) {
- case 2:
- break;
- case 3:
- wResult *= l1; /* b**3 */
- break;
- case 4:
- wResult *= wResult; /* b**4 */
- break;
- case 5:
- wResult *= wResult; /* b**4 */
- wResult *= w1; /* b**5 */
- break;
- case 6:
- wResult *= w1; /* b**3 */
- wResult *= wResult; /* b**6 */
- break;
- case 7:
- wResult *= w1; /* b**3 */
- wResult *= wResult; /* b**6 */
- wResult *= w1; /* b**7 */
- break;
- case 8:
- wResult *= wResult; /* b**4 */
- wResult *= wResult; /* b**8 */
- break;
- case 9:
- wResult *= wResult; /* b**4 */
- wResult *= wResult; /* b**8 */
- wResult *= w1; /* b**9 */
- break;
- case 10:
- wResult *= wResult; /* b**4 */
- wResult *= w1; /* b**5 */
- wResult *= wResult; /* b**10 */
- break;
- case 11:
- wResult *= wResult; /* b**4 */
- wResult *= w1; /* b**5 */
- wResult *= wResult; /* b**10 */
- wResult *= w1; /* b**11 */
- break;
- case 12:
- wResult *= w1; /* b**3 */
- wResult *= wResult; /* b**6 */
- wResult *= wResult; /* b**12 */
- break;
- case 13:
- wResult *= w1; /* b**3 */
- wResult *= wResult; /* b**6 */
- wResult *= wResult; /* b**12 */
- wResult *= w1; /* b**13 */
- break;
- case 14:
- wResult *= w1; /* b**3 */
- wResult *= wResult; /* b**6 */
- wResult *= w1; /* b**7 */
- wResult *= wResult; /* b**14 */
- break;
- case 15:
- wResult *= w1; /* b**3 */
- wResult *= wResult; /* b**6 */
- wResult *= w1; /* b**7 */
- wResult *= wResult; /* b**14 */
- wResult *= w1; /* b**15 */
- break;
- case 16:
- wResult *= wResult; /* b**4 */
- wResult *= wResult; /* b**8 */
- wResult *= wResult; /* b**16 */
- break;
- }
WIDE_RESULT(wResult);
}
diff --git a/generic/tclStubInit.c b/generic/tclStubInit.c
index 1d15715..6290aa0 100644
--- a/generic/tclStubInit.c
+++ b/generic/tclStubInit.c
@@ -859,10 +859,10 @@ const TclTomMathStubs tclTomMathStubs = {
TclBN_mp_set_long, /* 70 */
0, /* 71 */
0, /* 72 */
- 0, /* 73 */
- 0, /* 74 */
- 0, /* 75 */
- 0, /* 76 */
+ TclBN_mp_tc_and, /* 73 */
+ TclBN_mp_tc_or, /* 74 */
+ TclBN_mp_tc_xor, /* 75 */
+ TclBN_mp_tc_div_2d, /* 76 */
TclBN_mp_get_bit, /* 77 */
};
diff --git a/generic/tclTomMath.decls b/generic/tclTomMath.decls
index 09bf97d..6f4b4c3 100644
--- a/generic/tclTomMath.decls
+++ b/generic/tclTomMath.decls
@@ -240,6 +240,21 @@ declare 67 {
declare 70 {
int TclBN_mp_set_long(mp_int *a, unsigned long i)
}
+
+# Added in libtommath 1.1.0
+declare 73 {
+ int TclBN_mp_tc_and(const mp_int *a, const mp_int *b, mp_int *c)
+}
+declare 74 {
+ int TclBN_mp_tc_or(const mp_int *a, const mp_int *b, mp_int *c)
+}
+declare 75 {
+ int TclBN_mp_tc_xor(const mp_int *a, const mp_int *b, mp_int *c)
+}
+declare 76 {
+ int TclBN_mp_tc_div_2d(const mp_int *a, int b, mp_int *c)
+}
+
declare 77 {
int TclBN_mp_get_bit(const mp_int *a, int b)
}
diff --git a/generic/tclTomMathDecls.h b/generic/tclTomMathDecls.h
index f287b84..9b525d2 100644
--- a/generic/tclTomMathDecls.h
+++ b/generic/tclTomMathDecls.h
@@ -96,6 +96,10 @@
#define mp_sqrt TclBN_mp_sqrt
#define mp_sub TclBN_mp_sub
#define mp_sub_d TclBN_mp_sub_d
+#define mp_tc_and TclBN_mp_tc_and
+#define mp_tc_div_2d TclBN_mp_tc_div_2d
+#define mp_tc_or TclBN_mp_tc_or
+#define mp_tc_xor TclBN_mp_tc_xor
#define mp_to_unsigned_bin TclBN_mp_to_unsigned_bin
#define mp_to_unsigned_bin_n TclBN_mp_to_unsigned_bin_n
#define mp_toom_mul TclBN_mp_toom_mul
@@ -307,10 +311,17 @@ EXTERN int TclBN_mp_expt_d_ex(const mp_int *a, mp_digit b,
EXTERN int TclBN_mp_set_long(mp_int *a, unsigned long i);
/* Slot 71 is reserved */
/* Slot 72 is reserved */
-/* Slot 73 is reserved */
-/* Slot 74 is reserved */
-/* Slot 75 is reserved */
-/* Slot 76 is reserved */
+/* 73 */
+EXTERN int TclBN_mp_tc_and(const mp_int *a, const mp_int *b,
+ mp_int *c);
+/* 74 */
+EXTERN int TclBN_mp_tc_or(const mp_int *a, const mp_int *b,
+ mp_int *c);
+/* 75 */
+EXTERN int TclBN_mp_tc_xor(const mp_int *a, const mp_int *b,
+ mp_int *c);
+/* 76 */
+EXTERN int TclBN_mp_tc_div_2d(const mp_int *a, int b, mp_int *c);
/* 77 */
EXTERN int TclBN_mp_get_bit(const mp_int *a, int b);
@@ -391,10 +402,10 @@ typedef struct TclTomMathStubs {
int (*tclBN_mp_set_long) (mp_int *a, unsigned long i); /* 70 */
void (*reserved71)(void);
void (*reserved72)(void);
- void (*reserved73)(void);
- void (*reserved74)(void);
- void (*reserved75)(void);
- void (*reserved76)(void);
+ int (*tclBN_mp_tc_and) (const mp_int *a, const mp_int *b, mp_int *c); /* 73 */
+ int (*tclBN_mp_tc_or) (const mp_int *a, const mp_int *b, mp_int *c); /* 74 */
+ int (*tclBN_mp_tc_xor) (const mp_int *a, const mp_int *b, mp_int *c); /* 75 */
+ int (*tclBN_mp_tc_div_2d) (const mp_int *a, int b, mp_int *c); /* 76 */
int (*tclBN_mp_get_bit) (const mp_int *a, int b); /* 77 */
} TclTomMathStubs;
@@ -552,10 +563,14 @@ extern const TclTomMathStubs *tclTomMathStubsPtr;
(tclTomMathStubsPtr->tclBN_mp_set_long) /* 70 */
/* Slot 71 is reserved */
/* Slot 72 is reserved */
-/* Slot 73 is reserved */
-/* Slot 74 is reserved */
-/* Slot 75 is reserved */
-/* Slot 76 is reserved */
+#define TclBN_mp_tc_and \
+ (tclTomMathStubsPtr->tclBN_mp_tc_and) /* 73 */
+#define TclBN_mp_tc_or \
+ (tclTomMathStubsPtr->tclBN_mp_tc_or) /* 74 */
+#define TclBN_mp_tc_xor \
+ (tclTomMathStubsPtr->tclBN_mp_tc_xor) /* 75 */
+#define TclBN_mp_tc_div_2d \
+ (tclTomMathStubsPtr->tclBN_mp_tc_div_2d) /* 76 */
#define TclBN_mp_get_bit \
(tclTomMathStubsPtr->tclBN_mp_get_bit) /* 77 */
diff --git a/tests/mathop.test b/tests/mathop.test
index f122b7b..a1a3f80 100644
--- a/tests/mathop.test
+++ b/tests/mathop.test
@@ -1206,6 +1206,8 @@ test mathop-25.5 { exp operator } {TestOp ** 1 5} 1
test mathop-25.6 { exp operator } {TestOp ** 5 1} 5
test mathop-25.7 { exp operator } {TestOp ** 4 3 2 1} 262144
test mathop-25.8 { exp operator } {TestOp ** 5.5 4} 915.0625
+test mathop-25.8a { exp operator } {TestOp ** 4.0 -1} 0.25
+test mathop-25.8b { exp operator } {TestOp ** 2.0 -2} 0.25
test mathop-25.9 { exp operator } {TestOp ** 16 3.5} 16384.0
test mathop-25.10 { exp operator } {TestOp ** 3.5 0} 1.0
test mathop-25.11 { exp operator } {TestOp ** 378 0} 1
@@ -1219,8 +1221,32 @@ test mathop-25.18 { exp operator } {TestOp ** -1 -2} 1
test mathop-25.19 { exp operator } {TestOp ** -1 3} -1
test mathop-25.20 { exp operator } {TestOp ** -1 4} 1
test mathop-25.21 { exp operator } {TestOp ** 2 63} 9223372036854775808
-test mathop-25.22 { exp operator } {TestOp ** 83756485763458746358734658473567847567473 2} 7015148907444467657897585474493757781161998914521537835809623408157343003287605729
-test mathop-25.23 { exp operator errors } {
+test mathop-25.22 { exp operator } {TestOp ** 2 256} 115792089237316195423570985008687907853269984665640564039457584007913129639936
+set big 83756485763458746358734658473567847567473
+test mathop-25.23 { exp operator } {TestOp ** $big 2} 7015148907444467657897585474493757781161998914521537835809623408157343003287605729
+test mathop-25.24 { exp operator } {TestOp ** $big 0} 1
+test mathop-25.25 { exp operator } {TestOp ** $big 1} $big
+test mathop-25.26 { exp operator } {TestOp ** $big -1} 0
+test mathop-25.27 { exp operator } {TestOp ** $big -2} 0
+test mathop-25.28 { exp operator } {TestOp ** $big -$big} 0
+test mathop-25.29 { exp operator } {expr {[set res [TestOp ** $big -1.0]] > 0 && $res < 1.2e-41}} 1
+test mathop-25.30 { exp operator } {expr {[set res [TestOp ** $big -1e-18]] > 0 && $res < 1}} 1
+test mathop-25.31 { exp operator } {expr {[set res [TestOp ** -$big -1.0]] > -1 && $res < 0}} 1
+test mathop-25.32 { exp operator } {expr {[set res [TestOp ** -$big -2.0]] > 0 && $res < 1}} 1
+test mathop-25.33 { exp operator } {expr {[set res [TestOp ** -$big -3.0]] > -1 && $res < 0}} 1
+test mathop-25.34 { exp operator } {TestOp ** $big -1e-30} 1.0
+test mathop-25.35 { exp operator } {TestOp ** $big -1e+30} 0.0
+test mathop-25.36 { exp operator } {TestOp ** 0 $big} 0
+test mathop-25.37 { exp operator } {TestOp ** 1 $big} 1
+test mathop-25.38 { exp operator } {TestOp ** -1 $big} -1
+test mathop-25.39 { exp operator } {TestOp ** -1 [expr {$big+1}]} 1
+test mathop-25.40 { exp operator (small exponent power helper and its boundaries) } {
+ set pwr 0
+ set res 1
+ while {[incr pwr] <= 17 && [set i [TestOp ** 15 $pwr]] == [set res [expr {$res * 15}]]} {}
+ list [incr pwr -1] $res
+} {17 98526125335693359375}
+test mathop-25.41 { exp operator errors } {
set res {}
set exp {}
diff --git a/unix/Makefile.in b/unix/Makefile.in
index bdab85a..8a4c72a 100644
--- a/unix/Makefile.in
+++ b/unix/Makefile.in
@@ -332,7 +332,8 @@ TOMMATH_OBJS = bn_reverse.o bn_fast_s_mp_mul_digs.o \
bn_mp_read_radix.o bn_mp_rshd.o bn_mp_set.o bn_mp_set_int.o \
bn_mp_set_long.o bn_mp_shrink.o \
bn_mp_sqr.o bn_mp_sqrt.o bn_mp_sub.o bn_mp_sub_d.o \
- bn_mp_to_unsigned_bin.o bn_mp_to_unsigned_bin_n.o \
+ bn_mp_tc_and.o bn_mp_tc_div_2d.o bn_mp_tc_or.o bn_mp_tc_xor.o \
+ bn_mp_to_unsigned_bin.o bn_mp_to_unsigned_bin_n.o \
bn_mp_toom_mul.o bn_mp_toom_sqr.o bn_mp_toradix_n.o \
bn_mp_unsigned_bin_size.o bn_mp_xor.o bn_mp_zero.o bn_s_mp_add.o \
bn_s_mp_mul_digs.o bn_s_mp_sqr.o bn_s_mp_sub.o
@@ -536,6 +537,10 @@ TOMMATH_SRCS = \
$(TOMMATH_DIR)/bn_mp_sqrt.c \
$(TOMMATH_DIR)/bn_mp_sub.c \
$(TOMMATH_DIR)/bn_mp_sub_d.c \
+ $(TOMMATH_DIR)/bn_mp_tc_and.c \
+ $(TOMMATH_DIR)/bn_mp_tc_div_2d.c \
+ $(TOMMATH_DIR)/bn_mp_tc_or.c \
+ $(TOMMATH_DIR)/bn_mp_tc_xor.c \
$(TOMMATH_DIR)/bn_mp_to_unsigned_bin.c \
$(TOMMATH_DIR)/bn_mp_to_unsigned_bin_n.c \
$(TOMMATH_DIR)/bn_mp_toom_mul.c \
@@ -1517,6 +1522,18 @@ bn_mp_sub.o: $(TOMMATH_DIR)/bn_mp_sub.c $(MATHHDRS)
bn_mp_sub_d.o: $(TOMMATH_DIR)/bn_mp_sub_d.c $(MATHHDRS)
$(CC) -c $(CC_SWITCHES) $(TOMMATH_DIR)/bn_mp_sub_d.c
+bn_mp_tc_and.o: $(TOMMATH_DIR)/bn_mp_tc_and.c $(MATHHDRS)
+ $(CC) -c $(CC_SWITCHES) $(TOMMATH_DIR)/bn_mp_tc_and.c
+
+bn_mp_tc_div_2d.o: $(TOMMATH_DIR)/bn_mp_tc_div_2d.c $(MATHHDRS)
+ $(CC) -c $(CC_SWITCHES) $(TOMMATH_DIR)/bn_mp_tc_div_2d.c
+
+bn_mp_tc_or.o: $(TOMMATH_DIR)/bn_mp_tc_or.c $(MATHHDRS)
+ $(CC) -c $(CC_SWITCHES) $(TOMMATH_DIR)/bn_mp_tc_or.c
+
+bn_mp_tc_xor.o: $(TOMMATH_DIR)/bn_mp_tc_xor.c $(MATHHDRS)
+ $(CC) -c $(CC_SWITCHES) $(TOMMATH_DIR)/bn_mp_tc_xor.c
+
bn_mp_to_unsigned_bin.o: $(TOMMATH_DIR)/bn_mp_to_unsigned_bin.c $(MATHHDRS)
$(CC) -c $(CC_SWITCHES) $(TOMMATH_DIR)/bn_mp_to_unsigned_bin.c
diff --git a/win/Makefile.in b/win/Makefile.in
index a427eee..cc3de21 100644
--- a/win/Makefile.in
+++ b/win/Makefile.in
@@ -365,6 +365,10 @@ TOMMATH_OBJS = \
bn_mp_sqrt.${OBJEXT} \
bn_mp_sub.${OBJEXT} \
bn_mp_sub_d.${OBJEXT} \
+ bn_mp_tc_and.${OBJEXT} \
+ bn_mp_tc_div_2d.${OBJEXT} \
+ bn_mp_tc_or.${OBJEXT} \
+ bn_mp_tc_xor.${OBJEXT} \
bn_mp_to_unsigned_bin.${OBJEXT} \
bn_mp_to_unsigned_bin_n.${OBJEXT} \
bn_mp_toom_mul.${OBJEXT} \
diff --git a/win/makefile.vc b/win/makefile.vc
index 2e0198e..d1122a4 100644
--- a/win/makefile.vc
+++ b/win/makefile.vc
@@ -305,6 +305,10 @@ TOMMATHOBJS = \
$(TMP_DIR)\bn_mp_sqrt.obj \
$(TMP_DIR)\bn_mp_sub.obj \
$(TMP_DIR)\bn_mp_sub_d.obj \
+ $(TMP_DIR)\bn_mp_tc_and.obj \
+ $(TMP_DIR)\bn_mp_tc_div_2d.obj \
+ $(TMP_DIR)\bn_mp_tc_or.obj \
+ $(TMP_DIR)\bn_mp_tc_xor.obj \
$(TMP_DIR)\bn_mp_to_unsigned_bin.obj \
$(TMP_DIR)\bn_mp_to_unsigned_bin_n.obj \
$(TMP_DIR)\bn_mp_toom_mul.obj \