1
1
# # Arbitrary precision integers.
2
2
3
-
4
- import std/ [algorithm, bitops, math]
3
+ import std/ [algorithm, bitops, math, options]
5
4
6
5
type
7
6
BigInt* = object
@@ -73,6 +72,14 @@ func isZero(a: BigInt): bool {.inline.} =
73
72
return false
74
73
return true
75
74
75
+ func abs* (a: BigInt): BigInt =
76
+ # Returns the absolute value of `a`.
77
+ runnableExamples:
78
+ assert abs(42 .initBigInt) == 42 .initBigInt
79
+ assert abs(- 12 .initBigInt) == 12 .initBigInt
80
+ result = a
81
+ result .isNegative = false
82
+
76
83
func unsignedCmp(a: BigInt, b: uint32 ): int64 =
77
84
# ignores the sign of `a`
78
85
# `a` and `b` are assumed to not be zero
@@ -563,7 +570,7 @@ func `shl`*(x: BigInt, y: Natural): BigInt =
563
570
result .limbs.add(uint32 (carry shr (32 - b)))
564
571
565
572
# forward declaration for use in `shr`
566
- func dec* (a: var BigInt, b: int32 = 1 )
573
+ func dec* (a: var BigInt, b: int = 1 )
567
574
568
575
func `shr` * (x: BigInt, y: Natural): BigInt =
569
576
# # Shifts a `BigInt` to the right (arithmetically).
@@ -826,7 +833,7 @@ func `mod`*(a, b: BigInt): BigInt =
826
833
var tmp: BigInt
827
834
division(tmp, result , a, b)
828
835
829
- func ` divmod` * (a, b: BigInt): tuple [q, r: BigInt] =
836
+ func divmod* (a, b: BigInt): tuple [q, r: BigInt] =
830
837
# # Computes both the integer division and modulo (remainder) of two
831
838
# # `BigInt` numbers.
832
839
# # Raises a `DivByZeroDefect` if `b` is zero.
@@ -837,6 +844,92 @@ func `divmod`*(a, b: BigInt): tuple[q, r: BigInt] =
837
844
assert divmod(a, b) == (3 .initBigInt, 2 .initBigInt)
838
845
division(result .q, result .r, a, b)
839
846
847
+ func countTrailingZeroBits(a: BigInt): int =
848
+ var count = 0
849
+ for x in a.limbs:
850
+ if x == 0 :
851
+ count += 32
852
+ else :
853
+ return count + countTrailingZeroBits(x)
854
+ return count
855
+
856
+ func gcd* (a, b: BigInt): BigInt =
857
+ # # Returns the greatest common divisor (GCD) of `a` and `b`.
858
+ runnableExamples:
859
+ assert gcd(54 .initBigInt, 24 .initBigInt) == 6 .initBigInt
860
+
861
+ # binary GCD algorithm
862
+ var
863
+ u = abs(a)
864
+ v = abs(b)
865
+ if u.isZero:
866
+ return v
867
+ elif v.isZero:
868
+ return u
869
+ let
870
+ i = countTrailingZeroBits(u)
871
+ j = countTrailingZeroBits(v)
872
+ k = min(i, j)
873
+ u = u shr i
874
+ v = v shr j
875
+ while true :
876
+ # u and v are odd
877
+ if u > v:
878
+ swap(u, v)
879
+ v -= u
880
+ if v.isZero:
881
+ return u shl k
882
+ v = v shr countTrailingZeroBits(v)
883
+
884
+
885
+ func toSignedInt* [T: SomeSignedInt](x: BigInt): Option[T] =
886
+ ## Converts a `BigInt` number to signed integer, if possible.
887
+ ## If the `BigInt` doesn't fit in a `T`', returns `none`;
888
+ ## otherwise returns `some(T)`.
889
+ runnableExamples:
890
+ import std/options
891
+ let
892
+ a = 44.initBigInt
893
+ b = 130.initBigInt
894
+ assert toSignedInt[int8 ](a) == some(44'i8)
895
+ assert toSignedInt[int8 ](b) == none(int8 )
896
+ assert toSignedInt[int ](b) == some(130)
897
+
898
+ when sizeof(T) == 8:
899
+ if x.limbs.len > 2:
900
+ result = none(T)
901
+ elif x.limbs.len == 2:
902
+ if x.limbs[ 1] > uint32 .high shr 1 :
903
+ if x.isNegative and x.limbs[0 ] == 0 :
904
+ result = some(T(int64 .low))
905
+ else :
906
+ result = none(T)
907
+ else :
908
+ let value = T(x.limbs[1 ]) shl 32 + T(x.limbs[0 ])
909
+ if x.isNegative:
910
+ result = some(not (value - 1 ))
911
+ else :
912
+ result = some(value)
913
+ else :
914
+ if x.isNegative:
915
+ result = some(not T(x.limbs[0 ] - 1 ))
916
+ else :
917
+ result = some(T(x.limbs[0 ]))
918
+ else :
919
+ if x.limbs.len > 1 :
920
+ result = none(T)
921
+ else :
922
+ if x.isNegative:
923
+ if x.limbs[0 ] - 1 > uint32 (T.high):
924
+ result = none(T)
925
+ else :
926
+ result = some(not T(x.limbs[0 ] - 1 ))
927
+ else :
928
+ if x.limbs[0 ] > uint32 (T.high):
929
+ result = none(T)
930
+ else :
931
+ result = some(T(x.limbs[0 ]))
932
+
840
933
841
934
func calcSizes(): array [2 .. 36 , int ] =
842
935
for i in 2 .. 36 :
@@ -991,27 +1084,45 @@ func initBigInt*(str: string, base: range[2..36] = 10): BigInt =
991
1084
when (NimMajor , NimMinor ) >= (1 , 5 ):
992
1085
include bigints/ private/ literals
993
1086
994
- func inc* (a: var BigInt, b: int32 = 1 ) =
1087
+ func inc* (a: var BigInt, b: int = 1 ) =
995
1088
# # Increase the value of a `BigInt` by the specified amount (default: 1).
996
1089
runnableExamples:
997
1090
var a = 15 .initBigInt
998
1091
inc a
999
1092
assert a == 16 .initBigInt
1000
1093
inc(a, 7 )
1001
1094
assert a == 23 .initBigInt
1002
- var c = a
1003
- additionInt(a, c, b)
1004
1095
1005
- func dec* (a: var BigInt, b: int32 = 1 ) =
1096
+ if b in int32 .low.. int32 .high:
1097
+ var c = a
1098
+ additionInt(a, c, b.int32 )
1099
+ else :
1100
+ a += initBigInt(b)
1101
+
1102
+ func dec* (a: var BigInt, b: int = 1 ) =
1006
1103
# # Decrease the value of a `BigInt` by the specified amount (default: 1).
1007
1104
runnableExamples:
1008
1105
var a = 15 .initBigInt
1009
1106
dec a
1010
1107
assert a == 14 .initBigInt
1011
1108
dec(a, 5 )
1012
1109
assert a == 9 .initBigInt
1013
- var c = a
1014
- subtractionInt(a, c, b)
1110
+
1111
+ if b in int32 .low.. int32 .high:
1112
+ var c = a
1113
+ subtractionInt(a, c, b.int32 )
1114
+ else :
1115
+ a -= initBigInt(b)
1116
+
1117
+ func succ* (a: BigInt, b: int = 1 ): BigInt =
1118
+ # # Returns the `b`-th successor of a `BigInt`.
1119
+ result = a
1120
+ inc(result , b)
1121
+
1122
+ func pred* (a: BigInt, b: int = 1 ): BigInt =
1123
+ # # Returns the `b`-th predecessor of a `BigInt`.
1124
+ result = a
1125
+ dec(result , b)
1015
1126
1016
1127
1017
1128
iterator countup* (a, b: BigInt, step: int32 = 1 ): BigInt =
@@ -1041,3 +1152,63 @@ iterator `..<`*(a, b: BigInt): BigInt =
1041
1152
while res < b:
1042
1153
yield res
1043
1154
inc res
1155
+
1156
+ func invmod* (a, modulus: BigInt): BigInt =
1157
+ # # Compute the modular inverse of `a` modulo `modulus`.
1158
+ # # The return value is always in the range `[1, modulus-1]`
1159
+ runnableExamples:
1160
+ invmod(3 .initBigInt, 7 .initBigInt) = 5 .initBigInt
1161
+
1162
+ # extended Euclidean algorithm
1163
+ if modulus.isZero:
1164
+ raise newException(DivByZeroDefect, " modulus must be nonzero" )
1165
+ elif modulus.isNegative:
1166
+ raise newException(ValueError, " modulus must be strictly positive" )
1167
+ elif a.isZero:
1168
+ raise newException(DivByZeroDefect, " 0 has no modular inverse" )
1169
+ else :
1170
+ var
1171
+ r0 = ((a mod modulus) + modulus) mod modulus
1172
+ r1 = modulus
1173
+ s0 = one
1174
+ s1 = zero
1175
+ while r1 > 0 :
1176
+ let
1177
+ q = r0 div r1
1178
+ # the `q.isZero` check is needed because of an ARC/ORC bug (see https://github.com/nim-lang/bigints/issues/88)
1179
+ rk = if q.isZero: r0 else : r0 - q * r1
1180
+ sk = if q.isZero: s0 else : s0 - q * s1
1181
+ r0 = r1
1182
+ r1 = rk
1183
+ s0 = s1
1184
+ s1 = sk
1185
+ if r0 != one:
1186
+ raise newException(ValueError, $ a & " has no modular inverse modulo " & $ modulus)
1187
+ result = ((s0 mod modulus) + modulus) mod modulus
1188
+
1189
+ func powmod* (base, exponent, modulus: BigInt): BigInt =
1190
+ # # Compute modular exponentation of `base` with power `exponent` modulo `modulus`.
1191
+ # # The return value is always in the range `[0, modulus-1]`.
1192
+ runnableExamples:
1193
+ assert powmod(2 .initBigInt, 3 .initBigInt, 7 .initBigInt) == 1 .initBigInt
1194
+ if modulus.isZero:
1195
+ raise newException(DivByZeroDefect, " modulus must be nonzero" )
1196
+ elif modulus.isNegative:
1197
+ raise newException(ValueError, " modulus must be strictly positive" )
1198
+ elif modulus == 1 :
1199
+ return zero
1200
+ else :
1201
+ var
1202
+ base = base
1203
+ exponent = exponent
1204
+ if exponent < 0 :
1205
+ base = invmod(base, modulus)
1206
+ exponent = - exponent
1207
+ var
1208
+ basePow = ((base mod modulus) + modulus) mod modulus # Base stays in [0, m-1]
1209
+ result = one
1210
+ while not exponent.isZero:
1211
+ if (exponent.limbs[0 ] and 1 ) != 0 :
1212
+ result = (result * basePow) mod modulus
1213
+ basePow = (basePow * basePow) mod modulus
1214
+ exponent = exponent shr 1
0 commit comments