-
Notifications
You must be signed in to change notification settings - Fork 0
/
bigint.nim
143 lines (104 loc) · 3.14 KB
/
bigint.nim
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
import unsigned
type
TBigIntDigit=uint32 #the type of a single big int digit
TBigIntDigits=seq[TBigIntDigit] #a sequence of digits used for a big integer
TLongDigit=uint64 #type that fits two big int digits multiplied
TBigInt* =object
digits:TBigIntDigits #posetive digits in base maxvalue(uint)+1
neg:bool #true if negative, false if zero or posetive
const
digitmask:TLongDigit=TLongDigit(0xffffffff)
superzero=TLongDigit(0)
superbase=TLongDigit(0x100000000)
maxdigit=TBigIntDigit(0xffffffff)
proc unsignedAdd(a,b:TBigIntDigits):TBigIntDigits=
## adds two sequences of digits, a must
## have more or equal digits as b
var numa=a.len
var numb=b.len
var numres=max(numa,numb) #number of digits in result, might possibly grow by one if carry left
newSeq(result,numres)
var carry:TLongDigit=0
for idx in 0.. <numres:
if idx<numa: carry=carry+a[idx]
if idx<numb: carry=carry+b[idx]
result[idx]=(TBigIntDigit(carry and digitmask))
carry=carry shr 32 #now the carry really is a carry for the next turn
if carry>superzero:
result.add(TBigIntDigit(carry))
proc unsignedSubtract(a,b:TBigIntDigits):TBigIntDigits=
## subtract a sequence with b,
## a must be >= b, so that the result is posetive
var numa=a.len
var numb=b.len
var adig,bdig:TBigIntDigit
var numres=max(numa,numb) #maximum number of digits in result
newSeq(result,numres)
var carry=false
for idx in 0.. <numres:
if idx<numa: adig=a[idx]
else: adig=0
if idx<numb: bdig=b[idx]
else:bdig=0
if carry:
if adig==0:
adig=maxdigit
carry=true
else:
dec adig
carry=false
carry=bdig>adig
result[idx]=adig-bdig
#TODO: raise exception if any carry left, which means b>a which is not allowed
#TODO: clean
proc `+` *(a,b:TBigInt):TBigInt=
result.digits=unsignedAdd(a.digits,b.digits)
result.neg=false
proc `-` *(a,b:TBigInt):TBigInt=
result.digits=unsignedSubtract(a.digits,b.digits)
result.neg=false
proc initBigInt*(val:int32):TBigInt=
result.digits = @[TBigIntDigit(abs(val))]
result.neg = (val<0)
proc initBigInt*(val:uint32):TBigInt=
result.digits = @[val]
result.neg = false
proc `$`(bi:TBigInt):string=
for a in bi.digits:
echo a
result =""
proc divide(bi:var TBigInt,n:TBigIntDigit):TLongDigit=
var tmp:TLongDigit=0
#TODO: handle division by zero
bi.neg=bi.neg and n>TBigIntDigit(0) or not bi.neg and n<TBigIntDigit(0)
for i in countdown(high(bi.digits),0):
tmp=tmp*65536
tmp=tmp or bi.digits[i]
bi.digits[i]=TBigIntDigit(tmp div n)
tmp=tmp-bi.digits[i]*n
# TODO: clean
result=tmp
#
#proc divide(bi:var TBigInt,n:TBigInt):TBigInt=
#
# #TODO: handle division by zero
#
#
# var tmp=initBigInt(0'i32)
# for i in countdown(high(bi.digits),0):
# tmp = tmp * 10
# tmp = tmp + digits[i]
# digits[i] = 0;
# while tmp>n:
# tmp=tmp-n
# inc bi.digits[n]
#
# #TODO: clean
# return tmp
#
when isMainModule:
var bi=initBigInt(uint32(10000))
echo bi
echo divide(bi,9)
echo bi
discard readline(stdin)