Browse Source

Merge pull request #1132 from Kelimion/bigint

big: Run tests under CI.
Jeroen van Rijn 4 years ago
parent
commit
aa5b1c9c97

+ 8 - 1
.github/workflows/ci.yml

@@ -64,5 +64,12 @@ jobs:
           call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat
           odin run examples/demo/demo.odin
         timeout-minutes: 10
-
+      - name: core:math/big tests
+        shell: cmd
+        run: |
+          call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat
+          cd core\math\big\tests
+          python3 --version
+          call build.bat
+        timeout-minutes: 10
 

+ 2 - 2
core/math/big/private.odin

@@ -1642,8 +1642,8 @@ _private_int_gcd_lcm :: proc(res_gcd, res_lcm, a, b: ^Int, allocator := context.
 		/*
 			Store quotient in `t2` such that `t2 * a` is the LCM.
 		*/
-		internal_div(res_lcm, a, temp_gcd_res) or_return
-		err = internal_mul(res_lcm, res_lcm, b)
+		internal_div(res_lcm, b, temp_gcd_res) or_return
+		err = internal_mul(res_lcm, res_lcm, a)
 	}
 
 	if res_gcd != nil {

+ 4 - 3
core/math/big/tests/build.bat

@@ -3,6 +3,7 @@ set TEST_ARGS=-fast-tests
 set TEST_ARGS=
 set OUT_NAME=test_library
 set COMMON=-build-mode:shared -show-timings -no-bounds-check -define:MATH_BIG_EXE=false -vet -strict-style
-:odin build . %COMMON% -o:minimal -out:%OUT_NAME% && python test.py %TEST_ARGS%
-odin build . %COMMON% -o:size    -out:%OUT_NAME% && python test.py %TEST_ARGS%
-:odin build . %COMMON% -o:speed   -out:%OUT_NAME% && python test.py %TEST_ARGS%
+set PATH_TO_ODIN==..\..\..\..\odin
+:%PATH_TO_ODIN% build . %COMMON% -o:minimal -out:%OUT_NAME% && python3 test.py %TEST_ARGS%
+:%PATH_TO_ODIN% build . %COMMON% -o:size    -out:%OUT_NAME% && python3 test.py %TEST_ARGS%
+%PATH_TO_ODIN% build . %COMMON% -o:speed   -out:%OUT_NAME% && python3 test.py %TEST_ARGS%

+ 48 - 3
core/math/big/tests/test.py

@@ -235,6 +235,42 @@ def arg_to_odin(a):
 		s = '-' + hex(a)[3:]
 	return s.encode('utf-8')
 
+
+def big_integer_sqrt(src):
+	# The Python version on Github's CI doesn't offer math.isqrt.
+	# We implement our own
+	count = src.bit_length()
+	a, b = count >> 1, count & 1
+
+	x = 1 << (a + b)
+
+	while True:
+		# y = (x + n // x) // 2
+		t1 = src // x
+		t2 = t1  + x
+		y = t2 >> 1
+
+		if y >= x:
+			return x
+
+		x, y = y, x
+
+def big_integer_lcm(a, b):
+	# Computes least common multiple as `|a*b|/gcd(a,b)`
+	# Divide the smallest by the GCD.
+
+	if a == 0 or b == 0:
+		return 0
+
+	if abs(a) < abs(b):
+		# Store quotient in `t2` such that `t2 * b` is the LCM.
+		lcm = a // math.gcd(a, b)
+		return abs(b * lcm)
+	else:
+		# Store quotient in `t2` such that `t2 * a` is the LCM.
+		lcm = b // math.gcd(a, b)
+		return abs(a * lcm)
+
 def test_add(a = 0, b = 0, expected_error = Error.Okay):
 	args = [arg_to_odin(a), arg_to_odin(b)]
 	res  = add(*args)
@@ -338,7 +374,7 @@ def test_sqrt(number = 0, expected_error = Error.Okay):
 		if number < 0:
 			expected_result = 0
 		else:
-			expected_result = int(math.isqrt(number))
+			expected_result = big_integer_sqrt(number)
 	return test("test_sqrt", res, [number], expected_error, expected_result)
 
 def root_n(number, root):
@@ -441,7 +477,7 @@ def test_lcm(a = 0, b = 0, expected_error = Error.Okay):
 	res   = int_lcm(*args)
 	expected_result = None
 	if expected_error == Error.Okay:
-		expected_result = math.lcm(a, b)
+		expected_result = big_integer_lcm(a, b)
 		
 	return test("test_lcm", res, [a, b], expected_error, expected_result)
 
@@ -450,7 +486,7 @@ def test_is_square(a = 0, b = 0, expected_error = Error.Okay):
 	res   = is_square(*args)
 	expected_result = None
 	if expected_error == Error.Okay:
-		expected_result = str(math.isqrt(a) ** 2 == a) if a > 0 else "False"
+		expected_result = str(big_integer_sqrt(a) ** 2 == a) if a > 0 else "False"
 		
 	return test("test_is_square", res, [a], expected_error, expected_result)
 
@@ -683,6 +719,15 @@ if __name__ == '__main__':
 					b = randint(0, min(BITS, 120))
 				elif test_proc == test_is_square:
 					a = randint(0, 1 << BITS)
+				elif test_proc == test_lcm:
+					smallest = min(a, b)
+					biggest  = max(a, b)
+
+					# Randomly swap biggest and smallest
+					if randint(1, 11) % 2 == 0:
+						smallest, biggest = biggest, smallest
+
+					a, b = smallest, biggest
 				else:
 					b = randint(0, 1 << BITS)