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