Skip to content

Implemented math.factorial(n) for calculating very large factorials with speed and accuracy. #2557

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 8 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
191 changes: 162 additions & 29 deletions src/runtime/math.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,36 +15,170 @@ def modf(x: f64) -> tuple[f64, f64]:
"""
return (x - f64(int(x)), float(int(x)))

@overload
def factorial(x: i32) -> i32:
"""
Computes the factorial of `x`.
"""

result: i32
result = 0
if x < 0:
return result
result = 1
i: i32
for i in range(1, x+1):
result *= i
return result

@overload
def factorial(x: i64) -> i64:
"""
Computes the factorial of `x`.
"""
result: i64
result = i64(0)
if x < i64(0):
return result
result = i64(1)
i: i64
for i in range(i64(1), x + i64(1)):
result *= i64(i)
return result
def factorial(n: i32) -> i64:
"""Computes the factorial of `n`."""
MAX_LOOKUP_VALUE: i32 = 20
FACTORIAL_LOOKUP_TABLE: list[i64] = [
i64(1),
i64(1),
i64(2),
i64(6),
i64(24),
i64(120),
i64(720),
i64(5040),
i64(40320),
i64(362880),
i64(3628800),
i64(39916800),
i64(479001600),
i64(6227020800),
i64(87178291200),
i64(1307674368000),
i64(20922789888000),
i64(355687428096000),
i64(6402373705728000),
i64(121645100408832000),
i64(2432902008176640000),
]
if n < 0:
# Exceptions are not implemented currently
# raise ValueError("factorial() not defined for negative values")
assert 1 == 0, "factorial() not defined for negative values."
elif n < MAX_LOOKUP_VALUE:
return FACTORIAL_LOOKUP_TABLE[n]
else:
f: list[i32] = [0] * 4300
f[0] = 0
f[1] = 0
f[2] = 0
f[3] = 0
f[4] = 4
f[5] = 6
f[6] = 6
f[7] = 7
f[8] = 1
f[9] = 8
f[10] = 0
f[11] = 0
f[12] = 2
f[13] = 0
f[14] = 9
f[15] = 2
f[16] = 3
f[17] = 4
f[18] = 2

f_size: i32 = 19

i: i32 = 21
while i <= n:
index: i32 = 0
carry: i32 = 0
while index < f_size:
product: i32 = f[index] * i + carry
f[index] = product % 10

carry = product // 10
index += 1

while carry > 0:
f[f_size] = carry % 10
carry = carry // 10
f_size += 1
i += 1

result: str = ""
idx: i32
for idx in range(f_size - 1, -1, -1):
result += str(f[idx])
print(result)
return i64(0)


@overload
def factorial(n: i64) -> i64:
"""Computes the factorial of `n`."""
MAX_LOOKUP_VALUE: i64 = i64(20)
FACTORIAL_LOOKUP_TABLE: list[i64] = [
i64(1),
i64(1),
i64(2),
i64(6),
i64(24),
i64(120),
i64(720),
i64(5040),
i64(40320),
i64(362880),
i64(3628800),
i64(39916800),
i64(479001600),
i64(6227020800),
i64(87178291200),
i64(1307674368000),
i64(20922789888000),
i64(355687428096000),
i64(6402373705728000),
i64(121645100408832000),
i64(2432902008176640000),
]
if n < i64(0):
# Exceptions are not implemented currently
# raise ValueError("factorial() not defined for negative values")
assert 1 == 0, "factorial() not defined for negative values."
elif n < MAX_LOOKUP_VALUE:
return FACTORIAL_LOOKUP_TABLE[n]
else:
f: list[i32] = [0] * 4300
f[0] = 0
f[1] = 0
f[2] = 0
f[3] = 0
f[4] = 4
f[5] = 6
f[6] = 6
f[7] = 7
f[8] = 1
f[9] = 8
f[10] = 0
f[11] = 0
f[12] = 2
f[13] = 0
f[14] = 9
f[15] = 2
f[16] = 3
f[17] = 4
f[18] = 2

f_size: i32 = 19

i: i32 = 21
while i64(i) <= n:
index: i32 = 0
carry: i32 = 0
while index < f_size:
product: i32 = f[index] * i + carry
f[index] = product % 10

carry = product // 10
index += 1

while carry > 0:
f[f_size] = carry % 10
carry = carry // 10
f_size += 1
i += 1

result: str = ""
idx: i32
for idx in range(f_size - 1, -1, -1):
result += str(f[idx])
print(result)
return i64(0)


@overload
def floor(x: i32) -> i32:
Expand Down Expand Up @@ -457,7 +591,6 @@ def ldexp(x: f64, i: i32) -> f64:
return result



def mod(a: i32, b: i32) -> i32:
"""
Returns a%b
Expand Down