This commit is contained in:
itamar 2026-03-20 18:34:42 +00:00
commit e09e88e69c
Signed by: itamar
GPG key ID: C494AC33A201F9E4
7 changed files with 2333 additions and 0 deletions

192
bigints.nim Normal file
View file

@ -0,0 +1,192 @@
import strutils
const BASE = 1_000_000_000'u64
const BASE_DIGITS = 9
type
BigInt* = object
sign*: int # -1, 0, 1
digits*: seq[uint32] # little endian limbs
proc normalize(a: var BigInt) =
while a.digits.len > 0 and a.digits[^1] == 0:
a.digits.setLen(a.digits.len - 1)
if a.digits.len == 0:
a.sign = 0
elif a.sign == 0:
a.sign = 1
proc big*(x: int): BigInt =
if x == 0:
return BigInt(sign: 0)
var v = abs(x)
result.sign = if x < 0: -1 else: 1
while v > 0:
result.digits.add(uint32(v mod int(BASE)))
v = v div int(BASE)
proc parse*(s: string): BigInt =
var str = s
result.sign = 1
if str[0] == '-':
result.sign = -1
str = str[1..^1]
for i in countdown(str.len, 1, BASE_DIGITS):
let start = max(0, i - BASE_DIGITS)
let chunk = parseInt(str[start..<i])
result.digits.add(uint32(chunk))
result.normalize()
proc cmp(a, b: BigInt): int =
if a.digits.len != b.digits.len:
return cmp(a.digits.len, b.digits.len)
for i in countdown(a.digits.len - 1, 0):
if a.digits[i] != b.digits[i]:
return cmp(a.digits[i], b.digits[i])
return 0
proc `==`*(a, b: BigInt): bool =
a.sign == b.sign and a.digits == b.digits
proc add(a, b: BigInt): BigInt =
var carry: uint64 = 0
let n = max(a.digits.len, b.digits.len)
result.digits = newSeq[uint32](n)
for i in 0..<n:
var x = carry
if i < a.digits.len: x += a.digits[i]
if i < b.digits.len: x += b.digits[i]
result.digits[i] = uint32(x mod BASE)
carry = x div BASE
if carry > 0:
result.digits.add(uint32(carry))
result.sign = 1
result.normalize()
proc sub(a, b: BigInt): BigInt =
var borrow: int64 = 0
result.digits = newSeq[uint32](a.digits.len)
for i in 0..<a.digits.len:
var x = int64(a.digits[i]) - borrow
if i < b.digits.len:
x -= int64(b.digits[i])
if x < 0:
x += int64(BASE)
borrow = 1
else:
borrow = 0
result.digits[i] = uint32(x)
result.sign = 1
result.normalize()
proc `+`*(a, b: BigInt): BigInt =
if a.sign == 0: return b
if b.sign == 0: return a
if a.sign == b.sign:
result = add(a, b)
result.sign = a.sign
else:
let c = cmp(a, b)
if c == 0:
return BigInt(sign: 0)
if c > 0:
result = sub(a, b)
result.sign = a.sign
else:
result = sub(b, a)
result.sign = b.sign
proc `-`*(a, b: BigInt): BigInt =
var nb = b
nb.sign *= -1
a + nb
proc `*`*(a, b: BigInt): BigInt =
if a.sign == 0 or b.sign == 0:
return BigInt(sign: 0)
result.digits = newSeq[uint32](a.digits.len + b.digits.len)
for i in 0..<a.digits.len:
var carry: uint64 = 0
for j in 0..<b.digits.len:
let k = i + j
var cur =
uint64(result.digits[k]) +
uint64(a.digits[i]) * uint64(b.digits[j]) +
carry
result.digits[k] = uint32(cur mod BASE)
carry = cur div BASE
var pos = i + b.digits.len
while carry > 0:
let cur = uint64(result.digits[pos]) + carry
result.digits[pos] = uint32(cur mod BASE)
carry = cur div BASE
inc pos
result.sign = a.sign * b.sign
result.normalize()
proc `$`*(a: BigInt): string =
if a.sign == 0:
return "0"
var parts: seq[string]
for d in a.digits:
parts.add($d)
result = parts[^1]
for i in countdown(parts.len - 2, 0):
result.add(parts[i].align(BASE_DIGITS, '0'))
if a.sign < 0:
result = "-" & result
when isMainModule:
let a = parse("123456789123456789123456789")
let b = parse("987654321987654321987654321")
echo "a = ", a
echo "b = ", b
echo "a + b = ", a + b
echo "a * b = ", a * b