# Add internal numeric base (5)
# @see drmXLx
import itertools
import operator
class Num:
base = 2**8
def __init__(self, init=0):
if isinstance(init, tuple):
self.m = init[0].copy()
self.s = init[1]
else:
self.m = iton(abs(init), Num.base)
self.s = init < 0
def __neg__(self):
return Num((self.m, not self.s))
def __add__(self, other):
return Num(nadd(self.m, self.s, other.m, other.s, Num.base))
def __sub__(self, other):
return Num(nadd(self.m, self.s, other.m, not other.s, Num.base))
def __mul__(self, other):
return Num(nmul(self.m, self.s, other.m, other.s, Num.base))
def __str__(self):
return '-' * self.s + ntos(self.m, Num.base)
def __repr__(self):
return str((self.m, self.s))
# Utility.
def _fixsign(a, s):
return a, s and not _iszero(a)
def _iszero(a):
return len(a) == 1 and a[0] == 0
def _zeroextend(a, n):
return a[:] + [0] * (n - len(a))
def _zeroreduce(a):
n = len(a)
while n != 1 and a[n-1] == 0:
n -= 1
return a[:n]
def _inplace_mulc(r, x, c, b):
for i in range(len(r)):
c, r[i] = divmod(r[i] * x + c, b)
return c, r
# Conversion.
def iton(x, b):
r = []
while True:
x, y = divmod(x, b)
r.append(y)
if x == 0:
return r
def nton(a, bi, bo):
r = [0]
for x in reversed(a):
c = _inplace_mulc(r, bi, x, bo)[0]
if c != 0:
r.extend(iton(c, bo))
return r
def ntos(a, b):
return ''.join(map(str, reversed(nton(a, b, 10))))
# Compare.
def _cmp(x, y):
if x != y:
return -1 if x < y else 1
return 0
def ncmp(a, b):
n = len(a)
m = len(b)
u = itertools.chain([n], reversed(a))
v = itertools.chain([m], reversed(b))
return next(itertools.dropwhile(lambda x: x == 0, map(_cmp, u, v)), 0)
# Shift.
def nshl(a, n):
return _zeroreduce([0] * n + a[:])
def nshr(a, n):
return _zeroextend(a[n:], 1)
# Add.
def _add(a, b, base, op):
n = 1 + max(len(a), len(b))
r = _zeroextend(a, n)
b = _zeroextend(b, n)
c = 0
for i in range(n):
c, r[i] = divmod(op(r[i], b[i] + abs(c)), base)
return _zeroreduce(r)
def nadd(a, s, b, t, base):
if s == t:
op = operator.add
else:
op = operator.sub
if ncmp(a, b) < 0:
a, b, s = b, a, t
return _fixsign(_add(a, b, base, op), s)
# Multiply.
def _mul1(a, x, base):
n = 1 + len(a)
return _zeroreduce(_inplace_mulc(_zeroextend(a, n), x, 0, base)[1])
def _mul(a, b, base):
if _iszero(b):
return [0]
return _add(_mul1(a, b[0], base), _mul(nshl(a, 1), nshr(b, 1), base),
base, operator.add)
def nmul(a, s, b, t, base):
return _fixsign(_mul(a, b, base), s != t)
# Test.
def _test(n, op):
for x, y in itertools.product(range(-n, n+1), repeat=2):
u = int(str(op(Num(x), Num(y))))
v = op(x, y)
assert u == v, f'{op}({x}, {y})\nExpected:{v}, Got:{u}'
n = 50
_test(n, operator.add)
_test(n, operator.sub)
_test(n, operator.mul)
def factorial(n):
r = Num(1)
for i in range(2, n+1):
r *= Num(i)
return r
def show(a):
print(repr(a), a, sep='; ')
w = 12345
z = (0, 1, -1, w, -w)
for x in z:
show(Num(x))
print('+')
for x, y in itertools.product(z, repeat=2):
show(Num(x) + Num(y))
print('-')
for x, y in itertools.product(z, repeat=2):
show(Num(x) - Num(y))
print('*')
for x, y in itertools.product(z, repeat=2):
show(Num(x) * Num(y))
print('f')
for i in range(5):
show(factorial(10*i))
IyBBZGQgaW50ZXJuYWwgbnVtZXJpYyBiYXNlICg1KQojIEBzZWUgZHJtWEx4CgppbXBvcnQgaXRlcnRvb2xzCmltcG9ydCBvcGVyYXRvcgoKY2xhc3MgTnVtOgogICAgYmFzZSA9IDIqKjgKCiAgICBkZWYgX19pbml0X18oc2VsZiwgaW5pdD0wKToKICAgICAgICBpZiBpc2luc3RhbmNlKGluaXQsIHR1cGxlKToKICAgICAgICAgICAgc2VsZi5tID0gaW5pdFswXS5jb3B5KCkKICAgICAgICAgICAgc2VsZi5zID0gaW5pdFsxXQogICAgICAgIGVsc2U6CiAgICAgICAgICAgIHNlbGYubSA9IGl0b24oYWJzKGluaXQpLCBOdW0uYmFzZSkKICAgICAgICAgICAgc2VsZi5zID0gaW5pdCA8IDAKCiAgICBkZWYgX19uZWdfXyhzZWxmKToKICAgICAgICByZXR1cm4gTnVtKChzZWxmLm0sIG5vdCBzZWxmLnMpKQoKICAgIGRlZiBfX2FkZF9fKHNlbGYsIG90aGVyKToKICAgICAgICByZXR1cm4gTnVtKG5hZGQoc2VsZi5tLCBzZWxmLnMsIG90aGVyLm0sIG90aGVyLnMsIE51bS5iYXNlKSkKCiAgICBkZWYgX19zdWJfXyhzZWxmLCBvdGhlcik6CiAgICAgICAgcmV0dXJuIE51bShuYWRkKHNlbGYubSwgc2VsZi5zLCBvdGhlci5tLCBub3Qgb3RoZXIucywgTnVtLmJhc2UpKQoKICAgIGRlZiBfX211bF9fKHNlbGYsIG90aGVyKToKICAgICAgICByZXR1cm4gTnVtKG5tdWwoc2VsZi5tLCBzZWxmLnMsIG90aGVyLm0sIG90aGVyLnMsIE51bS5iYXNlKSkKCiAgICBkZWYgX19zdHJfXyhzZWxmKToKICAgICAgICByZXR1cm4gJy0nICogc2VsZi5zICsgbnRvcyhzZWxmLm0sIE51bS5iYXNlKQoKICAgIGRlZiBfX3JlcHJfXyhzZWxmKToKICAgICAgICByZXR1cm4gc3RyKChzZWxmLm0sIHNlbGYucykpCgojIFV0aWxpdHkuCgpkZWYgX2ZpeHNpZ24oYSwgcyk6CiAgICByZXR1cm4gYSwgcyBhbmQgbm90IF9pc3plcm8oYSkKCmRlZiBfaXN6ZXJvKGEpOgogICAgcmV0dXJuIGxlbihhKSA9PSAxIGFuZCBhWzBdID09IDAKCmRlZiBfemVyb2V4dGVuZChhLCBuKToKICAgIHJldHVybiBhWzpdICsgWzBdICogKG4gLSBsZW4oYSkpCgpkZWYgX3plcm9yZWR1Y2UoYSk6CiAgICBuID0gbGVuKGEpCiAgICB3aGlsZSBuICE9IDEgYW5kIGFbbi0xXSA9PSAwOgogICAgICAgIG4gLT0gMQogICAgcmV0dXJuIGFbOm5dCgpkZWYgX2lucGxhY2VfbXVsYyhyLCB4LCBjLCBiKToKICAgIGZvciBpIGluIHJhbmdlKGxlbihyKSk6CiAgICAgICAgYywgcltpXSA9IGRpdm1vZChyW2ldICogeCArIGMsIGIpCiAgICByZXR1cm4gYywgcgoKIyBDb252ZXJzaW9uLgoKZGVmIGl0b24oeCwgYik6CiAgICByID0gW10KICAgIHdoaWxlIFRydWU6CiAgICAgICAgeCwgeSA9IGRpdm1vZCh4LCBiKQogICAgICAgIHIuYXBwZW5kKHkpCiAgICAgICAgaWYgeCA9PSAwOgogICAgICAgICAgICByZXR1cm4gcgoKZGVmIG50b24oYSwgYmksIGJvKToKICAgIHIgPSBbMF0KICAgIGZvciB4IGluIHJldmVyc2VkKGEpOgogICAgICAgIGMgPSBfaW5wbGFjZV9tdWxjKHIsIGJpLCB4LCBibylbMF0KICAgICAgICBpZiBjICE9IDA6CiAgICAgICAgICAgIHIuZXh0ZW5kKGl0b24oYywgYm8pKQogICAgcmV0dXJuIHIKCmRlZiBudG9zKGEsIGIpOgogICAgcmV0dXJuICcnLmpvaW4obWFwKHN0ciwgcmV2ZXJzZWQobnRvbihhLCBiLCAxMCkpKSkKCiMgQ29tcGFyZS4KCmRlZiBfY21wKHgsIHkpOgogICAgaWYgeCAhPSB5OgogICAgICAgIHJldHVybiAtMSBpZiB4IDwgeSBlbHNlIDEKICAgIHJldHVybiAwCgpkZWYgbmNtcChhLCBiKToKICAgIG4gPSBsZW4oYSkKICAgIG0gPSBsZW4oYikKICAgIHUgPSBpdGVydG9vbHMuY2hhaW4oW25dLCByZXZlcnNlZChhKSkKICAgIHYgPSBpdGVydG9vbHMuY2hhaW4oW21dLCByZXZlcnNlZChiKSkKICAgIHJldHVybiBuZXh0KGl0ZXJ0b29scy5kcm9wd2hpbGUobGFtYmRhIHg6IHggPT0gMCwgbWFwKF9jbXAsIHUsIHYpKSwgMCkKCiMgU2hpZnQuCgpkZWYgbnNobChhLCBuKToKICAgIHJldHVybiBfemVyb3JlZHVjZShbMF0gKiBuICsgYVs6XSkKCmRlZiBuc2hyKGEsIG4pOgogICAgcmV0dXJuIF96ZXJvZXh0ZW5kKGFbbjpdLCAxKQoKIyBBZGQuCgpkZWYgX2FkZChhLCBiLCBiYXNlLCBvcCk6CiAgICBuID0gMSArIG1heChsZW4oYSksIGxlbihiKSkKICAgIHIgPSBfemVyb2V4dGVuZChhLCBuKQogICAgYiA9IF96ZXJvZXh0ZW5kKGIsIG4pCiAgICBjID0gMAogICAgZm9yIGkgaW4gcmFuZ2Uobik6CiAgICAgICAgYywgcltpXSA9IGRpdm1vZChvcChyW2ldLCBiW2ldICsgYWJzKGMpKSwgYmFzZSkKICAgIHJldHVybiBfemVyb3JlZHVjZShyKQoKZGVmIG5hZGQoYSwgcywgYiwgdCwgYmFzZSk6CiAgICBpZiBzID09IHQ6CiAgICAgICAgb3AgPSBvcGVyYXRvci5hZGQKICAgIGVsc2U6CiAgICAgICAgb3AgPSBvcGVyYXRvci5zdWIKICAgICAgICBpZiBuY21wKGEsIGIpIDwgMDoKICAgICAgICAgICAgYSwgYiwgcyA9IGIsIGEsIHQKICAgIHJldHVybiBfZml4c2lnbihfYWRkKGEsIGIsIGJhc2UsIG9wKSwgcykKCiMgTXVsdGlwbHkuCgpkZWYgX211bDEoYSwgeCwgYmFzZSk6CiAgICBuID0gMSArIGxlbihhKQogICAgcmV0dXJuIF96ZXJvcmVkdWNlKF9pbnBsYWNlX211bGMoX3plcm9leHRlbmQoYSwgbiksIHgsIDAsIGJhc2UpWzFdKQoKZGVmIF9tdWwoYSwgYiwgYmFzZSk6CiAgICBpZiBfaXN6ZXJvKGIpOgogICAgICAgIHJldHVybiBbMF0KICAgIHJldHVybiBfYWRkKF9tdWwxKGEsIGJbMF0sIGJhc2UpLCBfbXVsKG5zaGwoYSwgMSksIG5zaHIoYiwgMSksIGJhc2UpLAogICAgICAgICAgICAgICAgYmFzZSwgb3BlcmF0b3IuYWRkKQoKZGVmIG5tdWwoYSwgcywgYiwgdCwgYmFzZSk6CiAgICByZXR1cm4gX2ZpeHNpZ24oX211bChhLCBiLCBiYXNlKSwgcyAhPSB0KQoKIyBUZXN0LgoKZGVmIF90ZXN0KG4sIG9wKToKICAgIGZvciB4LCB5IGluIGl0ZXJ0b29scy5wcm9kdWN0KHJhbmdlKC1uLCBuKzEpLCByZXBlYXQ9Mik6CiAgICAgICAgdSA9IGludChzdHIob3AoTnVtKHgpLCBOdW0oeSkpKSkKICAgICAgICB2ID0gb3AoeCwgeSkKICAgICAgICBhc3NlcnQgdSA9PSB2LCBmJ3tvcH0oe3h9LCB7eX0pXG5FeHBlY3RlZDp7dn0sIEdvdDp7dX0nCgpuID0gNTAKX3Rlc3Qobiwgb3BlcmF0b3IuYWRkKQpfdGVzdChuLCBvcGVyYXRvci5zdWIpCl90ZXN0KG4sIG9wZXJhdG9yLm11bCkKCmRlZiBmYWN0b3JpYWwobik6CiAgICByID0gTnVtKDEpCiAgICBmb3IgaSBpbiByYW5nZSgyLCBuKzEpOgogICAgICAgIHIgKj0gTnVtKGkpCiAgICByZXR1cm4gcgoKZGVmIHNob3coYSk6CiAgICBwcmludChyZXByKGEpLCBhLCBzZXA9JzsgJykKCncgPSAxMjM0NQp6ID0gKDAsIDEsIC0xLCB3LCAtdykKZm9yIHggaW4gejoKICAgIHNob3coTnVtKHgpKQpwcmludCgnKycpCmZvciB4LCB5IGluIGl0ZXJ0b29scy5wcm9kdWN0KHosIHJlcGVhdD0yKToKICAgIHNob3coTnVtKHgpICsgTnVtKHkpKQpwcmludCgnLScpCmZvciB4LCB5IGluIGl0ZXJ0b29scy5wcm9kdWN0KHosIHJlcGVhdD0yKToKICAgIHNob3coTnVtKHgpIC0gTnVtKHkpKQpwcmludCgnKicpCmZvciB4LCB5IGluIGl0ZXJ0b29scy5wcm9kdWN0KHosIHJlcGVhdD0yKToKICAgIHNob3coTnVtKHgpICogTnVtKHkpKQpwcmludCgnZicpCmZvciBpIGluIHJhbmdlKDUpOgogICAgc2hvdyhmYWN0b3JpYWwoMTAqaSkp
([0], False); 0
([1], False); 1
([1], True); -1
([57, 48], False); 12345
([57, 48], True); -12345
+
([0], False); 0
([1], False); 1
([1], True); -1
([57, 48], False); 12345
([57, 48], True); -12345
([1], False); 1
([2], False); 2
([0], False); 0
([58, 48], False); 12346
([56, 48], True); -12344
([1], True); -1
([0], False); 0
([2], True); -2
([56, 48], False); 12344
([58, 48], True); -12346
([57, 48], False); 12345
([58, 48], False); 12346
([56, 48], False); 12344
([114, 96], False); 24690
([0], False); 0
([57, 48], True); -12345
([56, 48], True); -12344
([58, 48], True); -12346
([0], False); 0
([114, 96], True); -24690
-
([0], False); 0
([1], True); -1
([1], False); 1
([57, 48], True); -12345
([57, 48], False); 12345
([1], False); 1
([0], False); 0
([2], False); 2
([56, 48], True); -12344
([58, 48], False); 12346
([1], True); -1
([2], True); -2
([0], False); 0
([58, 48], True); -12346
([56, 48], False); 12344
([57, 48], False); 12345
([56, 48], False); 12344
([58, 48], False); 12346
([0], False); 0
([114, 96], False); 24690
([57, 48], True); -12345
([58, 48], True); -12346
([56, 48], True); -12344
([114, 96], True); -24690
([0], False); 0
*
([0], False); 0
([0], False); 0
([0], False); 0
([0], False); 0
([0], False); 0
([0], False); 0
([1], False); 1
([1], True); -1
([57, 48], False); 12345
([57, 48], True); -12345
([0], False); 0
([1], True); -1
([1], False); 1
([57, 48], True); -12345
([57, 48], False); 12345
([0], False); 0
([57, 48], False); 12345
([57, 48], True); -12345
([177, 108, 21, 9], False); 152399025
([177, 108, 21, 9], True); -152399025
([0], False); 0
([57, 48], True); -12345
([57, 48], False); 12345
([177, 108, 21, 9], True); -152399025
([177, 108, 21, 9], False); 152399025
f
([1], False); 1
([0, 95, 55], False); 3628800
([0, 0, 180, 130, 124, 103, 195, 33], False); 2432902008176640000
([0, 0, 0, 84, 221, 245, 93, 134, 150, 15, 55, 246, 19, 13], False); 265252859812191058636308480000000
([0, 0, 0, 0, 64, 37, 5, 255, 100, 222, 15, 8, 126, 242, 199, 132, 27, 232, 234, 142], False); 815915283247897734345611269596115894272000000000