1 prototypes ensureNamespace: #numerics &delegate: True.
3 numerics define: #Number &parents: {Comparable}.
4 "A Number is a Comparable value upon which arithmetic operations may be performed."
9 n isNegative ifTrue: [n negated] ifFalse: [n]
12 n@(Number traits) negated
13 "The argument's additive inverse generically."
16 n@(Number traits) isZero
17 "This method tests for zero generically."
20 n@(Number traits) isPositive
21 "Whether it's positive generically."
24 n@(Number traits) isNegative
25 "Whether it's negative generically."
28 n@(Number traits) isUnit
29 "This method tests for one generically."
32 n@(Number traits) sign
33 "Answers 1 for positive, -1 for negative, 0 for zero."
37 ifFalse: [n isPositive ifTrue: [1] ifFalse: [-1]]
40 _@(Number traits) isInfinite [False].
42 n@(Number traits) zero
43 "This method returns the zero element for the numeric type.
44 So, n * n zero = n zero."
47 n@(Number traits) unit
48 "This method returns the unit element for the numeric type.
52 n@(Number traits) divideByZero
53 "The default handler for division by zero."
55 [(DivideByZero of: n) signal] handleWith: DivideByZero ReturnInput
58 numerics define: #CoercibleNumberMixin &parents: {Cloneable}.
59 "A CoercibleNumberMixin integrates a Number into the coercible tower of Numbers."
61 t@(CoercibleNumberMixin traits) level
66 numerics define: #Integer &parents: {Number. CoercibleNumberMixin}.
68 SmallInteger traitsWindow atSlotNamed: #traits1 put: Integer traits.
69 SmallInteger traitsWindow atSlotNamed: #traits2 put: Number traits.
70 SmallInteger traitsWindow atSlotNamed: #traits3 put: Comparable traits.
71 SmallInteger traitsWindow atSlotNamed: #traits4 put: CoercibleNumberMixin traits.
75 SmallInteger traitsWindow _delegates:
76 {CoercibleNumberMixin traits. Comparable traits. Number traits. Integer traits. SmallInteger traits}.
80 SmallInteger traits minimumValue ::= lobby smallIntegerMinimum.
81 SmallInteger traits maximumValue ::= lobby smallIntegerMaximum.
82 SmallInteger traits level ::= 0.
83 "Level of the number type for coercion purposes."
85 i@(SmallInteger traits) bitAt: n
86 [(i bitAnd: 1 << n) sign].
88 i@(SmallInteger traits) highBit
90 i = SmallInteger minimumValue
91 ifTrue: [^ (i bitNot highBit + 1)].
95 whileTrue: [bit += 1. n := n bitShift: -1].
99 x@(SmallInteger traits) bitShiftOverflow: y@(SmallInteger traits)
101 (x as: BigInteger) bitShift: y
104 x@(SmallInteger traits) addOverflow: y@(SmallInteger traits)
106 (x as: BigInteger) + (y as: BigInteger)
109 x@(SmallInteger traits) subtractOverflow: y@(SmallInteger traits)
111 (x as: BigInteger) - (y as: BigInteger)
114 x@(SmallInteger traits) multiplyOverflow: y@(SmallInteger traits)
116 (x as: BigInteger) * (y as: BigInteger)
119 numerics define: #Float &parents: {Number. CoercibleNumberMixin}.
121 n@(Float traits) zero
122 "This method returns the zero element for the numeric type.
123 So, n * n zero = n zero."
126 n@(Float traits) unit
127 "This method returns the unit element for the numeric type.
131 x@(Float traits) isNaN
132 "Simple, endianness-independent test for Not-a-Number."
135 f@(Float traits) as: _@(Float traits)
138 n@(Number traits) isNaN
139 "Compatibility with Float."
143 SingleFloat traitsWindow atSlotNamed: #traits1 put: Float traits.
144 SingleFloat traitsWindow atSlotNamed: #traits2 put: Number traits.
145 SingleFloat traitsWindow atSlotNamed: #traits3 put: Comparable traits.
146 SingleFloat traitsWindow atSlotNamed: #traits4 put: CoercibleNumberMixin traits.
149 SingleFloat traitsWindow _delegates:
150 {ByteArray traits. CoercibleNumberMixin traits. Comparable traits. Number traits. Float traits. SingleFloat traits}.
152 SingleFloat traits level ::= 3.
153 "Level of the number type for coercion purposes."
155 SingleFloat traits tolerance ::= 0.0001.
157 _@(Number traits) tolerance [0].
159 f@(SingleFloat traits) hash
161 f significand bitXor: f exponent
164 x@(Number traits) isCloseTo: y@(Number traits)
165 "Whether the two Floats are close to each other in value."
168 [x isZero] -> [y abs < y tolerance].
169 [y isZero] -> [x abs < x tolerance].
170 [x isNaN \/ [y isNaN]] -> [False]
171 ) otherwise: [(x - y) abs <= (x tolerance min: y tolerance)]
174 f@(SingleFloat traits) significandSize
179 f@(SingleFloat traits) exponentSize
184 f@(SingleFloat traits) bias
189 x@(Float traits) raisedTo: y@(Float traits)
190 "Implements floating-point exponentiation in terms of the natural logarithm
191 and exponential primitives - this is generally faster than the naive method."
194 [y isZero] -> [x unit].
195 [x isZero \/ [y isUnit]] -> [x]
196 ) otherwise: [(x ln * y) exp]
199 f@(Float traits) truncated
200 [| significand exponent n |
201 significand := f significand.
202 exponent := f exponent.
203 exponent = (f bias * 2 + 1) ifTrue:
204 [error: 'Can\'t coerce floating-point Inf or NaN to an integer.'].
205 exponent isZero ifTrue:
206 [^ (significand isZero
208 ifFalse: [f isNegative
212 significand := (1 bitShift: f significandSize) bitOr: significand.
213 n := significand bitShift: exponent - f significandSize.
219 f@(Float traits) as: _@(Integer traits)
224 i@(Integer traits) as: _@(Float traits)
225 [| f n length significand bits newF |
227 ifTrue: [^ SingleFloat zero].
228 " f := i highBit <= SingleFloat significandSize
229 ifTrue: [SingleFloat]
230 ifFalse: [DoubleFloat].
237 [error: 'Integer is too large to coerce to floating-point value.'].
239 ((n bitShift: f significandSize - length)
240 bitAnd: (1 bitShift: f significandSize) - 1).
241 newF := f withSignificand: significand exponent: length + f bias.
243 ifTrue: [newF negated]
248 numerics Pi ::= 3.141592654.
249 numerics E ::= 2.718281828.
251 n@(Number traits) squared
252 "The square of the number."
255 n@(Number traits) sqrt
256 "The square root of the number."
258 n isNegative ifTrue: [(n as: Complex) sqrt]
259 ifFalse: [n raisedTo: 1 / 2]
262 n@(Integer traits) succ
263 "Answer the Integer's successor."
266 n@(Integer traits) pred
267 "Answer the Integer's predecessor."
270 n@(Integer traits) factorial
271 "The standard recursive definition."
273 n isNegative ifTrue: [error: 'Negative inputs to factorial are invalid.'].
276 ifFalse: [n * ((n - 1) factorial)]
279 x@(Integer traits) gcd: y@(Integer traits)
280 "Euclid's algorithm for finding the greatest common divisor."
284 [n isZero] whileFalse: [temp := n. n := m \\ temp. m := temp].
288 x@(Number traits) quo: y@(Number traits)
289 "Division rounded towards zero."
294 x@(Number traits) rem: y@(Number traits)
295 "Find the modulus (remainder) of a pair of numbers. Floats will return a non-
301 x@(Number traits) quoRem: y@(Number traits)
302 "Calculate the quotient and the remainder, ideally at once, of x and y."
307 x@(Number traits) mod: y@(Number traits)
313 base@(Integer traits) raisedTo: expon mod: n
314 "Answer (base raisedTo: expon) mod: n, only more efficiently than that.
315 It works in the standard way, by square-and-multiply, expanding the
316 exponent into a sum of powers of 2, and factoring the base by this
320 ifTrue: [(base raisedTo: (expon negated) mod: n) inverseMod: n]
324 [expon isZero] whileFalse:
325 [[(expon mod: 2) isZero] whileTrue:
326 [expon := expon // 2.
327 base := base squared mod: n].
329 z := z * base mod: n]
333 m@(Integer traits) inverseMod: n@(Integer traits)
334 "Answer x such that (m * x) \\ n = 1."
337 [m isZero] whileFalse:
338 [q := n // m. m := n \\ (n := m). a := b - (q * (b := a))].
339 n ~= 1 ifTrue: [error: 'Integer does not have an inverse.'].
343 x@(Number traits) isEven
344 "Answer whether the Number is even; modulo tells us the remainder of division."
349 x@(Number traits) isOdd
350 "Odd numbers are those which are not even."
355 m@(Integer traits) isPrime
356 "Whether the Integer is evenly divisible by no other Integers than 1 and
359 m isEven ifTrue: [^ (m = 2)].
361 q := m - 1 bitShift: -1.
364 [q := q bitShift: -1.
366 25 timesRepeat: [(m isProbablyPrimeWithK: k andQ: q) ifFalse: [^ False]].
370 m@(Integer traits) isProbablyPrimeWithK: k andQ: q
371 "Algorithm P, probabilistic primality test, from
372 Knuth, Donald E. 'The Art of Computer Programming', Vol 2,
373 Third Edition, section 4.5.4, page 395."
375 x := (m - 2) atRandom + 1.
377 y := x raisedTo: q mod: m.
378 [(j isZero /\ [y isUnit] \/ [y + 1 = m]) ifTrue: [^ True].
379 j isPositive /\ [y isUnit] ifTrue: [^ False].
383 ifTrue: [y := y squared \\ m]
387 n@(Integer traits) primesDo: block
388 "Decomposes the Integer into primes, applying the block to each (in increasing
390 [| div next remaining |
394 [[(remaining \\ div) isZero]
397 remaining := remaining // div].
398 remaining = 1] whileFalse:
400 next += 2] "Just looks at the next odd integer."
403 x@(Number traits) truncated
404 "The greatest lesser Integer value."
407 x@(Integer traits) truncated
408 "Integers have no fractional part."
411 i@(Integer traits) as: _@(Integer traits)
412 "By default integers merely coerce to themselves."
416 "Define the natural logarithm in terms of the Float primitive."
419 x@(Number traits) log: base
420 "Define the logarithm-base-N in terms of natural logarithm ratios."
423 x@(Number traits) log10
426 x@(Number traits) exp
427 "Define E raisedTo: x in terms of the Float primitive."
430 x@(Number traits) ceiling
431 "The smallest greater Integer value."
433 trunc ::= x truncated.
434 x = trunc \/ [x isNegative]
439 x@(Number traits) floor
440 "The largest lesser Integer value."
442 trunc ::= x truncated.
443 x = trunc \/ [x isPositive]
448 x@(Integer traits) ceiling
449 "Integers have no fractional part."
452 x@(Integer traits) floor
453 "Integers have no fractional part."
456 i@(Integer traits) highBit
457 [(i ln / 2 ln) ceiling].
459 i@(Integer traits) lowBit
461 i = SmallInteger minimumValue
463 ifFalse: [(i bitXor: i - 1) highBit]
466 x@(Integer traits) << y@(Integer traits)
467 "Left-bit-shift by the given amount."
472 x@(Integer traits) >> y@(Integer traits)
473 "Right-bit-shift by the given amount."
475 x bitShift: y negated
478 x@(Integer traits) rounded
479 "Integers round to themselves."
482 x@(Float traits) rounded
483 "Answer the integer nearest to x."
486 x@(Number traits) roundTo: q@(Number traits)
487 "Answer the nearest number which is a multiple of q."
488 [(x / q) rounded * q].
490 x@(Number traits) fractionPart
491 "Return the difference between the integral part of the number and itself."
496 x@(Number traits) \\ y@(Number traits)
497 "Answer the remainder of dividing x by y."
502 x@(Number traits) reciprocal
503 "Answer the multiplicative inverse."
506 ifTrue: [x divideByZero]
507 ifFalse: [x unit / x]
510 x@(CoercibleNumberMixin traits) coerceTo: y@(CoercibleNumberMixin traits)
511 "Convert x to the same type as y, only in order of ascending level."
513 x level < y level ifTrue: [x as: y] ifFalse: [x]
516 "Generic arithmetic methods. These work by catching any arithmetic
517 operation with dissimilar types and converting the less generic type to
518 the more generic type. They then dispatch the converted arguments to the
519 method which handles that operation for matched types.
520 E.g. Float + Complex and Complex + Float will both dispatch to
522 x@(CoercibleNumberMixin traits) + y@(CoercibleNumberMixin traits) [(x coerceTo: y) + (y coerceTo: x)].
523 x@(CoercibleNumberMixin traits) - y@(CoercibleNumberMixin traits) [(x coerceTo: y) - (y coerceTo: x)].
524 x@(CoercibleNumberMixin traits) * y@(CoercibleNumberMixin traits) [(x coerceTo: y) * (y coerceTo: x)].
525 x@(CoercibleNumberMixin traits) / y@(CoercibleNumberMixin traits) [(x coerceTo: y) / (y coerceTo: x)].
526 x@(CoercibleNumberMixin traits) < y@(CoercibleNumberMixin traits) [(x coerceTo: y) < (y coerceTo: x)].
527 x@(CoercibleNumberMixin traits) = y@(CoercibleNumberMixin traits) [(x coerceTo: y) = (y coerceTo: x)].
529 x@(CoercibleNumberMixin traits) raisedTo: y@(CoercibleNumberMixin traits) [(x coerceTo: y) raisedTo: (y coerceTo: x)].
531 x@(CoercibleNumberMixin traits) bitAnd: y@(CoercibleNumberMixin traits) [(x coerceTo: y) bitAnd: (y coerceTo: x)].
532 x@(CoercibleNumberMixin traits) bitOr: y@(CoercibleNumberMixin traits) [(x coerceTo: y) bitOr: (y coerceTo: x)].
533 x@(CoercibleNumberMixin traits) bitXor: y@(CoercibleNumberMixin traits) [(x coerceTo: y) bitXor: (y coerceTo: x)].
535 x@(Integer traits) bitNot
540 x@(Integer traits) bitShift: y@(Integer traits)
542 (x * (2 raisedTo: y)) truncated
545 x@(Integer traits) // y@(Integer traits)
549 ifTrue: [x divideByZero]
552 (x isNegative xor: y isNegative) /\ [q * y ~= x]
557 x@(Integer traits) / y@(Integer traits)
558 "This is a provisional stub in case Fraction does not override it."
561 ifTrue: [x divideByZero]
565 ifFalse: [(Fraction newFor: x over: y) reduced]]
568 x@(Integer traits) lcm: y@(Integer traits)
569 "Find the least common multiple of the pair."
574 n@(Integer traits) taken: r@(Integer traits)
575 "Calculates the number of combinations of N elements taken R at a time.
576 It's zero outside of Pascal's triangle."
578 r isNegative \/ [r > n] ifTrue: [^ 0].
580 n above: (r max: n - r)
581 do: [| :factor | num *= factor].
584 do: [| :factor | denom *= factor].
588 n@(Integer traits) hashMultiply
589 "A copying of Squeak's hash-multiplier. TODO: To Be Replaced."
591 low28 ::= n bitAnd: 268435455.
592 low14 ::= low28 bitAnd: 16383.
593 9741 * low14 + ((9741 * (low28 bitShift: -14) + (101 * low14)
594 bitAnd: 16383) * 16384) bitAnd: 268435455
597 x@(Number traits) raisedTo: y@(Integer traits)
600 [y isZero] -> [x unit].
601 [x isZero \/ [y = 1]] -> [x].
603 -> "(x * x raisedTo: y // 2) * (x raisedTo: y \\ 2)"
606 [(count := count bitShift: 1) < y] whileTrue.
610 [result := result squared.
611 (y bitAnd: count) isZero ifFalse: [result *= x].
612 count := count bitShift: -1].
614 ) otherwise: [(x raisedTo: y negated) reciprocal]
617 numerics define: #UniqueNumber &parents: {Number}.
619 numerics LargeUnbounded ::= UniqueNumber clone.
620 "A quantity which is unbounded but still a Number: as-large-as-you-like. It's
621 definitely not an infinity."
623 x@(Comparable traits) < _@LargeUnbounded
626 _@LargeUnbounded < _@LargeUnbounded
629 numerics define: #Infinity &parents: {UniqueNumber}.
631 _@(Infinity traits) isInfinite [True].
633 inf@(Infinity traits) * x
639 ifTrue: [inf negated]
643 inf@(Infinity traits) + _@(Number traits)
646 _@(Number traits) + inf@(Infinity traits)
649 inf@(Infinity traits) - _@(Number traits)
652 _@(Number traits) - inf@(Infinity traits)
655 numerics PositiveInfinity ::= Infinity clone.
657 _@PositiveInfinity isInfinite [True].
659 x@(Comparable traits) < pi@PositiveInfinity
664 pi@PositiveInfinity < x@(Comparable traits)
667 _@PositiveInfinity printOn: s
669 s ; 'positive infinity'
672 numerics NegativeInfinity ::= Infinity clone.
674 ni@NegativeInfinity < x@(Comparable traits)
679 x@(Comparable traits) < pi@NegativeInfinity
682 _@NegativeInfinity printOn: s
684 s ; 'negative infinity'
687 _@PositiveInfinity negated
690 _@NegativeInfinity negated
693 numerics define: #Epsilon &parents: {UniqueNumber}.
695 x@(Epsilon traits) = y
698 _@(Epsilon traits) isZero
701 x@(Number traits) * y@(Epsilon traits)
711 x@(Epsilon traits) / y@(Number traits)
714 ifTrue: [x divideByZero]
721 x@(Number traits) / y@(Epsilon traits)
724 ifTrue: [y recriprocal negated]
725 ifFalse: [y recriprocal]
728 x@(Epsilon traits) * y@(Number traits)
731 x@(Number traits) + _@(Epsilon traits)
734 _@(Epsilon traits) + x@(Number traits)
737 x@(Number traits) - _@(Epsilon traits)
740 _@(Epsilon traits) - x@(Number traits)
743 numerics PositiveEpsilon ::= Epsilon clone.
744 "The reciprocal of PositiveInfinity."
746 _@PositiveEpsilon isPositive
749 _@PositiveInfinity reciprocal
752 _@PositiveEpsilon reciprocal
755 _@PositiveEpsilon as: x@(Number traits)
758 x@(Number traits) < _@PositiveEpsilon
763 _@PositiveEpsilon < x@(Number traits)
768 numerics NegativeEpsilon ::= Epsilon clone.
769 "The reciprocal of NegativeInfinity."
771 x@(Number traits) < _@NegativeEpsilon
776 _@NegativeEpsilon < x@(Number traits)
781 _@NegativeEpsilon isNegative
784 _@NegativeInfinity reciprocal
787 _@NegativeEpsilon reciprocal
790 _@NegativeEpsilon as: x@(Number traits)
795 _@PositiveEpsilon negated
798 _@NegativeEpsilon negated
801 "Yuck! This should be in dimensioned.slate but is here for now"
803 n@(Number traits) degreesToRadians
806 n@(Number traits) radiansToDegrees
809 n@(Number traits) readFrom: s
810 "Reads the first thing in the String (or Stream) as a Number.
811 An error is raised if the return type does not match the requested one.
812 Use as: if there is already a String whose full contents are exactly the
815 ((next ::= (Syntax Lexer newOn: s reader) readNumber value) is: n)
816 ifFalse: [error: 'The source did not parse into ' ; n printName asAn ; '.'].
820 n@(Integer traits) readFrom: s &radix
822 radix `defaultsTo: 10.
823 ((next ::= (Syntax Lexer newOn: s reader) readInteger: radix) is: n)
824 ifFalse: [error: 'The source did not parse into ' ; n printName asAn ; '.'].
828 "A portable way to represent floating point numbers without loss of precision
829 http://research.microsoft.com/~hollasch/cgindex/coding/portfloat.html
830 Would be useful in #storeOn: #loadFrom: for floats"
832 n@(Float traits) storeOn: s
833 "Stores a float in portable encoding"
836 n@(Float traits) loadFrom: s
837 "Loads a float in portable encoding"