diff --git a/core/math/big/build.bat b/core/math/big/build.bat index b1ff7303a..eb6f581aa 100644 --- a/core/math/big/build.bat +++ b/core/math/big/build.bat @@ -1,8 +1,8 @@ @echo off -odin run . -vet +:odin run . -vet : -o:size -:odin build . -build-mode:shared -show-timings -o:minimal -no-bounds-check && python test.py -fast-tests -:odin build . -build-mode:shared -show-timings -o:size -no-bounds-check && python test.py -fast-tests -:odin build . -build-mode:shared -show-timings -o:size && python test.py -fast-tests -:odin build . -build-mode:shared -show-timings -o:speed -no-bounds-check && python test.py -fast-tests -:odin build . -build-mode:shared -show-timings -o:speed && python test.py -fast-tests \ No newline at end of file +:odin build . -build-mode:shared -show-timings -o:minimal -no-bounds-check -define:MATH_BIG_EXE=false && python test.py -fast-tests +:odin build . -build-mode:shared -show-timings -o:size -no-bounds-check -define:MATH_BIG_EXE=false && python test.py -fast-tests +:odin build . -build-mode:shared -show-timings -o:size -define:MATH_BIG_EXE=false && python test.py -fast-tests +odin build . -build-mode:shared -show-timings -o:speed -no-bounds-check -define:MATH_BIG_EXE=false && python test.py -fast-tests +:odin build . -build-mode:shared -show-timings -o:speed -define:MATH_BIG_EXE=false && python test.py -fast-tests \ No newline at end of file diff --git a/core/math/big/common.odin b/core/math/big/common.odin index 5e2fe4d8c..57fa32c9d 100644 --- a/core/math/big/common.odin +++ b/core/math/big/common.odin @@ -27,10 +27,22 @@ import "core:intrinsics" `initialize_constants` also replaces the other `_DEFAULT_*` cutoffs with custom compile-time values if so `#config`ured. */ -MUL_KARATSUBA_CUTOFF := initialize_constants(); -SQR_KARATSUBA_CUTOFF := _DEFAULT_SQR_KARATSUBA_CUTOFF; -MUL_TOOM_CUTOFF := _DEFAULT_MUL_TOOM_CUTOFF; -SQR_TOOM_CUTOFF := _DEFAULT_SQR_TOOM_CUTOFF; + +/* + There is a bug with DLL globals. They don't get set. + To allow tests to run we add `-define:MATH_BIG_EXE=false` to hardcode the cutoffs for now. +*/ +when #config(MATH_BIG_EXE, true) { + MUL_KARATSUBA_CUTOFF := initialize_constants(); + SQR_KARATSUBA_CUTOFF := _DEFAULT_SQR_KARATSUBA_CUTOFF; + MUL_TOOM_CUTOFF := _DEFAULT_MUL_TOOM_CUTOFF; + SQR_TOOM_CUTOFF := _DEFAULT_SQR_TOOM_CUTOFF; +} else { + MUL_KARATSUBA_CUTOFF := _DEFAULT_MUL_KARATSUBA_CUTOFF; + SQR_KARATSUBA_CUTOFF := _DEFAULT_SQR_KARATSUBA_CUTOFF; + MUL_TOOM_CUTOFF := _DEFAULT_MUL_TOOM_CUTOFF; + SQR_TOOM_CUTOFF := _DEFAULT_SQR_TOOM_CUTOFF; +} /* These defaults were tuned on an AMD A8-6600K (64-bit) using libTomMath's `make tune`. diff --git a/core/math/big/example.odin b/core/math/big/example.odin index 986580f7f..4fbf44664 100644 --- a/core/math/big/example.odin +++ b/core/math/big/example.odin @@ -206,16 +206,16 @@ demo :: proc() { a, b, c, d, e, f := &Int{}, &Int{}, &Int{}, &Int{}, &Int{}, &Int{}; defer destroy(a, b, c, d, e, f); - power_of_two(a, 14_500); - print("a: ", a); + atoi(a, "12980742146337069150589594264770969721", 10); + print("a: ", a, 10, true, true, true); + atoi(b, "4611686018427387904", 10); + print("b: ", b, 10, true, true, true); - power_of_two(b, 10_500); - - if err := internal_int_divmod(c, d, a, b); err != nil { + if err := internal_divmod(c, d, a, b); err != nil { fmt.printf("Error: %v\n", err); } print("c: ", c); - print("d: ", d); + print("c: ", d); } main :: proc() { diff --git a/core/math/big/internal.odin b/core/math/big/internal.odin index 506c5b683..ba6b04f43 100644 --- a/core/math/big/internal.odin +++ b/core/math/big/internal.odin @@ -36,6 +36,8 @@ import "core:mem" import "core:intrinsics" import rnd "core:math/rand" +import "core:fmt" + /* Low-level addition, unsigned. Handbook of Applied Cryptography, algorithm 14.7. @@ -714,7 +716,6 @@ internal_sqr :: proc (dest, src: ^Int, allocator := context.allocator) -> (res: */ internal_int_divmod :: proc(quotient, remainder, numerator, denominator: ^Int, allocator := context.allocator) -> (err: Error) { context.allocator = allocator; - if denominator.used == 0 { return .Division_by_Zero; } /* If numerator < denominator then quotient = 0, remainder = numerator. @@ -729,7 +730,8 @@ internal_int_divmod :: proc(quotient, remainder, numerator, denominator: ^Int, a return nil; } - 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."); err = _private_int_div_recursive(quotient, remainder, numerator, denominator); // err = #force_inline _private_int_div_school(quotient, remainder, numerator, denominator); } else { diff --git a/core/math/big/test.odin b/core/math/big/test.odin index 2846dac6d..64d822ee1 100644 --- a/core/math/big/test.odin +++ b/core/math/big/test.odin @@ -26,7 +26,9 @@ PyRes :: struct { @export test_initialize_constants :: proc "c" () -> (res: u64) { context = runtime.default_context(); - return u64(initialize_constants()); + res = u64(initialize_constants()); + //assert(MUL_KARATSUBA_CUTOFF >= 40); + return res; } @export test_error_string :: proc "c" (err: Error) -> (res: cstring) { diff --git a/core/math/big/test.py b/core/math/big/test.py index f9398389c..5b5a86cff 100644 --- a/core/math/big/test.py +++ b/core/math/big/test.py @@ -66,6 +66,8 @@ timed_or_fast.add_argument( args = parser.parse_args() +EXIT_ON_FAIL = args.exit_on_fail + # # How many iterations of each random test do we want to run? # @@ -153,7 +155,7 @@ class Res(Structure): _fields_ = [("res", c_char_p), ("err", c_uint64)] initialize_constants = load(l.test_initialize_constants, [], c_uint64) -initialize_constants() +print("initialize_constants: ", initialize_constants()) error_string = load(l.test_error_string, [c_byte], c_char_p) @@ -211,7 +213,7 @@ def test(test_name: "", res: Res, param=[], expected_error = Error.Okay, expecte print(error, flush=True) passed = False - if args.exit_on_fail and not passed: exit(res.err) + if EXIT_ON_FAIL and not passed: exit(res.err) return passed @@ -257,7 +259,7 @@ def test_sqr(a = 0, b = 0, expected_error = Error.Okay): try: res = sqr(*args) except OSError as e: - print("{} while trying to square {} x {}.".format(e, a)) + print("{} while trying to square {}.".format(e, a)) if EXIT_ON_FAIL: exit(3) return False @@ -268,7 +270,12 @@ def test_sqr(a = 0, b = 0, expected_error = Error.Okay): def test_div(a = 0, b = 0, expected_error = Error.Okay): args = [arg_to_odin(a), arg_to_odin(b)] - res = div(*args) + try: + res = div(*args) + except OSError as e: + print("{} while trying divide to {} / {}.".format(e, a, b)) + if EXIT_ON_FAIL: exit(3) + return False expected_result = None if expected_error == Error.Okay: #