int128.nim 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517
  1. type
  2. Int128* = object
  3. udata: array[4,uint32]
  4. template sdata(arg: Int128, idx: int): int32 =
  5. # udata and sdata was supposed to be in a union, but unions are
  6. # handled incorrectly in the VM.
  7. cast[ptr int32](arg.udata[idx].unsafeAddr)[]
  8. # encoding least significant int first (like LittleEndian)
  9. type
  10. InvalidArgument = object of Exception
  11. template require(cond: bool) =
  12. if unlikely(not cond):
  13. raise newException(InvalidArgument, "")
  14. const
  15. Zero* = Int128(udata: [0'u32,0,0,0])
  16. One* = Int128(udata: [1'u32,0,0,0])
  17. Ten* = Int128(udata: [10'u32,0,0,0])
  18. Min = Int128(udata: [0'u32,0,0,0x80000000'u32])
  19. Max = Int128(udata: [high(uint32),high(uint32),high(uint32),uint32(high(int32))])
  20. template low*(t: typedesc[Int128]): Int128 = Min
  21. template high*(t: typedesc[Int128]): Int128 = Max
  22. proc `$`*(a: Int128): string
  23. proc toInt128*[T: SomeInteger](arg: T): Int128 =
  24. when T is SomeUnsignedInt:
  25. when sizeof(arg) <= 4:
  26. result.udata[0] = uint32(arg)
  27. else:
  28. result.udata[0] = uint32(arg and T(0xffffffff))
  29. result.udata[1] = uint32(arg shr 32)
  30. else:
  31. when sizeof(arg) <= 4:
  32. result.sdata(0) = int32(arg)
  33. if arg < 0: # sign extend
  34. result.sdata(1) = -1
  35. result.sdata(2) = -1
  36. result.sdata(3) = -1
  37. else:
  38. let tmp = int64(arg)
  39. result.udata[0] = uint32(tmp and 0xffffffff)
  40. result.sdata(1) = int32(tmp shr 32)
  41. if arg < 0: # sign extend
  42. result.sdata(2) = -1
  43. result.sdata(3) = -1
  44. template isNegative(arg: Int128): bool =
  45. arg.sdata(3) < 0
  46. template isNegative(arg: int32): bool =
  47. arg < 0
  48. proc bitconcat(a,b: uint32): uint64 =
  49. (uint64(a) shl 32) or uint64(b)
  50. proc bitsplit(a: uint64): (uint32,uint32) =
  51. (cast[uint32](a shr 32), cast[uint32](a))
  52. proc toInt64*(arg: Int128): int64 =
  53. if isNegative(arg):
  54. assert(arg.sdata(3) == -1, "out of range")
  55. assert(arg.sdata(2) == -1, "out of range")
  56. else:
  57. assert(arg.sdata(3) == 0, "out of range")
  58. assert(arg.sdata(2) == 0, "out of range")
  59. cast[int64](bitconcat(arg.udata[1], arg.udata[0]))
  60. proc toUInt64*(arg: Int128): uint64 =
  61. assert(arg.udata[3] == 0)
  62. assert(arg.udata[2] == 0)
  63. bitconcat(arg.udata[1], arg.udata[0])
  64. proc addToHex(result: var string; arg: uint32) =
  65. for i in 0 ..< 8:
  66. let idx = (arg shr ((7-i) * 4)) and 0xf
  67. result.add "0123456789abcdef"[idx]
  68. proc addToHex*(result: var string; arg: Int128) =
  69. var i = 3
  70. while i >= 0:
  71. result.addToHex(arg.udata[i])
  72. i -= 1
  73. proc toHex*(arg: Int128): string =
  74. result.addToHex(arg)
  75. proc inc*(a: var Int128, y: uint32 = 1) =
  76. let input = a
  77. a.udata[0] += y
  78. if unlikely(a.udata[0] < y):
  79. a.udata[1].inc
  80. if unlikely(a.udata[1] == 0):
  81. a.udata[2].inc
  82. if unlikely(a.udata[2] == 0):
  83. a.udata[3].inc
  84. doAssert(a.sdata(3) != low(int32), "overflow")
  85. proc cmp*(a,b: Int128): int =
  86. let tmp1 = cmp(a.sdata(3), b.sdata(3))
  87. if tmp1 != 0: return tmp1
  88. let tmp2 = cmp(a.udata[2], b.udata[2])
  89. if tmp2 != 0: return tmp2
  90. let tmp3 = cmp(a.udata[1], b.udata[1])
  91. if tmp3 != 0: return tmp3
  92. let tmp4 = cmp(a.udata[0], b.udata[0])
  93. return tmp4
  94. proc `<`*(a,b: Int128): bool =
  95. cmp(a,b) < 0
  96. proc `<=`*(a,b: Int128): bool =
  97. cmp(a,b) <= 0
  98. proc `==`*(a,b: Int128): bool =
  99. if a.udata[0] != b.udata[0]: return false
  100. if a.udata[1] != b.udata[1]: return false
  101. if a.udata[2] != b.udata[2]: return false
  102. if a.udata[3] != b.udata[3]: return false
  103. return true
  104. proc inplaceBitnot(a: var Int128) =
  105. a.udata[0] = not a.udata[0]
  106. a.udata[1] = not a.udata[1]
  107. a.udata[2] = not a.udata[2]
  108. a.udata[3] = not a.udata[3]
  109. proc bitnot*(a: Int128): Int128 =
  110. result.udata[0] = not a.udata[0]
  111. result.udata[1] = not a.udata[1]
  112. result.udata[2] = not a.udata[2]
  113. result.udata[3] = not a.udata[3]
  114. proc bitand*(a,b: Int128): Int128 =
  115. result.udata[0] = a.udata[0] and b.udata[0]
  116. result.udata[1] = a.udata[1] and b.udata[1]
  117. result.udata[2] = a.udata[2] and b.udata[2]
  118. result.udata[3] = a.udata[3] and b.udata[3]
  119. proc bitor*(a,b: Int128): Int128 =
  120. result.udata[0] = a.udata[0] or b.udata[0]
  121. result.udata[1] = a.udata[1] or b.udata[1]
  122. result.udata[2] = a.udata[2] or b.udata[2]
  123. result.udata[3] = a.udata[3] or b.udata[3]
  124. proc bitxor*(a,b: Int128): Int128 =
  125. result.udata[0] = a.udata[0] xor b.udata[0]
  126. result.udata[1] = a.udata[1] xor b.udata[1]
  127. result.udata[2] = a.udata[2] xor b.udata[2]
  128. result.udata[3] = a.udata[3] xor b.udata[3]
  129. proc `shr`*(a: Int128, b: int): Int128 =
  130. let b = b and 127
  131. if b < 32:
  132. result.sdata(3) = a.sdata(3) shr b
  133. result.udata[2] = cast[uint32](bitconcat(a.udata[3], a.udata[2]) shr b)
  134. result.udata[1] = cast[uint32](bitconcat(a.udata[2], a.udata[1]) shr b)
  135. result.udata[0] = cast[uint32](bitconcat(a.udata[1], a.udata[0]) shr b)
  136. elif b < 64:
  137. if isNegative(a):
  138. result.sdata(3) = -1
  139. result.sdata(2) = a.sdata(3) shr (b and 31)
  140. result.udata[1] = cast[uint32](bitconcat(a.udata[2], a.udata[1]) shr (b and 31))
  141. result.udata[0] = cast[uint32](bitconcat(a.udata[1], a.udata[0]) shr (b and 31))
  142. elif b < 96:
  143. if isNegative(a):
  144. result.sdata(3) = -1
  145. result.sdata(2) = -1
  146. result.sdata(1) = a.sdata(3) shr (b and 31)
  147. result.udata[0] = cast[uint32](bitconcat(a.udata[1], a.udata[0]) shr (b and 31))
  148. else: # b < 128
  149. if isNegative(a):
  150. result.sdata(3) = -1
  151. result.sdata(2) = -1
  152. result.sdata(1) = -1
  153. result.sdata(0) = a.sdata(3) shr (b and 31)
  154. proc `shl`*(a: Int128, b: int): Int128 =
  155. let b = b and 127
  156. if b < 32:
  157. result.udata[0] = a.udata[0] shl b
  158. result.udata[1] = cast[uint32]((bitconcat(a.udata[1], a.udata[0]) shl b) shr 32)
  159. result.udata[2] = cast[uint32]((bitconcat(a.udata[2], a.udata[1]) shl b) shr 32)
  160. result.udata[3] = cast[uint32]((bitconcat(a.udata[3], a.udata[2]) shl b) shr 32)
  161. elif b < 64:
  162. result.udata[0] = 0
  163. result.udata[1] = a.udata[0] shl (b and 31)
  164. result.udata[2] = cast[uint32]((bitconcat(a.udata[1], a.udata[0]) shl (b and 31)) shr 32)
  165. result.udata[3] = cast[uint32]((bitconcat(a.udata[2], a.udata[1]) shl (b and 31)) shr 32)
  166. elif b < 96:
  167. result.udata[0] = 0
  168. result.udata[1] = 0
  169. result.udata[2] = a.udata[0] shl (b and 31)
  170. result.udata[3] = cast[uint32]((bitconcat(a.udata[1], a.udata[0]) shl (b and 31)) shr 32)
  171. else:
  172. result.udata[0] = 0
  173. result.udata[1] = 0
  174. result.udata[2] = 0
  175. result.udata[3] = a.udata[0] shl (b and 31)
  176. proc `+`*(a,b: Int128): Int128 =
  177. let tmp0 = uint64(a.udata[0]) + uint64(b.udata[0])
  178. result.udata[0] = cast[uint32](tmp0)
  179. let tmp1 = uint64(a.udata[1]) + uint64(b.udata[1]) + (tmp0 shr 32)
  180. result.udata[1] = cast[uint32](tmp1)
  181. let tmp2 = uint64(a.udata[2]) + uint64(b.udata[2]) + (tmp1 shr 32)
  182. result.udata[2] = cast[uint32](tmp2)
  183. let tmp3 = uint64(a.udata[3]) + uint64(b.udata[3]) + (tmp2 shr 32)
  184. result.udata[3] = cast[uint32](tmp3)
  185. proc `+=`*(a: var Int128, b: Int128) =
  186. a = a + b
  187. proc `-`*(a: Int128): Int128 =
  188. result = bitnot(a)
  189. result.inc
  190. proc `-`*(a,b: Int128): Int128 =
  191. a + (-b)
  192. proc `-=`*(a: var Int128, b: Int128) =
  193. a = a - b
  194. proc abs*(a: Int128): Int128 =
  195. if isNegative(a):
  196. -a
  197. else:
  198. a
  199. proc abs(a: int32): int =
  200. if a < 0: -a else: a
  201. proc `*`(a: Int128, b: uint32): Int128 =
  202. let tmp0 = uint64(a.udata[0]) * uint64(b)
  203. let tmp1 = uint64(a.udata[1]) * uint64(b)
  204. let tmp2 = uint64(a.udata[2]) * uint64(b)
  205. let tmp3 = uint64(a.udata[3]) * uint64(b)
  206. if unlikely(tmp3 > uint64(high(int32))):
  207. assert(false, "overflow")
  208. result.udata[0] = cast[uint32](tmp0)
  209. result.udata[1] = cast[uint32](tmp1) + cast[uint32](tmp0 shr 32)
  210. result.udata[2] = cast[uint32](tmp2) + cast[uint32](tmp1 shr 32)
  211. result.udata[3] = cast[uint32](tmp3) + cast[uint32](tmp2 shr 32)
  212. proc `*`*(a: Int128, b: int32): Int128 =
  213. let isNegative = isNegative(a) xor isNegative(b)
  214. result = a * cast[uint32](abs(b))
  215. if b < 0:
  216. result = -result
  217. proc `*=`*(a: var Int128, b: int32): Int128 =
  218. result = result * b
  219. proc makeInt128(high,low: uint64): Int128 =
  220. result.udata[0] = cast[uint32](low)
  221. result.udata[1] = cast[uint32](low shr 32)
  222. result.udata[2] = cast[uint32](high)
  223. result.udata[3] = cast[uint32](high shr 32)
  224. proc high64(a: Int128): uint64 =
  225. bitconcat(a.udata[3], a.udata[2])
  226. proc low64(a: Int128): uint64 =
  227. bitconcat(a.udata[1], a.udata[0])
  228. proc `*`*(lhs,rhs: Int128): Int128 =
  229. let isNegative = isNegative(lhs) xor isNegative(rhs)
  230. let
  231. a = cast[uint64](lhs.udata[0])
  232. b = cast[uint64](lhs.udata[1])
  233. c = cast[uint64](lhs.udata[2])
  234. d = cast[uint64](lhs.udata[3])
  235. e = cast[uint64](rhs.udata[0])
  236. f = cast[uint64](rhs.udata[1])
  237. g = cast[uint64](rhs.udata[2])
  238. h = cast[uint64](rhs.udata[3])
  239. let a32 = cast[uint64](lhs.udata[1])
  240. let a00 = cast[uint64](lhs.udata[0])
  241. let b32 = cast[uint64](rhs.udata[1])
  242. let b00 = cast[uint64](rhs.udata[0])
  243. result = makeInt128(high64(lhs) * low64(rhs) + low64(lhs) * high64(rhs) + a32 * b32, a00 * b00)
  244. result = result + toInt128(a32 * b00) shl 32
  245. result = result + toInt128(a00 * b32) shl 32
  246. if isNegative != isNegative(result):
  247. echo result
  248. assert(false, "overflow")
  249. proc `*=`*(a: var Int128, b: Int128) =
  250. a = a * b
  251. import bitops
  252. proc fastLog2*(a: Int128): int =
  253. if a.udata[3] != 0:
  254. return 96 + fastLog2(a.udata[3])
  255. if a.udata[2] != 0:
  256. return 64 + fastLog2(a.udata[2])
  257. if a.udata[1] != 0:
  258. return 32 + fastLog2(a.udata[1])
  259. if a.udata[0] != 0:
  260. return fastLog2(a.udata[0])
  261. proc divMod*(dividend, divisor: Int128): tuple[quotient, remainder: Int128] =
  262. assert(divisor != Zero)
  263. let isNegative = isNegative(dividend) xor isNegative(divisor)
  264. var dividend = abs(dividend)
  265. let divisor = abs(divisor)
  266. if divisor > dividend:
  267. result.quotient = Zero
  268. result.remainder = dividend
  269. return
  270. if divisor == dividend:
  271. result.quotient = One
  272. result.remainder = Zero
  273. return
  274. var denominator = divisor
  275. var quotient = Zero
  276. # Left aligns the MSB of the denominator and the dividend.
  277. let shift = fastLog2(dividend) - fastLog2(denominator)
  278. denominator = denominator shl shift
  279. # Uses shift-subtract algorithm to divide dividend by denominator. The
  280. # remainder will be left in dividend.
  281. for i in 0 .. shift:
  282. quotient = quotient shl 1
  283. if dividend >= denominator:
  284. dividend = dividend - denominator
  285. quotient = bitor(quotient, One)
  286. denominator = denominator shr 1
  287. result.quotient = quotient
  288. result.remainder = dividend
  289. proc `div`*(a,b: Int128): Int128 =
  290. let (a,b) = divMod(a,b)
  291. return a
  292. proc `mod`*(a,b: Int128): Int128 =
  293. let (a,b) = divMod(a,b)
  294. return b
  295. proc `$`*(a: Int128): string =
  296. if a == Zero:
  297. result = "0"
  298. elif a == low(Int128):
  299. result = "-170141183460469231731687303715884105728"
  300. else:
  301. let isNegative = isNegative(a)
  302. var a = abs(a)
  303. while a > Zero:
  304. let (quot, rem) = divMod(a, Ten)
  305. result.add "0123456789"[rem.toInt64]
  306. a = quot
  307. if isNegative:
  308. result.add '-'
  309. var i = 0
  310. var j = high(result)
  311. while i < j:
  312. swap(result[i], result[j])
  313. i += 1
  314. j -= 1
  315. proc parseDecimalInt128*(arg: string, pos: int = 0): Int128 =
  316. assert(pos < arg.len)
  317. assert(arg[pos] in {'-','0'..'9'})
  318. var isNegative = false
  319. var pos = pos
  320. if arg[pos] == '-':
  321. isNegative = true
  322. pos += 1
  323. result = Zero
  324. while pos < arg.len and arg[pos] in '0' .. '9':
  325. result = result * Ten
  326. result.inc(uint32(arg[pos]) - uint32('0'))
  327. pos += 1
  328. if isNegative:
  329. result = -result
  330. # fluff
  331. proc `<`*(a: Int128, b: BiggestInt): bool =
  332. cmp(a,toInt128(b)) < 0
  333. proc `<`*(a: BiggestInt, b: Int128): bool =
  334. cmp(toInt128(a), b) < 0
  335. proc `<=`*(a: Int128, b: BiggestInt): bool =
  336. cmp(a,toInt128(b)) <= 0
  337. proc `<=`*(a: BiggestInt, b: Int128): bool =
  338. cmp(toInt128(a), b) <= 0
  339. proc `==`*(a: Int128, b: BiggestInt): bool =
  340. a == toInt128(b)
  341. proc `==`*(a: BiggestInt, b: Int128): bool =
  342. toInt128(a) == b
  343. proc `-`*(a: BiggestInt, b: Int128): Int128 =
  344. toInt128(a) - b
  345. proc `-`*(a: Int128, b: BiggestInt): Int128 =
  346. a - toInt128(b)
  347. proc `+`*(a: BiggestInt, b: Int128): Int128 =
  348. toInt128(a) + b
  349. proc `+`*(a: Int128, b: BiggestInt): Int128 =
  350. a + toInt128(b)
  351. when isMainModule:
  352. let (a,b) = divMod(Ten,Ten)
  353. doAssert $One == "1"
  354. doAssert $Ten == "10"
  355. doAssert $Zero == "0"
  356. let c = parseDecimalInt128("12345678989876543210123456789")
  357. doAssert $c == "12345678989876543210123456789"
  358. var d : array[39, Int128]
  359. d[0] = parseDecimalInt128("1")
  360. d[1] = parseDecimalInt128("10")
  361. d[2] = parseDecimalInt128("100")
  362. d[3] = parseDecimalInt128("1000")
  363. d[4] = parseDecimalInt128("10000")
  364. d[5] = parseDecimalInt128("100000")
  365. d[6] = parseDecimalInt128("1000000")
  366. d[7] = parseDecimalInt128("10000000")
  367. d[8] = parseDecimalInt128("100000000")
  368. d[9] = parseDecimalInt128("1000000000")
  369. d[10] = parseDecimalInt128("10000000000")
  370. d[11] = parseDecimalInt128("100000000000")
  371. d[12] = parseDecimalInt128("1000000000000")
  372. d[13] = parseDecimalInt128("10000000000000")
  373. d[14] = parseDecimalInt128("100000000000000")
  374. d[15] = parseDecimalInt128("1000000000000000")
  375. d[16] = parseDecimalInt128("10000000000000000")
  376. d[17] = parseDecimalInt128("100000000000000000")
  377. d[18] = parseDecimalInt128("1000000000000000000")
  378. d[19] = parseDecimalInt128("10000000000000000000")
  379. d[20] = parseDecimalInt128("100000000000000000000")
  380. d[21] = parseDecimalInt128("1000000000000000000000")
  381. d[22] = parseDecimalInt128("10000000000000000000000")
  382. d[23] = parseDecimalInt128("100000000000000000000000")
  383. d[24] = parseDecimalInt128("1000000000000000000000000")
  384. d[25] = parseDecimalInt128("10000000000000000000000000")
  385. d[26] = parseDecimalInt128("100000000000000000000000000")
  386. d[27] = parseDecimalInt128("1000000000000000000000000000")
  387. d[28] = parseDecimalInt128("10000000000000000000000000000")
  388. d[29] = parseDecimalInt128("100000000000000000000000000000")
  389. d[30] = parseDecimalInt128("1000000000000000000000000000000")
  390. d[31] = parseDecimalInt128("10000000000000000000000000000000")
  391. d[32] = parseDecimalInt128("100000000000000000000000000000000")
  392. d[33] = parseDecimalInt128("1000000000000000000000000000000000")
  393. d[34] = parseDecimalInt128("10000000000000000000000000000000000")
  394. d[35] = parseDecimalInt128("100000000000000000000000000000000000")
  395. d[36] = parseDecimalInt128("1000000000000000000000000000000000000")
  396. d[37] = parseDecimalInt128("10000000000000000000000000000000000000")
  397. d[38] = parseDecimalInt128("100000000000000000000000000000000000000")
  398. for i in 0 ..< d.len:
  399. for j in 0 ..< d.len:
  400. doAssert(cmp(d[i], d[j]) == cmp(i,j))
  401. if i + j < d.len:
  402. doAssert d[i] * d[j] == d[i+j]
  403. if i - j >= 0:
  404. doAssert d[i] div d[j] == d[i-j]
  405. var sum: Int128
  406. for it in d:
  407. sum += it
  408. doAssert $sum == "111111111111111111111111111111111111111"
  409. for it in d.mitems:
  410. it = -it
  411. for i in 0 ..< d.len:
  412. for j in 0 ..< d.len:
  413. doAssert(cmp(d[i], d[j]) == -cmp(i,j))
  414. if i + j < d.len:
  415. doAssert d[i] * d[j] == -d[i+j]
  416. if i - j >= 0:
  417. doAssert d[i] div d[j] == -d[i-j]
  418. doAssert $high(Int128) == "170141183460469231731687303715884105727"
  419. doAssert $low(Int128) == "-170141183460469231731687303715884105728"