big: Use new comparison helpers.

This commit is contained in:
Jeroen van Rijn
2021-09-01 19:13:47 +02:00
parent 335d361fc6
commit 671b413b15
5 changed files with 41 additions and 46 deletions
+3 -2
View File
@@ -1,9 +1,10 @@
@echo off @echo off
odin run . -vet :odin run . -vet
set TEST_ARGS=-fast-tests set TEST_ARGS=-fast-tests
:set TEST_ARGS=
:odin build . -build-mode:shared -show-timings -o:minimal -no-bounds-check -define:MATH_BIG_EXE=false && python test.py %TEST_ARGS% :odin build . -build-mode:shared -show-timings -o:minimal -no-bounds-check -define:MATH_BIG_EXE=false && python test.py %TEST_ARGS%
:odin build . -build-mode:shared -show-timings -o:size -no-bounds-check -define:MATH_BIG_EXE=false && python test.py %TEST_ARGS% :odin build . -build-mode:shared -show-timings -o:size -no-bounds-check -define:MATH_BIG_EXE=false && python test.py %TEST_ARGS%
:odin build . -build-mode:shared -show-timings -o:size -define:MATH_BIG_EXE=false && python test.py %TEST_ARGS% :odin build . -build-mode:shared -show-timings -o:size -define:MATH_BIG_EXE=false && python test.py %TEST_ARGS%
:odin build . -build-mode:shared -show-timings -o:speed -no-bounds-check -define:MATH_BIG_EXE=false && python test.py %TEST_ARGS% odin build . -build-mode:shared -show-timings -o:speed -no-bounds-check -define:MATH_BIG_EXE=false && python test.py %TEST_ARGS%
:odin build . -build-mode:shared -show-timings -o:speed -define:MATH_BIG_EXE=false && python test.py -fast-tests %TEST_ARGS% :odin build . -build-mode:shared -show-timings -o:speed -define:MATH_BIG_EXE=false && python test.py -fast-tests %TEST_ARGS%
+14 -15
View File
@@ -136,7 +136,7 @@ internal_int_add_signed :: proc(dest, a, b: ^Int, allocator := context.allocator
Subtract the one with the greater magnitude from the other. Subtract the one with the greater magnitude from the other.
The result gets the sign of the one with the greater magnitude. The result gets the sign of the one with the greater magnitude.
*/ */
if #force_inline internal_cmp_mag(a, b) == -1 { if #force_inline internal_lt_abs(a, b) {
x, y = y, x; x, y = y, x;
} }
@@ -358,7 +358,7 @@ internal_int_sub_signed :: proc(dest, number, decrease: ^Int, allocator := conte
Subtract a positive from a positive, OR negative from a negative. Subtract a positive from a positive, OR negative from a negative.
First, take the difference between their magnitudes, then... First, take the difference between their magnitudes, then...
*/ */
if #force_inline internal_cmp_mag(number, decrease) == -1 { if #force_inline internal_lt_abs(number, decrease) {
/* /*
The second has a larger magnitude. The second has a larger magnitude.
The result has the *opposite* sign from the first number. The result has the *opposite* sign from the first number.
@@ -718,7 +718,7 @@ internal_int_divmod :: proc(quotient, remainder, numerator, denominator: ^Int, a
/* /*
If numerator < denominator then quotient = 0, remainder = numerator. If numerator < denominator then quotient = 0, remainder = numerator.
*/ */
if #force_inline internal_cmp_mag(numerator, denominator) == -1 { if #force_inline internal_lt_abs(numerator, denominator) {
if remainder != nil { if remainder != nil {
internal_copy(remainder, numerator) or_return; internal_copy(remainder, numerator) or_return;
} }
@@ -731,7 +731,6 @@ internal_int_divmod :: proc(quotient, remainder, numerator, denominator: ^Int, a
if (denominator.used > 2 * MUL_KARATSUBA_CUTOFF) && (denominator.used <= (numerator.used / 3) * 2) { if (denominator.used > 2 * MUL_KARATSUBA_CUTOFF) && (denominator.used <= (numerator.used / 3) * 2) {
assert(denominator.used >= 160 && numerator.used >= 240, "MUL_KARATSUBA_CUTOFF global not properly set."); assert(denominator.used >= 160 && numerator.used >= 240, "MUL_KARATSUBA_CUTOFF global not properly set.");
err = _private_int_div_recursive(quotient, remainder, numerator, denominator); err = _private_int_div_recursive(quotient, remainder, numerator, denominator);
// err = #force_inline _private_int_div_school(quotient, remainder, numerator, denominator);
} else { } else {
when true { when true {
err = #force_inline _private_int_div_school(quotient, remainder, numerator, denominator); err = #force_inline _private_int_div_school(quotient, remainder, numerator, denominator);
@@ -1243,12 +1242,12 @@ internal_less_than_or_equal :: proc {
internal_int_less_than_or_equal, internal_int_less_than_or_equal,
internal_int_less_than_or_equal_digit, internal_int_less_than_or_equal_digit,
} }
internal_lteq :: internal_less_than_or_equal; internal_lte :: internal_less_than_or_equal;
internal_less_than_or_equal_abs :: proc { internal_less_than_or_equal_abs :: proc {
internal_int_less_than_or_equal_abs, internal_int_less_than_or_equal_abs,
} }
internal_lteq_abs :: internal_less_than_or_equal_abs; internal_lte_abs :: internal_less_than_or_equal_abs;
/* /*
@@ -1311,12 +1310,12 @@ internal_greater_than_or_equal :: proc {
internal_int_greater_than_or_equal, internal_int_greater_than_or_equal,
internal_int_greater_than_or_equal_digit, internal_int_greater_than_or_equal_digit,
} }
internal_gteq :: internal_greater_than_or_equal; internal_gte :: internal_greater_than_or_equal;
internal_greater_than_or_equal_abs :: proc { internal_greater_than_or_equal_abs :: proc {
internal_int_greater_than_or_equal_abs, internal_int_greater_than_or_equal_abs,
} }
internal_gteq_abs :: internal_greater_than_or_equal_abs; internal_gte_abs :: internal_greater_than_or_equal_abs;
/* /*
@@ -1410,7 +1409,7 @@ internal_int_is_square :: proc(a: ^Int, allocator := context.allocator) -> (squa
sqrt(t, a) or_return; sqrt(t, a) or_return;
sqr(t, t) or_return; sqr(t, t) or_return;
square = internal_cmp_mag(t, a) == 0; square = internal_eq_abs(t, a);
return; return;
} }
@@ -1642,7 +1641,7 @@ internal_int_sqrt :: proc(dest, src: ^Int, allocator := context.allocator) -> (e
internal_add(t2, t1, x) or_return; internal_add(t2, t1, x) or_return;
internal_shr(y, t2, 1) or_return; internal_shr(y, t2, 1) or_return;
if c := internal_cmp(y, x); c == 0 || c == 1 { if internal_gte(y, x) {
internal_swap(dest, x); internal_swap(dest, x);
return nil; return nil;
} }
@@ -1757,8 +1756,8 @@ internal_int_root_n :: proc(dest, src: ^Int, n: int, allocator := context.alloca
Number of rounds is at most log_2(root). If it is more it Number of rounds is at most log_2(root). If it is more it
got stuck, so break out of the loop and do the rest manually. got stuck, so break out of the loop and do the rest manually.
*/ */
if ilog2 -= 1; ilog2 == 0 { break; } if ilog2 -= 1; ilog2 == 0 { break; }
if internal_cmp(t1, t2) == 0 { break; } if internal_eq(t1, t2) { break; }
iterations += 1; iterations += 1;
if iterations == MAX_ITERATIONS_ROOT_N { if iterations == MAX_ITERATIONS_ROOT_N {
@@ -1796,7 +1795,7 @@ internal_int_root_n :: proc(dest, src: ^Int, n: int, allocator := context.alloca
for { for {
internal_pow(t2, t1, n) or_return; internal_pow(t2, t1, n) or_return;
if internal_cmp(t2, a) != 1 { break; } if internal_lt(t2, a) { break; }
internal_sub(t1, t1, DIGIT(1)) or_return; internal_sub(t1, t1, DIGIT(1)) or_return;
@@ -2001,12 +2000,12 @@ internal_int_inverse_modulo :: proc(dest, a, b: ^Int, allocator := context.alloc
/* /*
For all n in N and n > 0, n = 0 mod 1. For all n in N and n > 0, n = 0 mod 1.
*/ */
if internal_is_positive(a) && internal_cmp(b, 1) == 0 { return internal_zero(dest); } if internal_is_positive(a) && internal_eq(b, 1) { return internal_zero(dest); }
/* /*
`b` cannot be negative and has to be > 1 `b` cannot be negative and has to be > 1
*/ */
if internal_is_negative(b) && internal_cmp(b, 1) != 1 { return .Invalid_Argument; } if internal_is_negative(b) || internal_gt(b, 1) { return .Invalid_Argument; }
/* /*
If the modulus is odd we can use a faster routine instead. If the modulus is odd we can use a faster routine instead.
+1 -1
View File
@@ -163,7 +163,7 @@ internal_int_kronecker :: proc(a, p: ^Int, allocator := context.allocator) -> (k
for { for {
if internal_is_zero(a1) { if internal_is_zero(a1) {
if internal_cmp(p1, 1) == 0 { if internal_eq(p1, 1) {
return k, nil; return k, nil;
} else { } else {
return 0, nil; return 0, nil;
+23 -27
View File
@@ -1071,11 +1071,11 @@ _private_int_div_school :: proc(quotient, remainder, numerator, denominator: ^In
internal_shl_digit(y, n - t) or_return; internal_shl_digit(y, n - t) or_return;
c := internal_cmp(x, y); gte := internal_gte(x, y);
for c != -1 { for gte {
q.digit[n - t] += 1; q.digit[n - t] += 1;
internal_sub(x, x, y) or_return; internal_sub(x, x, y) or_return;
c = internal_cmp(x, y); gte = internal_gte(x, y);
} }
/* /*
@@ -1134,7 +1134,7 @@ _private_int_div_school :: proc(quotient, remainder, numerator, denominator: ^In
t2.digit[2] = x.digit[i]; t2.digit[2] = x.digit[i];
t2.used = 3; t2.used = 3;
if t1_t2 := internal_cmp_mag(t1, t2); t1_t2 != 1 { if internal_lte(t1, t2) {
break; break;
} }
iter += 1; if iter > 100 { iter += 1; if iter > 100 {
@@ -1227,15 +1227,13 @@ _private_div_recursion :: proc(quotient, remainder, a, b: ^Int, allocator := con
/* /*
While A1 < 0 do Q1 = Q1 - 1, A1 = A1 + (beta^k * B) While A1 < 0 do Q1 = Q1 - 1, A1 = A1 + (beta^k * B)
*/ */
if internal_cmp(A1, 0) == -1 { if internal_lt(A1, 0) {
internal_shl(t, b, k * _DIGIT_BITS) or_return; internal_shl(t, b, k * _DIGIT_BITS) or_return;
for { for {
internal_decr(Q1) or_return; internal_decr(Q1) or_return;
internal_add(A1, A1, t) or_return; internal_add(A1, A1, t) or_return;
if internal_cmp(A1, 0) != -1 { if internal_gte(A1, 0) { break; }
break;
}
} }
} }
@@ -1256,7 +1254,7 @@ _private_div_recursion :: proc(quotient, remainder, a, b: ^Int, allocator := con
/* /*
While A2 < 0 do Q0 = Q0 - 1, A2 = A2 + B. While A2 < 0 do Q0 = Q0 - 1, A2 = A2 + B.
*/ */
for internal_cmp(A2, 0) == -1 { for internal_is_negative(A2) { // internal_lt(A2, 0) {
internal_decr(Q0) or_return; internal_decr(Q0) or_return;
internal_add(A2, A2, b) or_return; internal_add(A2, A2, b) or_return;
} }
@@ -1391,7 +1389,7 @@ _private_int_div_small :: proc(quotient, remainder, numerator, denominator: ^Int
shl(tq, tq, n) or_return; shl(tq, tq, n) or_return;
for n >= 0 { for n >= 0 {
if c, _ = cmp_mag(ta, tb); c == 0 || c == 1 { if internal_gte(ta, tb) {
// ta -= tb // ta -= tb
sub(ta, ta, tb) or_return; sub(ta, ta, tb) or_return;
// q += tq // q += tq
@@ -1596,7 +1594,7 @@ _private_int_gcd_lcm :: proc(res_gcd, res_lcm, a, b: ^Int, allocator := context.
/* /*
Make sure `v` is the largest. Make sure `v` is the largest.
*/ */
if internal_cmp_mag(u, v) == 1 { if internal_gt(u, v) {
/* /*
Swap `u` and `v` to make sure `v` is >= `u`. Swap `u` and `v` to make sure `v` is >= `u`.
*/ */
@@ -1634,7 +1632,7 @@ _private_int_gcd_lcm :: proc(res_gcd, res_lcm, a, b: ^Int, allocator := context.
Computes least common multiple as `|a*b|/gcd(a,b)` Computes least common multiple as `|a*b|/gcd(a,b)`
Divide the smallest by the GCD. Divide the smallest by the GCD.
*/ */
if internal_cmp_mag(a, b) == -1 { if internal_lt_abs(a, b) {
/* /*
Store quotient in `t2` such that `t2 * b` is the LCM. Store quotient in `t2` such that `t2 * b` is the LCM.
*/ */
@@ -1694,9 +1692,7 @@ _private_int_log :: proc(a: ^Int, base: DIGIT, allocator := context.allocator) -
/* /*
Iterate until `a` is bracketed between low + high. Iterate until `a` is bracketed between low + high.
*/ */
if #force_inline internal_cmp(bracket_high, a) != -1 { if #force_inline internal_gte(bracket_high, a) { break; }
break;
}
low = high; low = high;
#force_inline internal_copy(bracket_low, bracket_high) or_return; #force_inline internal_copy(bracket_low, bracket_high) or_return;
@@ -1844,7 +1840,7 @@ _private_montgomery_reduce_comba :: proc(x, n: ^Int, rho: DIGIT, allocator := co
/* /*
if A >= m then A = A - m if A >= m then A = A - m
*/ */
if internal_cmp_mag(x, n) != -1 { if internal_gte_abs(x, n) {
return internal_sub(x, x, n); return internal_sub(x, x, n);
} }
return nil; return nil;
@@ -1932,7 +1928,7 @@ _private_int_montgomery_reduce :: proc(x, n: ^Int, rho: DIGIT, allocator := cont
/* /*
if x >= n then x = x - n if x >= n then x = x - n
*/ */
if internal_cmp_mag(x, n) != -1 { if internal_gte_abs(x, n) {
return internal_sub(x, x, n); return internal_sub(x, x, n);
} }
@@ -1969,7 +1965,7 @@ _private_int_montgomery_calc_normalization :: proc(a, b: ^Int, allocator := cont
*/ */
for x := bits - 1; x < _DIGIT_BITS; x += 1 { for x := bits - 1; x < _DIGIT_BITS; x += 1 {
internal_int_shl1(a, a) or_return; internal_int_shl1(a, a) or_return;
if internal_cmp_mag(a, b) != -1 { if internal_gte_abs(a, b) {
internal_sub(a, a, b) or_return; internal_sub(a, a, b) or_return;
} }
} }
@@ -2064,7 +2060,7 @@ _private_int_reduce :: proc(x, m, mu: ^Int, allocator := context.allocator) -> (
/* /*
If x < 0, add b**(k+1) to it. If x < 0, add b**(k+1) to it.
*/ */
if internal_cmp(x, 0) == -1 { if internal_is_negative(x) {
internal_set(q, 1) or_return; internal_set(q, 1) or_return;
internal_shl_digit(q, um + 1) or_return; internal_shl_digit(q, um + 1) or_return;
internal_add(x, x, q) or_return; internal_add(x, x, q) or_return;
@@ -2073,7 +2069,7 @@ _private_int_reduce :: proc(x, m, mu: ^Int, allocator := context.allocator) -> (
/* /*
Back off if it's too big. Back off if it's too big.
*/ */
for internal_cmp(x, m) != -1 { for internal_gte(x, m) {
internal_sub(x, x, m) or_return; internal_sub(x, x, m) or_return;
} }
@@ -2110,7 +2106,7 @@ _private_int_reduce_2k :: proc(a, n: ^Int, d: DIGIT, allocator := context.alloca
a = a + q a = a + q
*/ */
internal_add(a, a, q) or_return; internal_add(a, a, q) or_return;
if internal_cmp_mag(a, n) == -1 { break; } if internal_lt_abs(a, n) { break; }
internal_sub(a, a, n) or_return; internal_sub(a, a, n) or_return;
} }
@@ -2146,7 +2142,7 @@ _private_int_reduce_2k_l :: proc(a, n, d: ^Int, allocator := context.allocator)
a = a + q a = a + q
*/ */
internal_add(a, a, q) or_return; internal_add(a, a, q) or_return;
if internal_cmp_mag(a, n) == -1 { break; } if internal_lt_abs(a, n) { break; }
internal_sub(a, a, n) or_return; internal_sub(a, a, n) or_return;
} }
@@ -2359,7 +2355,7 @@ _private_int_dr_reduce :: proc(x, n: ^Int, k: DIGIT, allocator := context.alloca
If x >= n then subtract and reduce again. If x >= n then subtract and reduce again.
Each successive "recursion" makes the input smaller and smaller. Each successive "recursion" makes the input smaller and smaller.
*/ */
if internal_cmp_mag(x, n) == -1 { break; } if internal_lt_abs(x, n) { break; }
internal_sub(x, x, n) or_return; internal_sub(x, x, n) or_return;
} }
@@ -2985,21 +2981,21 @@ _private_inverse_modulo :: proc(dest, a, b: ^Int, allocator := context.allocator
/* /*
If `v` != `1` then there is no inverse. If `v` != `1` then there is no inverse.
*/ */
if internal_cmp(v, 1) != 0 { if !internal_eq(v, 1) {
return .Invalid_Argument; return .Invalid_Argument;
} }
/* /*
If its too low. If its too low.
*/ */
if internal_cmp(C, 0) == -1 { if internal_is_negative(C) {
internal_add(C, C, b) or_return; internal_add(C, C, b) or_return;
} }
/* /*
Too big. Too big.
*/ */
if internal_cmp(C, 0) != -1 { if internal_gte(C, 0) {
internal_sub(C, C, b) or_return; internal_sub(C, C, b) or_return;
} }
@@ -3152,7 +3148,7 @@ _private_inverse_modulo_odd :: proc(dest, a, b: ^Int, allocator := context.alloc
/* /*
Too big. Too big.
*/ */
for internal_cmp_mag(D, b) != -1 { for internal_gte_abs(D, b) {
internal_sub(D, D, b) or_return; internal_sub(D, D, b) or_return;
} }
-1
View File
@@ -413,7 +413,6 @@ def test_shr_signed(a = 0, bits = 0, expected_error = Error.Okay):
return test("test_shr_signed", res, [a, bits], expected_error, expected_result) return test("test_shr_signed", res, [a, bits], expected_error, expected_result)
def test_factorial(number = 0, expected_error = Error.Okay): def test_factorial(number = 0, expected_error = Error.Okay):
print("Factorial:", number)
args = [number] args = [number]
try: try:
res = int_factorial(*args) res = int_factorial(*args)