fork(1) download
  1. # @file bignum.004.py
  2. # @ingroup experimental
  3. # Experimental big-number representation.
  4. # @date 11/22/2024
  5.  
  6. import itertools
  7. import operator
  8. import random
  9.  
  10. class Num:
  11. base = 2**8
  12.  
  13. def __init__(self, init):
  14. if isinstance(init, tuple):
  15. self.m = init[0]
  16. self.s = init[1]
  17. else:
  18. self.m = iton(abs(init), Num.base)
  19. self.s = init < 0
  20.  
  21. def __neg__(self):
  22. return Num(_fixsign(self.m.copy(), not self.s))
  23.  
  24. def __add__(self, other):
  25. return Num(nadd(self.m, self.s, other.m, other.s, Num.base))
  26.  
  27. def __sub__(self, other):
  28. t = _fixsign(other.m, not other.s)[1]
  29. return Num(nadd(self.m, self.s, other.m, t, Num.base))
  30.  
  31. def __mul__(self, other):
  32. return Num(nmul(self.m, self.s, other.m, other.s, Num.base))
  33.  
  34. def __floordiv__(self, other):
  35. return Num(ndivmod(self.m, self.s, other.m, other.s, Num.base)[0])
  36.  
  37. def __mod__(self, other):
  38. return Num(ndivmod(self.m, self.s, other.m, other.s, Num.base)[1])
  39.  
  40. def __str__(self):
  41. return '-' * self.s + ntos(self.m, Num.base)
  42.  
  43. def __repr__(self):
  44. return str((self.m, self.s))
  45.  
  46. # Utility.
  47.  
  48. def _iszero(a):
  49. return len(a) == 1 and a[0] == 0
  50.  
  51. def _fixsign(a, s):
  52. return a, s and not _iszero(a)
  53.  
  54. def _zeroextend(a, n):
  55. return a[:] + [0] * (n - len(a))
  56.  
  57. def _zeroreduce(a):
  58. n = len(a)
  59. while n != 1 and a[n-1] == 0:
  60. n -= 1
  61. return a[:n]
  62.  
  63. def _inplace_mul1(r, x, c, b):
  64. for i in range(len(r)):
  65. c, r[i] = divmod(r[i] * x + c, b)
  66. return c, r
  67.  
  68. # Convert.
  69.  
  70. def iton(x, b):
  71. r = []
  72. while True:
  73. x, y = divmod(x, b)
  74. r.append(y)
  75. if x == 0:
  76. return r
  77.  
  78. def nton(a, bi, bo):
  79. r = [0]
  80. for x in reversed(a):
  81. c = _inplace_mul1(r, bi, x, bo)[0]
  82. if c != 0:
  83. r.extend(iton(c, bo))
  84. return r
  85.  
  86. def ntos(a, b):
  87. return ''.join(map(str, reversed(nton(a, b, 10))))
  88.  
  89. # Compare.
  90.  
  91. def _cmp(x, y):
  92. return -1 if x < y else 1
  93.  
  94. def ncmp(a, b):
  95. n = len(a)
  96. m = len(b)
  97. if n != m:
  98. return _cmp(n, m)
  99. for x, y in zip(reversed(a), reversed(b)):
  100. if x != y:
  101. return _cmp(x, y)
  102. return 0
  103.  
  104. # Shift.
  105.  
  106. def nshl(a, n):
  107. return _zeroreduce([0] * n + a[:])
  108.  
  109. def nshr(a, n):
  110. return _zeroextend(a[n:], 1)
  111.  
  112. # Add.
  113.  
  114. def _add(a, b, base, op):
  115. n = 1 + max(len(a), len(b))
  116. r = _zeroextend(a, n)
  117. b = _zeroextend(b, n)
  118. c = 0
  119. for i in range(n):
  120. c, r[i] = divmod(op(r[i], b[i] + abs(c)), base)
  121. return _zeroreduce(r)
  122.  
  123. def nadd(a, s, b, t, base):
  124. if s == t:
  125. op = operator.add
  126. else:
  127. op = operator.sub
  128. if ncmp(a, b) < 0:
  129. a, b, s = b, a, t
  130. return _fixsign(_add(a, b, base, op), s)
  131.  
  132. # Multiply.
  133.  
  134. def _mul1(a, x, base):
  135. n = 1 + len(a)
  136. return _zeroreduce(_inplace_mul1(_zeroextend(a, n), x, 0, base)[1])
  137.  
  138. def _mul(a, b, base):
  139. if _iszero(b):
  140. return [0]
  141. return _add(_mul1(a, b[0], base), _mul(nshl(a, 1), nshr(b, 1), base),
  142. base, operator.add)
  143.  
  144. def nmul(a, s, b, t, base):
  145. return _fixsign(_mul(a, b, base), s != t)
  146.  
  147. # Divide.
  148.  
  149. def _divmodbase2(a, b):
  150. if len(a) < len(b):
  151. q, r = [0], a
  152. else:
  153. q, r = _divmodbase2(a, nshl(b, 1))
  154. q = nshl(q, 1)
  155. if ncmp(r, b) >= 0:
  156. q = _add(q, [1], 2, operator.add)
  157. r = _add(r, b, 2, operator.sub)
  158. return q, r
  159.  
  160. def _divmod(a, b, base):
  161. a = nton(a, base, 2)
  162. b = nton(b, base, 2)
  163. q, r = _divmodbase2(a, b)
  164. q = nton(q, 2, base)
  165. r = nton(r, 2, base)
  166. return q, r
  167.  
  168. def ndivmod(a, s, b, t, base):
  169. if _iszero(b):
  170. raise ZeroDivisionError
  171. q, r = _divmod(a, b, base)
  172. if s != t and not _iszero(r):
  173. q = _add(q, [1], base, operator.add)
  174. r = _add(b, r, base, operator.sub)
  175. return _fixsign(q, s != t), _fixsign(r, t)
  176.  
  177. # Test.
  178.  
  179. def _test(n, z, op, nozeroy=False):
  180. for x, y in itertools.product(z, repeat=2):
  181. if not nozeroy or y != 0:
  182. u = int(str(op(Num(x), Num(y))))
  183. v = op(x, y)
  184. assert u == v, f'{op}({x}, {y})\nExpected:{v}, Got:{u}'
  185. z = Num.base ** 3
  186. for _ in range(n):
  187. x = random.randint(-z, z)
  188. y = random.randint(-z, z)
  189. if not nozeroy or y != 0:
  190. u = int(str(op(Num(x), Num(y))))
  191. v = op(x, y)
  192. assert u == v, f'{op}({x}, {y})\nExpected:{v}, Got:{u}'
  193.  
  194. n = 1000
  195. w = Num.base
  196. z = (0, 1, -1, w, -w, w-1, 1-w)
  197. _test(n, z, operator.add)
  198. _test(n, z, operator.sub)
  199. _test(n, z, operator.mul)
  200. _test(n, z, operator.floordiv, True)
  201. _test(n, z, operator.mod, True)
  202.  
  203. def show1(a):
  204. print(repr(a), a, sep='; ')
  205.  
  206. def _show(z, op, nozeroy=False):
  207. print(op)
  208. for x, y in itertools.product(z, repeat=2):
  209. if not nozeroy or y != 0:
  210. show1(op(Num(x), Num(y)))
  211.  
  212. w = Num.base
  213. z = (0, 1, -1, w, -w)
  214. _show(z, operator.add)
  215. _show(z, operator.sub)
  216. _show(z, operator.mul)
  217. _show(z, operator.floordiv, True)
  218. _show(z, operator.mod, True)
  219.  
  220. def factorial(n):
  221. r = Num(1)
  222. for i in range(2, n+1):
  223. r *= Num(i)
  224. return r
  225.  
  226. print(factorial)
  227. for i in range(5):
  228. show1(factorial(10*i))
Success #stdin #stdout 0.37s 10332KB
stdin
Standard input is empty
stdout
<built-in function add>
([0], False); 0
([1], False); 1
([1], True); -1
([0, 1], False); 256
([0, 1], True); -256
([1], False); 1
([2], False); 2
([0], False); 0
([1, 1], False); 257
([255], True); -255
([1], True); -1
([0], False); 0
([2], True); -2
([255], False); 255
([1, 1], True); -257
([0, 1], False); 256
([1, 1], False); 257
([255], False); 255
([0, 2], False); 512
([0], False); 0
([0, 1], True); -256
([255], True); -255
([1, 1], True); -257
([0], False); 0
([0, 2], True); -512
<built-in function sub>
([0], False); 0
([1], True); -1
([1], False); 1
([0, 1], True); -256
([0, 1], False); 256
([1], False); 1
([0], False); 0
([2], False); 2
([255], True); -255
([1, 1], False); 257
([1], True); -1
([2], True); -2
([0], False); 0
([1, 1], True); -257
([255], False); 255
([0, 1], False); 256
([255], False); 255
([1, 1], False); 257
([0], False); 0
([0, 2], False); 512
([0, 1], True); -256
([1, 1], True); -257
([255], True); -255
([0, 2], True); -512
([0], False); 0
<built-in function mul>
([0], False); 0
([0], False); 0
([0], False); 0
([0], False); 0
([0], False); 0
([0], False); 0
([1], False); 1
([1], True); -1
([0, 1], False); 256
([0, 1], True); -256
([0], False); 0
([1], True); -1
([1], False); 1
([0, 1], True); -256
([0, 1], False); 256
([0], False); 0
([0, 1], False); 256
([0, 1], True); -256
([0, 0, 1], False); 65536
([0, 0, 1], True); -65536
([0], False); 0
([0, 1], True); -256
([0, 1], False); 256
([0, 0, 1], True); -65536
([0, 0, 1], False); 65536
<built-in function floordiv>
([0], False); 0
([0], False); 0
([0], False); 0
([0], False); 0
([1], False); 1
([1], True); -1
([0], False); 0
([1], True); -1
([1], True); -1
([1], False); 1
([1], True); -1
([0], False); 0
([0, 1], False); 256
([0, 1], True); -256
([1], False); 1
([1], True); -1
([0, 1], True); -256
([0, 1], False); 256
([1], True); -1
([1], False); 1
<built-in function mod>
([0], False); 0
([0], False); 0
([0], False); 0
([0], False); 0
([0], False); 0
([0], False); 0
([1], False); 1
([255], True); -255
([0], False); 0
([0], False); 0
([255], False); 255
([1], True); -1
([0], False); 0
([0], False); 0
([0], False); 0
([0], False); 0
([0], False); 0
([0], False); 0
([0], False); 0
([0], False); 0
<function factorial at 0x1463819d09d0>
([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