# Use complement negation for mixed sign addition. (6)
# @see GA5Sy6

import itertools
import operator
import random

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):
        t = _fixsign(other.m, not other.s)[1]
        return Num(nadd(self.m, self.s, other.m, t, 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 _iszero(a):
    return len(a) == 1 and a[0] == 0

def _fixsign(a, s):
    return a, s and not _iszero(a)

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_addc(r, a, c, b):
    for i in range(len(r)):
        c, r[i] = divmod(r[i] + a[i] + c, b)
    return c, r

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

def _complement(a, b):
    return [b-1-x for x in a]

def _negate(a, b):
    return _inplace_addc(_complement(a, b), _zeroextend([1], len(a)), 0, b)[1]

# Convert.

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):
    n = 1 + max(len(a), len(b))
    a = _zeroextend(a, n)
    b = _zeroextend(b, n)
    return _zeroreduce(_inplace_addc(a, b, 0, base)[1])

def nadd(a, s, b, t, base):
    if s == t:
        return _fixsign(_add(a, b, base), s)
    if s:
        a, b = b, a
    a = _zeroextend(a, len(b))
    b = _zeroextend(b, len(a))
    c, r = _inplace_addc(a, _negate(b, base), 0, base)
    if not c:
        r = _negate(r, base)
    return _fixsign(_zeroreduce(r), not c)

# 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)

def nmul(a, s, b, t, base):
    return _fixsign(_mul(a, b, base), s != t)

# Test.

def _test(n, op):
    w = Num.base
    z = (0, 1, -1, w, -w, w-1, 1-w)
    for x, y in itertools.product(z, 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}'
    w = Num.base ** 3
    for _ in range(n):
        x = random.randint(-w, w)
        y = random.randint(-w, w)
        u = int(str(op(Num(x), Num(y))))
        v = op(x, y)
        assert u == v, f'{op}({x}, {y})\nExpected:{v}, Got:{u}'

n = 1000
_test(n, operator.add)
_test(n, operator.sub)
_test(n, operator.mul)

def show1(a):
    print(repr(a), a, sep='; ')

def _show(z, op):
    print(op)
    for x, y in itertools.product(z, repeat=2):
        show1(op(Num(x), Num(y)))

w = Num.base
z = (0, 1, -1, w, -w)
_show(z, operator.add)
_show(z, operator.sub)
_show(z, operator.mul)

def factorial(n):
    r = Num(1)
    for i in range(2, n+1):
        r *= Num(i)
    return r

print(factorial)
for i in range(5):
    show1(factorial(10*i))