Browse Source

big: Add workaround for DLL globals bug.

Jeroen van Rijn 4 years ago
parent
commit
0db86a0638

+ 6 - 6
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
+: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

+ 16 - 4
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`.

+ 6 - 6
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() {

+ 4 - 2
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 {

+ 3 - 1
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) {

+ 11 - 4
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:
 		#