1 prototypes define: #BigInteger
2 &parents: {Integer. CoercibleNumberMixin. ByteArray}
4 &slots: {#isNegative -> False.}.
5 "An unlimited-precision Integer abstraction, stored in bytes."
6 "Ensure that newSize:, size, at:, and at:put: are appropriately inherited."
8 BigInteger traits level ::= 1.
9 "Level of the number type for coercion purposes."
11 BigInteger traits DigitBitSize ::= 8.
12 "The number of bits in a BigInteger digit.
13 NOTE: This should really only be used at compile-time."
15 i@(Integer traits) intoByte [i bitAnd: 16rFF].
16 i@(Integer traits) byteShift: n [i bitShift: n * 8].
17 i@(Integer traits) endianByteAt: n [(i byteShift: n negated) intoByte].
19 array@(Sequence traits) as: int@(Integer traits) &bigEndian: bigEndian &radix: radix
21 bigEndian `defaultsTo: lobby isLittleEndian not.
22 radix `defaultsTo: 256.
26 ifTrue: [array size - 1 downTo: 0 do:
27 [| :i | result := (array at: i) * position + result. position *= radix]]
28 ifFalse: [0 below: array size do:
29 [| :i | result := (array at: i) * position + result. position *= radix]].
33 i@(Integer traits) leastGreaterPowerOfTwo
36 [power < i] whileTrue: [power := power << 1].
40 i@(BigInteger traits) lastDigit
43 i@(BigInteger traits) isPositive
44 [(i isNegative \/ [i isZero]) not].
46 i@(BigInteger traits) isZero
47 [i size = 1 /\ [i lastDigit isZero]].
49 x@(SmallInteger traits) as: i@(BigInteger traits)
51 result ::= i newSize: x highBit // 8 + 1.
57 carry := (carry byteShift: -1) + (x bitXor: 16rFF) intoByte.
58 result at: index put: carry intoByte.
59 x := x byteShift: -1]]
63 result at: index put: x intoByte.
64 x := x byteShift: -1]].
65 result isNegative := x isNegative.
69 x@(BigInteger traits) canBeASmallInteger
70 "Answer whether the BigInteger is of a quantity that can fit into a SmallInteger."
71 [x between: SmallInteger minimumValue and: SmallInteger maximumValue].
73 x@(BigInteger traits) as: i@(SmallInteger traits)
76 ifFalse: [error: 'The integer is too large to be a SmallInteger.'].
83 n += (digit negated byteShift: shift).
88 n += (digit byteShift: shift).
93 i@(BigInteger traits) digitSize
96 i@(BigInteger traits) hash
99 i do: [| :digit | result := result bitXor: digit].
103 i1@(BigInteger traits) <=> i2@(BigInteger traits)
104 "Answer the sign of the comparison of the two arguments. It works by comparing
105 number of digits, then highest-to-lowest."
107 (size1 ::= i1 digitSize) < (size2 ::= i2 digitSize) ifTrue: [^ -1].
108 size2 < size1 ifTrue: [^ 1].
109 size1 - 1 downTo: 0 do:
111 (digit2 := (i2 at: index)) = (digit1 := i1 at: index)
112 ifFalse: [digit1 < digit2 ifTrue: [^ -1] ifFalse: [^ 1]]].
116 i1@(BigInteger traits) < i2@(BigInteger traits)
118 i1 isNegative == i2 isNegative
120 [i1 <=> i2 = (i1 isNegative ifTrue: [1] ifFalse: [-1])]
121 ifFalse: [i1 isNegative]
124 i1@(BigInteger traits) = i2@(BigInteger traits)
126 i1 isNegative == i2 isNegative /\ [i1 <=> i2 = 0]
129 i@(BigInteger traits) negated
131 i copy `>> [isNegative := i isNegative not. ]
134 source@(BigInteger traits) copyInto: target@(BigInteger traits)
136 0 below: (source digitSize min: target digitSize)
137 do: [| :index | target at: index put: (source at: index)].
141 i@(BigInteger traits) grownTo: newSize
143 i copyInto: (i newSize: newSize)
146 i@(BigInteger traits) grownBy: n
148 i grownTo: i digitSize + n
151 i@(BigInteger traits) shrunkToFit
152 "Check for leading zeroes and return a trimmed copy."
154 (i indexOfLastSatisfying: [| :digit | digit ~= 0])
158 (result := nonZero + 1 = i size
160 ifFalse: [i grownTo: nonZero + 1]) canBeASmallInteger
161 ifTrue: [result as: SmallInteger]
165 i@(Integer traits) shrunkToFit
166 "Works like BigInteger shrunkToFit."
169 i1@(BigInteger traits) logicallyCombineWith: i2@(BigInteger traits) by: logicOp
170 "Collects the logical (2s-complement) combination, as described by logicOp,
171 of a BigInteger with another and returns the collected BigInteger result,
172 shrunken to the smallest applicable size."
173 [| bigger smaller a b c x y z |
175 ifTrue: [smaller := i1. bigger := i2]
176 ifFalse: [smaller := i2. bigger := i1].
177 (result ::= bigger newSize: bigger size + 1) isNegative :=
179 applyWith: (smaller isNegative ifTrue: [1] ifFalse: [0])
180 with: (bigger isNegative ifTrue: [1] ifFalse: [0])) = 1.
186 x := index < smaller size ifTrue: [smaller at: index] ifFalse: [0].
189 [a := (a byteShift: -1) + (x bitXor: 16rFF).
191 y := bigger at: index.
194 [b := (b byteShift: -1) + (y bitXor: 16rFF).
196 z := logicOp applyWith: x with: y.
199 [c := (c byteShift: -1) + (z bitXor: 16rFF).
201 result at: index put: z].
202 x := smaller isNegative ifTrue: [16rFF] ifFalse: [0].
203 y := bigger isNegative ifTrue: [16rFF] ifFalse: [0].
204 z := logicOp applyWith: x with: y.
207 [c := (c byteShift: -1) + (z bitXor: 16rFF).
209 result at: bigger size put: z.
213 i1@(BigInteger traits) bitOr: i2@(BigInteger traits)
215 i1 logicallyCombineWith: i2 by: #bitOr:`er
218 i1@(BigInteger traits) bitAnd: i2@(BigInteger traits)
220 i1 logicallyCombineWith: i2 by: #bitAnd:`er
223 i1@(BigInteger traits) bitXor: i2@(BigInteger traits)
225 i1 logicallyCombineWith: i2 by: #bitXor:`er
228 i1@(BigInteger traits) add: i2@(BigInteger traits)
229 [| bigger smaller carry sum |
231 ifTrue: [smaller := i1. bigger := i2]
232 ifFalse: [smaller := i2. bigger := i1].
234 sum := i1 new &capacity: bigger size. "Sum gets the same sign as i1."
235 0 below: smaller size
237 carry := (carry byteShift: -1)
238 + (smaller at: index) + (bigger at: index).
239 sum at: index put: carry intoByte].
240 smaller size below: bigger size do:
242 carry := (carry byteShift: -1)
243 + (bigger at: index).
244 sum at: index put: carry intoByte].
246 ifTrue: [sum := sum grownBy: 1.
247 sum at: sum size - 1 put: 1].
251 i1@(BigInteger traits) subtract: i2@(BigInteger traits)
252 [| bigger smaller diff borrow |
254 ifTrue: [smaller := i1. bigger := i2]
255 ifFalse: [smaller := i2. bigger := i1].
257 diff := bigger newSameSize.
258 diff isNegative := i1 isNegative xor: i1 == smaller.
259 0 below: smaller size
261 borrow := (borrow byteShift: -1)
262 + (bigger at: index) - (smaller at: index).
263 diff at: index put: borrow intoByte].
264 smaller size below: bigger size do:
266 borrow := (borrow byteShift: -1)
267 + (bigger at: index).
268 diff at: index put: borrow intoByte].
272 i1@(BigInteger traits) + i2@(BigInteger traits)
273 [i1 isNegative = i2 isNegative
275 ifFalse: [i1 subtract: i2]
278 i1@(BigInteger traits) - i2@(BigInteger traits)
279 [i1 isNegative = i2 isNegative
280 ifTrue: [i1 subtract: i2]
281 ifFalse: [i1 add: i2]
284 i1@(BigInteger traits) * i2@(BigInteger traits)
286 i1 isZero \/ [i2 isZero] ifTrue: [^ 0].
287 result ::= i1 new &capacity: (i1 highBit + i2 highBit + 1) // 8 + 1.
288 result isNegative := i1 isNegative xor: i2 isNegative.
294 carry := (carry byteShift: -1) + (each2 * each1) + (result at: index1 + index2).
295 result at: index1 + index2 put: carry intoByte].
298 [result at: index1 + i2 size put: (carry byteShift: -1)]].
302 i@(BigInteger traits) highBit
303 "Answer the index of the high-order bit of the argument, or zero if it is zero."
305 (i digitSize - 1) * 8 + i lastDigit highBit
308 i@(BigInteger traits) lowBit
309 "Answer the index of the low-order bit of the argument, or zero if it is zero."
315 [(i at: index) isZero]
316 whileTrue: [index += 1].
317 (i at: index) lowBit + (8 * index)]
320 i1@(BigInteger traits) add: i2 scaledBy: q at: offset
325 carry := (carry byteShift: -1) + (i1 at: offset) + (digit * q).
326 i1 at: offset put: carry intoByte.
331 [carry := (carry byteShift: -1) + (i1 at: offset).
332 i1 at: offset put: carry intoByte.
337 i1@(BigInteger traits) subtract: i2 at: offset
342 borrow := (borrow byteShift: -1) + (i1 at: offset) - digit.
343 i1 at: offset put: borrow intoByte.
348 [borrow := (borrow byteShift: -1) + (i1 at: offset).
349 i1 at: offset put: borrow intoByte].
353 i@(BigInteger traits) twosComplement
358 carry := (carry byteShift: -1) + (digit bitXor: 16rFF).
359 i at: index put: carry intoByte
364 i1@(BigInteger traits) quoRem: i2@(BigInteger traits)
365 [| quoRem d shift q lastD quo rem |
372 shift := 7 - (i2 highBit bitAnd: 7).
373 quoRem := i1 new &capacity: i1 size + 2.
374 i1 bitShift: shift into: quoRem.
376 i2 bitShift: shift into: d.
377 lastD := d lastDigit.
382 q := quoRem at: index.
385 ifFalse: [(q byteShift: 1) + (quoRem at: index - 1) quo: lastD].
386 quoRem add: d scaledBy: q at: index - d size.
387 [(quoRem at: index) = q]
389 [quoRem subtract: d at: index - d size.
391 quo := i1 new &capacity: quoRem size - d size.
392 quo isNegative := i1 isNegative xor: i2 isNegative.
393 quoRem bitShift: d size * -8 into: quo.
394 rem := i2 newSameSize.
395 quoRem at: d size put: 0.
396 quoRem bitShift: shift negated into: rem.
397 { quo shrunkToFit. rem shrunkToFit }
400 i1@(BigInteger traits) / i2@(BigInteger traits)
402 (quoRem ::= i1 quoRem: i2) second isZero "No remainder."
403 ifTrue: [quoRem first]
404 ifFalse: [resend] "Make a fraction."
407 i1@(BigInteger traits) quo: i2@(BigInteger traits)
409 (i1 quoRem: i2) first
412 _@(SmallInteger traits) quo: _@(BigInteger traits)
417 i1@(BigInteger traits) quo: i2@(SmallInteger traits)
420 ifTrue: [i1 divideByZero]
421 ifFalse: [i1 quo: (i2 as: BigInteger)]
424 i1@(BigInteger traits) rem: i2@(BigInteger traits)
426 (i1 quoRem: i2) second
429 r@(SmallInteger traits) rem: _@(BigInteger traits)
434 i1@(BigInteger traits) rem: i2@(SmallInteger traits)
437 ifTrue: [i1 divideByZero]
438 ifFalse: [i1 rem: (i2 as: BigInteger)]
441 i1@(BigInteger traits) quoRem: i2@(SmallInteger traits)
444 ifTrue: [i1 divideByZero]
445 ifFalse: [i1 quoRem: (i2 as: BigInteger)]
448 i@(BigInteger traits) bitShift: n into: result
452 carry := n isNegative /\ [offset isPositive] /\ [-1 - source < i size]
453 ifTrue: [(i at: -1 - source) bitShift: offset]
455 limit ::= i size min: result size - source.
456 (source negated max: 0) below: limit
458 carry := (carry byteShift: -1) + ((i at: index) bitShift: offset).
459 result at: index + source put: carry intoByte].
460 carry > 16rFF /\ [limit + source < result size]
461 ifTrue: [result at: limit + source put: (carry byteShift: -1)].
465 i@(BigInteger traits) bitShift: n@(SmallInteger traits)
467 i isZero \/ [n isZero] ifTrue: [^ i].
468 result ::= i new &capacity: (i highBit + n // 8 max: 0) + 1.
469 i bitShift: n into: result.
470 i isNegative /\ [i lowBit < n negated]
472 ifFalse: [result shrunkToFit]
475 x@(Integer traits) raisedTo: y mod: n
476 "Answer the modular exponential. Originally by Jesse Welton (?)."
484 [(s *= t) >= n ifTrue: [s := s \\ n]].
485 (t *= t) >= n ifTrue: [t := t \\ n].
486 u := u bitShift: -1].
490 x@(Integer traits) isCongruentWith: y@(Integer traits) mod: n
491 "This is a straight interpretation of equivalence via modulus.
492 The selector is ternary because our grammar can't use 'n' as an adverb."
497 i@(Integer traits) as: a@(BitArray traits)
498 "Returns a BitArray initialized from the integer"
500 (BitArray new &capacity: i highBit + 2) `>> [| :newA |
501 keysDo: [| :index | newA at: index put: (i >> index bitAnd: 1) isZero not].