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(nsub(self.m, other.m, 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. # Subtract.
  142.  
  143. def nsub(a, b, base):
  144. return nadd(a, nneg(b, base), base)
  145.  
  146. # Multiply.
  147.  
  148. def _mul1(a, x, base):
  149. n = 1 + len(a)
  150. return _signreduce(_inplace_mul1(_signextend(a, n), x, 0, base)[1])
  151.  
  152. def _mul(a, b, base):
  153. if _iszero(b):
  154. return [0, 0]
  155. return nadd(_mul1(a, b[0], base), _mul(nshl(a, 1), nshr(b, 1), base),
  156. base)
  157.  
  158. def nmul(a, b, base):
  159. r = _mul(a, _abs(b, base), base)
  160. if _isneg(b):
  161. r = nneg(r, base)
  162. return r
  163.  
  164. # Divide.
  165.  
  166. def _div2(a, b):
  167. if len(a) < len(b):
  168. q, r = [0, 0], a
  169. else:
  170. q, r = _div2(a, nshl(b, 1))
  171. q = nshl(q, 1)
  172. if ncmp(r, b) >= 0:
  173. q = nadd(q, [1, 0], 2)
  174. r = nsub(r, b, 2)
  175. return q, r
  176.  
  177. def _div(a, b, base):
  178. a = nton(a, base, 2)
  179. b = nton(b, base, 2)
  180. q, r = _div2(a, b)
  181. q = nton(q, 2, base)
  182. r = nton(r, 2, base)
  183. return q, r
  184.  
  185. def ndiv(a, b, base):
  186. if _iszero(b):
  187. raise ZeroDivisionError
  188. t = _abs(b, base)
  189. q, r = _div(_abs(a, base), t, base)
  190. if not _samesign(a, b) and not _iszero(r):
  191. q = nadd(q, [1, 0], base)
  192. r = nsub(t, r, base)
  193. if not _samesign(a, b):
  194. q = nneg(q, base)
  195. if _isneg(b):
  196. r = nneg(r, base)
  197. return q, r
  198.  
  199. # Test.
  200.  
  201. def _test(n, z, op, nozeroy=False):
  202. for x, y in itertools.product(z, repeat=2):
  203. if not nozeroy or y != 0:
  204. u = int(str(op(Num(x), Num(y))))
  205. v = op(x, y)
  206. assert u == v, f'{op}({x}, {y})\nExpected:{v}, Got:{u}'
  207. z = Num.base ** 3
  208. for _ in range(n):
  209. x = random.randint(-z, z)
  210. y = random.randint(-z, z)
  211. if not nozeroy or y != 0:
  212. u = int(str(op(Num(x), Num(y))))
  213. v = op(x, y)
  214. assert u == v, f'{op}({x}, {y})\nExpected:{v}, Got:{u}'
  215.  
  216. n = 1000
  217. w = Num.base
  218. z = (0, 1, -1, w, -w, w-1, 1-w)
  219. _test(n, z, operator.add)
  220. _test(n, z, operator.sub)
  221. _test(n, z, operator.mul)
  222. _test(n, z, operator.floordiv, True)
  223. _test(n, z, operator.mod, True)
  224.  
  225. def show1(a):
  226. print(repr(a), a, sep='; ')
  227.  
  228. def _show(z, op, nozeroy=False):
  229. print(op)
  230. for x, y in itertools.product(z, repeat=2):
  231. if not nozeroy or y != 0:
  232. show1(op(Num(x), Num(y)))
  233.  
  234. w = Num.base
  235. z = (0, 1, -1, w, -w)
  236. _show(z, operator.add)
  237. _show(z, operator.sub)
  238. _show(z, operator.mul)
  239. _show(z, operator.floordiv, True)
  240. _show(z, operator.mod, True)
  241.  
  242. def factorial(n):
  243. r = Num(1)
  244. for i in range(2, n+1):
  245. r *= Num(i)
  246. return r
  247.  
  248. print(factorial)
  249. for i in range(5):
  250. show1(factorial(10*i))
Success #stdin #stdout 0.49s 10128KB
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 0x1499bedd0f70>
[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