mirror of
https://github.com/Ed94/Odin.git
synced 2026-07-30 19:30:06 +00:00
big: Add Python implementation of LCM.
This commit is contained in:
@@ -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.
|
Store quotient in `t2` such that `t2 * a` is the LCM.
|
||||||
*/
|
*/
|
||||||
internal_div(res_lcm, a, temp_gcd_res) or_return
|
internal_div(res_lcm, b, temp_gcd_res) or_return
|
||||||
err = internal_mul(res_lcm, res_lcm, b)
|
err = internal_mul(res_lcm, res_lcm, a)
|
||||||
}
|
}
|
||||||
|
|
||||||
if res_gcd != nil {
|
if res_gcd != nil {
|
||||||
|
|||||||
+42
-17
@@ -236,24 +236,40 @@ def arg_to_odin(a):
|
|||||||
return s.encode('utf-8')
|
return s.encode('utf-8')
|
||||||
|
|
||||||
|
|
||||||
def integer_sqrt(src):
|
def big_integer_sqrt(src):
|
||||||
# The Python version on Github's CI doesn't offer math.isqrt.
|
# The Python version on Github's CI doesn't offer math.isqrt.
|
||||||
# We implement our own
|
# We implement our own
|
||||||
count = src.bit_length()
|
count = src.bit_length()
|
||||||
a, b = count >> 1, count & 1
|
a, b = count >> 1, count & 1
|
||||||
|
|
||||||
x = 1 << (a + b)
|
x = 1 << (a + b)
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
# y = (x + n // x) // 2
|
# y = (x + n // x) // 2
|
||||||
t1 = src // x
|
t1 = src // x
|
||||||
t2 = t1 + x
|
t2 = t1 + x
|
||||||
y = t2 >> 1
|
y = t2 >> 1
|
||||||
|
|
||||||
if y >= x:
|
if y >= x:
|
||||||
return x
|
return x
|
||||||
|
|
||||||
x, y = y, 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):
|
def test_add(a = 0, b = 0, expected_error = Error.Okay):
|
||||||
args = [arg_to_odin(a), arg_to_odin(b)]
|
args = [arg_to_odin(a), arg_to_odin(b)]
|
||||||
@@ -358,7 +374,7 @@ def test_sqrt(number = 0, expected_error = Error.Okay):
|
|||||||
if number < 0:
|
if number < 0:
|
||||||
expected_result = 0
|
expected_result = 0
|
||||||
else:
|
else:
|
||||||
expected_result = integer_sqrt(number)
|
expected_result = big_integer_sqrt(number)
|
||||||
return test("test_sqrt", res, [number], expected_error, expected_result)
|
return test("test_sqrt", res, [number], expected_error, expected_result)
|
||||||
|
|
||||||
def root_n(number, root):
|
def root_n(number, root):
|
||||||
@@ -461,7 +477,7 @@ def test_lcm(a = 0, b = 0, expected_error = Error.Okay):
|
|||||||
res = int_lcm(*args)
|
res = int_lcm(*args)
|
||||||
expected_result = None
|
expected_result = None
|
||||||
if expected_error == Error.Okay:
|
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)
|
return test("test_lcm", res, [a, b], expected_error, expected_result)
|
||||||
|
|
||||||
@@ -470,7 +486,7 @@ def test_is_square(a = 0, b = 0, expected_error = Error.Okay):
|
|||||||
res = is_square(*args)
|
res = is_square(*args)
|
||||||
expected_result = None
|
expected_result = None
|
||||||
if expected_error == Error.Okay:
|
if expected_error == Error.Okay:
|
||||||
expected_result = str(integer_sqrt(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)
|
return test("test_is_square", res, [a], expected_error, expected_result)
|
||||||
|
|
||||||
@@ -703,6 +719,15 @@ if __name__ == '__main__':
|
|||||||
b = randint(0, min(BITS, 120))
|
b = randint(0, min(BITS, 120))
|
||||||
elif test_proc == test_is_square:
|
elif test_proc == test_is_square:
|
||||||
a = randint(0, 1 << BITS)
|
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:
|
else:
|
||||||
b = randint(0, 1 << BITS)
|
b = randint(0, 1 << BITS)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user