Browse Source

Merge pull request #1363 from Kelimion/big_math

[math/big] Rename `internal_int_shl_digit` to `_private_int_shl_leg`.
Jeroen van Rijn 3 years ago
parent
commit
3257454209

+ 2 - 72
core/math/big/internal.odin

@@ -2648,7 +2648,7 @@ internal_int_shrmod :: proc(quotient, remainder, numerator: ^Int, bits: int, all
 		Shift by as many digits in the bit count.
 	*/
 	if bits >= _DIGIT_BITS {
-		internal_shr_digit(quotient, bits / _DIGIT_BITS) or_return
+		_private_int_shr_leg(quotient, bits / _DIGIT_BITS) or_return
 	}
 
 	/*
@@ -2687,37 +2687,6 @@ internal_int_shr :: proc(dest, source: ^Int, bits: int, allocator := context.all
 }
 internal_shr :: proc { internal_int_shr, }
 
-/*
-	Shift right by `digits` * _DIGIT_BITS bits.
-*/
-internal_int_shr_digit :: proc(quotient: ^Int, digits: int, allocator := context.allocator) -> (err: Error) {
-	context.allocator = allocator
-
-	if digits <= 0 { return nil }
-
-	/*
-		If digits > used simply zero and return.
-	*/
-	if digits > quotient.used { return internal_zero(quotient) }
-
-	/*
-		Much like `int_shl_digit`, this is implemented using a sliding window,
-		except the window goes the other way around.
-
-		b-2 | b-1 | b0 | b1 | b2 | ... | bb |   ---->
-					/\                   |      ---->
-					 \-------------------/      ---->
-	*/
-
-	#no_bounds_check for x := 0; x < (quotient.used - digits); x += 1 {
-		quotient.digit[x] = quotient.digit[x + digits]
-	}
-	quotient.used -= digits
-	internal_zero_unused(quotient)
-	return internal_clamp(quotient)
-}
-internal_shr_digit :: proc { internal_int_shr_digit, }
-
 /*
 	Shift right by a certain bit count with sign extension.
 */
@@ -2756,7 +2725,7 @@ internal_int_shl :: proc(dest, src: ^Int, bits: int, allocator := context.alloca
 		Shift by as many digits in the bit count as we have.
 	*/
 	if bits >= _DIGIT_BITS {
-		internal_shl_digit(dest, bits / _DIGIT_BITS) or_return
+		_private_int_shl_leg(dest, bits / _DIGIT_BITS) or_return
 	}
 
 	/*
@@ -2786,45 +2755,6 @@ internal_int_shl :: proc(dest, src: ^Int, bits: int, allocator := context.alloca
 }
 internal_shl :: proc { internal_int_shl, }
 
-
-/*
-	Shift left by `digits` * _DIGIT_BITS bits.
-*/
-internal_int_shl_digit :: proc(quotient: ^Int, digits: int, allocator := context.allocator) -> (err: Error) {
-	context.allocator = allocator
-
-	if digits <= 0 { return nil }
-
-	/*
-		No need to shift a zero.
-	*/
-	if #force_inline internal_is_zero(quotient) {
-		return nil
-	}
-
-	/*
-		Resize `quotient` to accomodate extra digits.
-	*/
-	#force_inline internal_grow(quotient, quotient.used + digits) or_return
-
-	/*
-		Increment the used by the shift amount then copy upwards.
-	*/
-
-	/*
-		Much like `int_shr_digit`, this is implemented using a sliding window,
-		except the window goes the other way around.
-	*/
-	#no_bounds_check for x := quotient.used; x > 0; x -= 1 {
-		quotient.digit[x+digits-1] = quotient.digit[x-1]
-	}
-
-	quotient.used += digits
-	mem.zero_slice(quotient.digit[:digits])
-	return nil
-}
-internal_shl_digit :: proc { internal_int_shl_digit, }
-
 /*
 	Count bits in an `Int`.
 	Assumes `a` not to be `nil` and to have been initialized.

+ 1 - 32
core/math/big/logical.odin

@@ -86,21 +86,6 @@ int_shr :: proc(dest, source: ^Int, bits: int, allocator := context.allocator) -
 }
 shr :: proc { int_shr, }
 
-/*
-	Shift right by `digits` * _DIGIT_BITS bits.
-*/
-int_shr_digit :: proc(quotient: ^Int, digits: int, allocator := context.allocator) -> (err: Error) {
-	/*
-		Check that `quotient` is usable.
-	*/
-	assert_if_nil(quotient)
-	context.allocator = allocator
-
-	internal_clear_if_uninitialized(quotient) or_return
-	return #force_inline internal_int_shr_digit(quotient, digits)
-}
-shr_digit :: proc { int_shr_digit, }
-
 /*
 	Shift right by a certain bit count with sign extension.
 */
@@ -124,20 +109,4 @@ int_shl :: proc(dest, src: ^Int, bits: int, allocator := context.allocator) -> (
 	internal_clear_if_uninitialized(dest, src) or_return
 	return #force_inline internal_int_shl(dest, src, bits)
 }
-shl :: proc { int_shl, }
-
-
-/*
-	Shift left by `digits` * _DIGIT_BITS bits.
-*/
-int_shl_digit :: proc(quotient: ^Int, digits: int, allocator := context.allocator) -> (err: Error) {
-	/*
-		Check that `quotient` is usable.
-	*/
-	assert_if_nil(quotient)
-	context.allocator = allocator
-
-	internal_clear_if_uninitialized(quotient) or_return
-	return #force_inline internal_int_shl_digit(quotient, digits)
-}
-shl_digit :: proc { int_shl_digit, };
+shl :: proc { int_shl, }

+ 93 - 25
core/math/big/private.odin

@@ -211,12 +211,12 @@ _private_int_mul_toom :: proc(dest, a, b: ^Int, allocator := context.allocator)
 	/*
 		P = b1*x^4+ S2*x^3+ S1*x^2+ a1*x + a0;
 	*/
-	internal_shl_digit(b1, 4 * B)               or_return
-	internal_shl_digit(S2, 3 * B)               or_return
+	_private_int_shl_leg(b1, 4 * B)             or_return
+	_private_int_shl_leg(S2, 3 * B)             or_return
 	internal_add(b1, b1, S2)                    or_return
-	internal_shl_digit(S1, 2 * B)               or_return
+	_private_int_shl_leg(S1, 2 * B)             or_return
 	internal_add(b1, b1, S1)                    or_return
-	internal_shl_digit(a1, 1 * B)               or_return
+	_private_int_shl_leg(a1, 1 * B)             or_return
 	internal_add(b1, b1, a1)                    or_return
 	internal_add(dest, b1, a0)                  or_return
 
@@ -317,8 +317,8 @@ _private_int_mul_karatsuba :: proc(dest, a, b: ^Int, allocator := context.alloca
 	/*
 		shift by B.
 	*/
-	internal_shl_digit(t1, B)       or_return /* t1 = (x0y0 + x1y1 - (x1-x0)*(y1-y0))<<B */
-	internal_shl_digit(x1y1, B * 2) or_return /* x1y1 = x1y1 << 2*B */
+	_private_int_shl_leg(t1, B)       or_return /* t1 = (x0y0 + x1y1 - (x1-x0)*(y1-y0))<<B */
+	_private_int_shl_leg(x1y1, B * 2) or_return /* x1y1 = x1y1 << 2*B */
 
 	internal_add(t1, x0y0, t1)      or_return /* t1 = x0y0 + t1 */
 	internal_add(dest, t1, x1y1)    or_return /* t1 = x0y0 + t1 + x1y1 */
@@ -588,7 +588,7 @@ _private_int_mul_balance :: proc(dest, a, b: ^Int, allocator := context.allocato
 		/*
 			Shift `tmp` to the correct position.
 		*/
-		internal_shl_digit(tmp, b_size * i)                          or_return
+		_private_int_shl_leg(tmp, b_size * i)                          or_return
 
 		/*
 			Add to output. No carry needed.
@@ -606,7 +606,7 @@ _private_int_mul_balance :: proc(dest, a, b: ^Int, allocator := context.allocato
 		internal_clamp(a0)
 
 		internal_mul(tmp, a0, b)                                     or_return
-		internal_shl_digit(tmp, b_size * i)                          or_return
+		_private_int_shl_leg(tmp, b_size * i)                          or_return
 		internal_add(r, r, tmp)                                      or_return
 	}
 
@@ -840,8 +840,8 @@ _private_int_sqr_karatsuba :: proc(dest, src: ^Int, allocator := context.allocat
 	/*
 		Shift by B.
 	*/
-	internal_shl_digit(t1, B) or_return
-	internal_shl_digit(x1x1, B * 2) or_return
+	_private_int_shl_leg(t1, B) or_return
+	_private_int_shl_leg(x1x1, B * 2) or_return
 	internal_add(t1, t1, x0x0) or_return
 	internal_add(dest, t1, x1x1) or_return
 
@@ -942,10 +942,10 @@ _private_int_sqr_toom :: proc(dest, src: ^Int, allocator := context.allocator) -
 	internal_sub(dest, dest, S0) or_return
 	/** \\P = S4*x^4 + S3*x^3 + S2*x^2 + S1*x + S0; */
 	/** P = a2*x^4 + a1*x^3 + b*x^2 + a0*x + S0; */
-	internal_shl_digit(  a2, 4 * B) or_return
-	internal_shl_digit(  a1, 3 * B) or_return
-	internal_shl_digit(dest, 2 * B) or_return
-	internal_shl_digit(  a0, 1 * B) or_return
+	_private_int_shl_leg(  a2, 4 * B) or_return
+	_private_int_shl_leg(  a1, 3 * B) or_return
+	_private_int_shl_leg(dest, 2 * B) or_return
+	_private_int_shl_leg(  a0, 1 * B) or_return
 
 	internal_add(a2, a2, a1) or_return
 	internal_add(dest, dest, a2) or_return
@@ -1069,7 +1069,7 @@ _private_int_div_school :: proc(quotient, remainder, numerator, denominator: ^In
 		y = y*b**{n-t}
 	*/
 
-	internal_shl_digit(y, n - t) or_return
+	_private_int_shl_leg(y, n - t) or_return
 
 	gte := internal_gte(x, y)
 	for gte {
@@ -1081,7 +1081,7 @@ _private_int_div_school :: proc(quotient, remainder, numerator, denominator: ^In
 	/*
 		Reset y by shifting it back down.
 	*/
-	internal_shr_digit(y, n - t)
+	_private_int_shr_leg(y, n - t)
 
 	/*
 		Step 3. for i from n down to (t + 1).
@@ -1146,7 +1146,7 @@ _private_int_div_school :: proc(quotient, remainder, numerator, denominator: ^In
 			Step 3.3 x = x - q{i-t-1} * y * b**{i-t-1}
 		*/
 		int_mul_digit(t1, y, q.digit[(i - t) - 1]) or_return
-		internal_shl_digit(t1, (i - t) - 1) or_return
+		_private_int_shl_leg(t1, (i - t) - 1) or_return
 		internal_sub(x, x, t1) or_return
 
 		/*
@@ -1154,7 +1154,7 @@ _private_int_div_school :: proc(quotient, remainder, numerator, denominator: ^In
 		*/
 		if x.sign == .Negative {
 			internal_copy(t1, y) or_return
-			internal_shl_digit(t1, (i - t) - 1) or_return
+			_private_int_shl_leg(t1, (i - t) - 1) or_return
 			internal_add(x, x, t1) or_return
 
 			q.digit[(i - t) - 1] = (q.digit[(i - t) - 1] - 1) & _MASK
@@ -1220,7 +1220,7 @@ _private_div_recursion :: proc(quotient, remainder, a, b: ^Int, allocator := con
 	/*
 		A1 = (R1 * beta^(2k)) + (A % beta^(2k)) - (Q1 * B0 * beta^k)
 	*/
-	internal_shl_digit(R1, 2 * k) or_return
+	_private_int_shl_leg(R1, 2 * k) or_return
 	internal_add(A1, R1, t) or_return
 	internal_mul(t, Q1, B0) or_return
 
@@ -1246,7 +1246,7 @@ _private_div_recursion :: proc(quotient, remainder, a, b: ^Int, allocator := con
 	/*
 		A2 = (R0*beta^k) +  (A1 % beta^k) - (Q0*B0)
 	*/
-	internal_shl_digit(R0, k) or_return
+	_private_int_shl_leg(R0, k) or_return
 	internal_add(A2, R0, t) or_return
 	internal_mul(t, Q0, B0) or_return
 	internal_sub(A2, A2, t) or_return
@@ -1262,7 +1262,7 @@ _private_div_recursion :: proc(quotient, remainder, a, b: ^Int, allocator := con
 	/*
 		Return q = (Q1*beta^k) + Q0, r = A2.
 	*/
-	internal_shl_digit(Q1, k) or_return
+	_private_int_shl_leg(Q1, k) or_return
 	internal_add(quotient, Q1, Q0) or_return
 
 	return internal_copy(remainder, A2)
@@ -1923,7 +1923,7 @@ _private_int_montgomery_reduce :: proc(x, n: ^Int, rho: DIGIT, allocator := cont
 		x = x/b**n.used.
 	*/
 	internal_clamp(x)
-	internal_shr_digit(x, n.used)
+	_private_int_shr_leg(x, n.used)
 
 	/*
 		if x >= n then x = x - n
@@ -2026,7 +2026,7 @@ _private_int_reduce :: proc(x, m, mu: ^Int, allocator := context.allocator) -> (
 	/*
 		q1 = x / b**(k-1)
 	*/
-	internal_shr_digit(q, um - 1)
+	_private_int_shr_leg(q, um - 1)
 
 	/*
 		According to HAC this optimization is ok.
@@ -2040,7 +2040,7 @@ _private_int_reduce :: proc(x, m, mu: ^Int, allocator := context.allocator) -> (
 	/*
 		q3 = q2 / b**(k+1)
 	*/
-	internal_shr_digit(q, um + 1)
+	_private_int_shr_leg(q, um + 1)
 
 	/*
 		x = x mod b**(k+1), quick (no division)
@@ -2062,7 +2062,7 @@ _private_int_reduce :: proc(x, m, mu: ^Int, allocator := context.allocator) -> (
 	*/
 	if internal_is_negative(x) {
 		internal_set(q, 1)                                           or_return
-		internal_shl_digit(q, um + 1)                                or_return
+		_private_int_shl_leg(q, um + 1)                                or_return
 		internal_add(x, x, q)                                        or_return
 	}
 
@@ -3192,6 +3192,74 @@ _private_copy_digits :: proc(dest, src: ^Int, digits: int, offset := int(0)) ->
 	return nil
 }
 
+
+/*
+	Shift left by `digits` * _DIGIT_BITS bits.
+*/
+_private_int_shl_leg :: proc(quotient: ^Int, digits: int, allocator := context.allocator) -> (err: Error) {
+	context.allocator = allocator
+
+	if digits <= 0 { return nil }
+
+	/*
+		No need to shift a zero.
+	*/
+	if #force_inline internal_is_zero(quotient) {
+		return nil
+	}
+
+	/*
+		Resize `quotient` to accomodate extra digits.
+	*/
+	#force_inline internal_grow(quotient, quotient.used + digits) or_return
+
+	/*
+		Increment the used by the shift amount then copy upwards.
+	*/
+
+	/*
+		Much like `_private_int_shr_leg`, this is implemented using a sliding window,
+		except the window goes the other way around.
+	*/
+	#no_bounds_check for x := quotient.used; x > 0; x -= 1 {
+		quotient.digit[x+digits-1] = quotient.digit[x-1]
+	}
+
+	quotient.used += digits
+	mem.zero_slice(quotient.digit[:digits])
+	return nil
+}
+
+/*
+	Shift right by `digits` * _DIGIT_BITS bits.
+*/
+_private_int_shr_leg :: proc(quotient: ^Int, digits: int, allocator := context.allocator) -> (err: Error) {
+	context.allocator = allocator
+
+	if digits <= 0 { return nil }
+
+	/*
+		If digits > used simply zero and return.
+	*/
+	if digits > quotient.used { return internal_zero(quotient) }
+
+	/*
+		Much like `int_shl_digit`, this is implemented using a sliding window,
+		except the window goes the other way around.
+
+		b-2 | b-1 | b0 | b1 | b2 | ... | bb |   ---->
+					/\                   |      ---->
+					 \-------------------/      ---->
+	*/
+
+	#no_bounds_check for x := 0; x < (quotient.used - digits); x += 1 {
+		quotient.digit[x] = quotient.digit[x + digits]
+	}
+	quotient.used -= digits
+	internal_zero_unused(quotient)
+	return internal_clamp(quotient)
+}
+
 /*	
 	========================    End of private procedures    =======================
 

+ 4 - 4
tests/core/math/big/test.odin

@@ -208,7 +208,7 @@ print_to_buffer :: proc(val: ^big.Int) -> cstring {
 /*
 	dest = shr_digit(src, digits)
 */
-@export test_shr_digit :: proc "c" (source: cstring, digits: int) -> (res: PyRes) {
+@export test_shr_leg :: proc "c" (source: cstring, digits: int) -> (res: PyRes) {
 	context = runtime.default_context()
 	err: big.Error
 
@@ -216,7 +216,7 @@ print_to_buffer :: proc(val: ^big.Int) -> cstring {
 	defer big.internal_destroy(src)
 
 	if err = big.atoi(src, string(source), 16); err != nil { return PyRes{res=":shr_digit:atoi(src):", err=err} }
-	if err = #force_inline big.internal_shr_digit(src, digits); err != nil { return PyRes{res=":shr_digit:shr_digit(src):", err=err} }
+	if err = #force_inline big._private_int_shr_leg(src, digits); err != nil { return PyRes{res=":shr_digit:shr_digit(src):", err=err} }
 
 	r := print_to_buffer(src)
 	return PyRes{res = r, err = nil}
@@ -225,7 +225,7 @@ print_to_buffer :: proc(val: ^big.Int) -> cstring {
 /*
 	dest = shl_digit(src, digits)
 */
-@export test_shl_digit :: proc "c" (source: cstring, digits: int) -> (res: PyRes) {
+@export test_shl_leg :: proc "c" (source: cstring, digits: int) -> (res: PyRes) {
 	context = runtime.default_context()
 	err: big.Error
 
@@ -233,7 +233,7 @@ print_to_buffer :: proc(val: ^big.Int) -> cstring {
 	defer big.internal_destroy(src)
 
 	if err = big.atoi(src, string(source), 16); err != nil { return PyRes{res=":shl_digit:atoi(src):", err=err} }
-	if err = #force_inline big.internal_shl_digit(src, digits); err != nil { return PyRes{res=":shl_digit:shr_digit(src):", err=err} }
+	if err = #force_inline big._private_int_shl_leg(src, digits); err != nil { return PyRes{res=":shl_digit:shr_digit(src):", err=err} }
 
 	r := print_to_buffer(src)
 	return PyRes{res = r, err = nil}

+ 16 - 16
tests/core/math/big/test.py

@@ -187,8 +187,8 @@ int_sqrt   =     load(l.test_sqrt,       [c_char_p            ], Res)
 int_root_n =     load(l.test_root_n,     [c_char_p, c_longlong], Res)
 
 # Logical operations
-int_shl_digit  = load(l.test_shl_digit,  [c_char_p, c_longlong], Res)
-int_shr_digit  = load(l.test_shr_digit,  [c_char_p, c_longlong], Res)
+int_shl_leg    = load(l.test_shl_leg,    [c_char_p, c_longlong], Res)
+int_shr_leg    = load(l.test_shr_leg,    [c_char_p, c_longlong], Res)
 int_shl        = load(l.test_shl,        [c_char_p, c_longlong], Res)
 int_shr        = load(l.test_shr,        [c_char_p, c_longlong], Res)
 int_shr_signed = load(l.test_shr_signed, [c_char_p, c_longlong], Res)
@@ -402,17 +402,17 @@ def test_root_n(number = 0, root = 0, expected_error = Error.Okay):
 
 	return test("test_root_n", res, [number, root], expected_error, expected_result)
 
-def test_shl_digit(a = 0, digits = 0, expected_error = Error.Okay):
+def test_shl_leg(a = 0, digits = 0, expected_error = Error.Okay):
 	args  = [arg_to_odin(a), digits]
-	res   = int_shl_digit(*args)
+	res   = int_shl_leg(*args)
 	expected_result = None
 	if expected_error == Error.Okay:
 		expected_result = a << (digits * 60)
-	return test("test_shl_digit", res, [a, digits], expected_error, expected_result)
+	return test("test_shl_leg", res, [a, digits], expected_error, expected_result)
 
-def test_shr_digit(a = 0, digits = 0, expected_error = Error.Okay):
+def test_shr_leg(a = 0, digits = 0, expected_error = Error.Okay):
 	args  = [arg_to_odin(a), digits]
-	res   = int_shr_digit(*args)
+	res   = int_shr_leg(*args)
 	expected_result = None
 	if expected_error == Error.Okay:
 		if a < 0:
@@ -421,7 +421,7 @@ def test_shr_digit(a = 0, digits = 0, expected_error = Error.Okay):
 		else:
 			expected_result = a >> (digits * 60)
 		
-	return test("test_shr_digit", res, [a, digits], expected_error, expected_result)
+	return test("test_shr_leg", res, [a, digits], expected_error, expected_result)
 
 def test_shl(a = 0, bits = 0, expected_error = Error.Okay):
 	args  = [arg_to_odin(a), bits]
@@ -556,12 +556,12 @@ TESTS = {
 	test_root_n: [
 		[  1298074214633706907132624082305024, 2, Error.Okay, ],	
 	],
-	test_shl_digit: [
+	test_shl_leg: [
 		[ 3192,			1 ],
 		[ 1298074214633706907132624082305024, 2 ],
 		[ 1024,			3 ],
 	],
-	test_shr_digit: [
+	test_shr_leg: [
 		[ 3680125442705055547392, 1 ],
 		[ 1725436586697640946858688965569256363112777243042596638790631055949824, 2 ],
 		[ 219504133884436710204395031992179571, 2 ],
@@ -619,10 +619,10 @@ total_failures = 0
 # test_shr_signed also tests shr, so we're not going to test shr randomly.
 #
 RANDOM_TESTS = [
-	test_add, test_sub, test_mul, test_sqr, test_div,
-	test_log, test_pow, test_sqrt, test_root_n,
-	test_shl_digit, test_shr_digit, test_shl, test_shr_signed,
-	test_gcd, test_lcm, test_is_square,
+	test_add,     test_sub,     test_mul,       test_sqr,
+	test_log,     test_pow,     test_sqrt,      test_root_n,
+	test_shl_leg, test_shr_leg, test_shl,       test_shr_signed,
+	test_gcd,     test_lcm,     test_is_square, test_div,
 ]
 SKIP_LARGE   = [
 	test_pow, test_root_n, # test_gcd,
@@ -719,9 +719,9 @@ if __name__ == '__main__':
 					a = randint(1, 1 << BITS)
 					b = TEST_ROOT_N_PARAMS[index]
 					index = (index + 1) % len(TEST_ROOT_N_PARAMS)
-				elif test_proc == test_shl_digit:
+				elif test_proc == test_shl_leg:
 					b = randint(0, 10);
-				elif test_proc == test_shr_digit:
+				elif test_proc == test_shr_leg:
 					a = abs(a)
 					b = randint(0, 10);
 				elif test_proc == test_shl: