2,180 bytes · the Python implementation · view raw
import re
from .math_big_integer_types import BigIntegerOp
_INTEGER = re.compile(r"^-?(0|[1-9][0-9]*)$")
#: The largest result, in bits, that power will build: about 19,700 decimal digits.
MAX_POWER_BITS = 65536def parse_big_integer(text: str) -> int:
"""Parse the registry's decimal integer form. "-0", "+1", "01" and " 1" are refused."""ifnot isinstance(text, str) ornot _INTEGER.fullmatch(text) or text == "-0":
raise ValueError('not a whole number in decimal: "%s"' % (text,))
return int(text)
def _trunc_div(x: int, y: int) -> int:
q = abs(x) // abs(y)
return -q if (x < 0) != (y < 0) else q
def power_big_integer(base: int, exponent: int) -> int:
"""Raise to a power, refusing results beyond MAX_POWER_BITS before building them."""if exponent < 0:
raise ValueError("exponent must not be negative")
magnitude = abs(base)
if magnitude >= 2and magnitude.bit_length() * exponent > MAX_POWER_BITS:
raise ValueError("result too large: power is limited to %d bits" % (MAX_POWER_BITS,))
if magnitude <= 1:
if exponent == 0:
return1if base == -1:
return1if exponent % 2 == 0else -1return base
return base ** exponent
def calculate_big_integer(a: str, op: BigIntegerOp, b: str) -> str:
"""Exact integer arithmetic on decimal strings. Division truncates towards zero and the remainder takes the sign of the dividend, as in TypeScript and Rust. Python's own // floors, so it is not used directly on signed values. """
x = parse_big_integer(a)
y = parse_big_integer(b)
if op == "add":
return str(x + y)
if op == "subtract":
return str(x - y)
if op == "multiply":
return str(x * y)
if op == "divide":
if y == 0:
raise ZeroDivisionError("division by zero")
return str(_trunc_div(x, y))
if op == "remainder":
if y == 0:
raise ZeroDivisionError("division by zero")
return str(x - y * _trunc_div(x, y))
if op == "power":
return str(power_big_integer(x, y))
raise ValueError('unknown operation "%s"' % (op,))