requires: {}. provides: {#Magnitude. #Number. #Integer. #Fraction. #Float. #Complex. #Infinity. #Epsilon}. prototypes addDelegate: #numerics valued: Namespace clone. x@(Number traits) ~= y@(Number traits) [ (x = y) not ]. n@(Number traits) negated "The argument's additive inverse." [ 0 - n ]. n@(Number traits) isZero "This method tests for zero and as a protocol is actually generic." [ n = n zero ]. n@(Number traits) zero "This method returns the zero element for the numeric type." [ 0 ]. n@(Float traits) zero "This method returns the zero element for the numeric type." [ 0.0 ]. n@(Number traits) isPositive "Whether it's positive." [ n > 0 ]. n@(Number traits) isNegative "Whether it's negative." [ n < 0 ]. n@(Number traits) abs "The absolute value." [ n < 0 ifTrue: [n negated] ifFalse: [n] ]. n@(Number traits) sign "Answers 1 for positive, -1 for negative, 0 for zero." [ n isZero ifTrue: [0] ifFalse: [n isPositive ifTrue: [1] ifFalse: [-1]] ]. n@(Number traits) squared [ n * n ]. n@(Integer traits) succ "Answer the Integer's successor." [n + 1]. n@(Integer traits) pred "Answer the Integer's predecessor." [n - 1]. n@(Integer traits) factorial "The standard recursive definition." [ n <= 1 ifTrue: [1] ifFalse: [n * ((n - 1) factorial)] ]. x@(Integer traits) gcd: y@(Integer traits) "Euclid's algorithm for finding the greatest common denominator." [| n m | n: x. m: y. [n isZero] whileFalse: [n: m \\ (m: n)]. m abs ]. x@(Number traits) mod: y@(Number traits) "Find the modulus (remainder) of a pair of numbers. Floats will return a non- Integer difference." [ x - ((x quo: y) * y) ]. x@(Number traits) \\ y@(Number traits) "Syntax sugar for modulus." [ x mod: y ]. x@(Number traits) truncated [ x quo: 1 ]. x@(Integer traits) truncated [ x ]. x@(Number traits) fractionPart [ x - x truncated ]. x@(Float traits) fractionPart [ resend as: x ]. x@(Number traits) quo: y@(Number traits) "Division rounded towards zero." [ (x / y) truncated ]. "Implementation-defined." "x@(Integer traits) quo: y@(Integer traits) [| ng quo | ng: x isPositive /\ y isPositive. ]." x@(Number traits) rem: y@(Number traits) [ x - (x // y * y) ]. "x@(Integer traits) / y@(Integer traits) [ (x mod: y) isZero ifTrue: [x quo: y] ifFalse: [(Fraction clone numerator: x denominator: y) reduced] ]." x@(Number traits) reciprocal "Return the multiplicative inverse." [ x isZero ifTrue: [] ifFalse: [1 / x] ]. x@(Number traits) max: y@(Number traits) "Return the greater argument." [ x > y ifTrue: [x] ifFalse: [y] ]. x@(Number traits) min: y@(Number traits) "Return the lesser argument." [ x < y ifTrue: [x] ifFalse: [y] ]. x@(Integer traits) / y@(Integer traits) "Create and reduce a new Fraction for the pair." [ (Fraction clone numerator: x denominator: y) reduced ]. x@(Integer traits) // y@(Integer traits) "Integer division." [| q | y isZero ifTrue: [error: 'Divide by zero.']. x isZero ifTrue: [^ 0]. q: (x quo: y). (q isNegative ifTrue: [q * y ~= x] ifFalse: [q isZero and: [x isNegative ~= y isNegative]]) ifTrue: [q - 1] ifFalse: [q] ]. x@(Integer traits) lcm: y@(Integer traits) "Find the least common multiple of the pair." [ x // (x gcd: y) * y ]. n@(Integer traits) hashMultiply "A copying of Squeak's hash-multiplier. TODO: To Be Replaced." [| low28 low14 | low28: (n bitAnd: 268435455). low14: (low28 bitAnd: 16383). 9741 * low14 + ((9741 * (low28 bitShift: -14) + (101 * low14) bitAnd: 16383) * 16384) bitAnd: 268435455 ]. " n@(Number traits) printOn: s [ n print ]. " numerics addSlot: #Fraction valued: (Number deriveWith: {Cloneable traits}). Fraction addSlot: #numerator. Fraction addSlot: #denominator. "Fractions obviously represent reduced ratios of Integers. They are not unique objects per value, however, and they are lazily reduced." x@(Fraction traits) numerator: numer@(Integer traits) denominator: denom@(Integer traits) "Initialize the Fraction." [ x numerator: numer. x denominator: denom. x ]. x@(Fraction traits) printOn: s "Print out a representation of the Fraction." [ x numerator printOn: s. s ; ' / '. x denominator printOn: s. x ]. x@(Fraction traits) + y@(Integer traits) "Addition of an Integer to a Fraction." [ Fraction clone numerator: x numerator + (y * x denominator) denominator: x denominator ]. x@(Fraction traits) truncated "The nearest lesser Integer to the Fraction." [ x numerator quo: x denominator ]. x@(Integer traits) + y@(Fraction traits) "Use commutativity to rely on Fraction + Integer." [ y + x ]. x@(Integer traits) - y@(Fraction traits) "Use commutativity to rely on Fraction + Integer." [ y negated + x ]. x@(Fraction traits) - y@(Number traits) "Use Fraction + Integer." [ x + y negated ]. x@(Fraction traits) * y@(Fraction traits) [| xn xd yn yd d1 d2 | d1: ((xn: x numerator) gcd: (yd: y denominator)). d2: ((xd: x denominator) gcd: (yn: y numerator)). ((d2 = xd and: [d1 = yd]) ifTrue: [xn // d1 * yn // d2] ifFalse: [Fraction clone numerator: xn // d1 * (yn // d2) denominator: xd // d2 * (yd // d2)]) ]. x@(Fraction traits) + y@(Fraction traits) [| n d d1 d2| d: (x denominator gcd: y denominator). n: (x numerator * (d1: y denominator // d) + (y numerator * (d2: x denominator // d))). d1: d1 * d2. n: n // (d2: (n gcd: d)). (d: d1 * (d // d2)) = 1 ifTrue: [^ n]. Fraction clone numerator: n denominator: d ]. x@(Fraction traits) reduced [| gcd numer denom | x numerator isZero ifTrue: [^ 0]. gcd: (x numerator abs gcd: x denominator). numer: x numerator // gcd. denom: x denominator // gcd. denom = 1 ifTrue: [^ numer]. Fraction clone numerator: numer denominator: denom ]. x@(Fraction traits) negated [ Fraction clone numerator: x numerator negated denominator: x denominator ]. x@(Fraction traits) reciprocal [| numer | numer: x numerator. numer isZero ifTrue: [^ Nil]. numer = 1 ifTrue: [^ x denominator]. numer = -1 ifTrue: [^ x denominator negated]. Fraction clone numerator: x denominator denominator: numer ]. numerics addSlot: #Magnitude valued: Cloneable derive. Number addDelegate: #parent2 valued: Magnitude. x@(Magnitude traits) <= y@(Magnitude traits) [ (y < x) not ]. x@(Magnitude traits) >= y@(Magnitude traits) [ (x < y) not ]. x@(Magnitude traits) > y@(Magnitude traits) [ y < x ]. x@(Magnitude traits) between: min@(Magnitude traits) and: max@(Magnitude traits) "Return whether the first argument is between the other two." [ x >= min and: [x <= max] ]. x@(Magnitude traits) min: y@(Magnitude traits) "Return the lesser argument." [ x < y ifTrue: [x] ifFalse: [y] ]. x@(Magnitude traits) max: y@(Magnitude traits) "Return the greater argument." [ x > y ifTrue: [x] ifFalse: [y] ]. x@(Magnitude traits) min: y@(Magnitude traits) max: z@(Magnitude traits) [ (x min: y) max: z ]. numerics addSlot: #LargeUnbounded valued: Magnitude clone. "A quantity which is unbounded but still a Number: as-large-as-you-like. It's definitely not an infinity." x@(Magnitude traits) < _@LargeUnbounded [True]. _@LargeUnbounded < _@LargeUnbounded [False]. numerics addSlot: #PositiveInfinity valued: Magnitude clone. x@(Magnitude traits) < pi@PositiveInfinity [ pi ~= x ]. pi@PositiveInfinity * x [ x isZero ifTrue: [^ x]. x isNegative ifTrue: [pi negated] ifFalse: [pi] ]. _@PositiveInfinity printOn: s [ s ; 'positive infinity' ]. numerics addSlot: #NegativeInfinity valued: Magnitude clone. ni@NegativeInfinity < x@(Magnitude traits) [ ni ~= x ]. ni@NegativeInfinity * x [ x isZero ifTrue: [^ x]. x isNegative ifTrue: [ni negated] ifFalse: [ni] ]. _@NegativeInfinity printOn: s [ s ; 'negative infinity' ]. _@PositiveInfinity negated [NegativeInfinity]. _@NegativeInfinity negated [PositiveInfinity]. _ - pi@PositiveInfinity [ pi negated ]. _ - ni@NegativeInfinity [ ni negated ]. numerics addSlot: #PositiveEpsilon valued: Magnitude clone. "The reciprocal of PositiveInfinity." pe@PositiveEpsilon = x [pe == x]. _@PositiveEpsilon isZero [False]. _@PositiveEpsilon isPositive [True]. _@(Magnitude traits) / _@PositiveInfinity [ PositiveEpsilon ]. _@(Magnitude traits) / _@PositiveEpsilon [ PositiveInfinity ]. _@(Magnitude traits) * pe@PositiveEpsilon [pe]. x@(Magnitude traits) + _@PositiveEpsilon [x]. _@PositiveEpsilon as: x@(Magnitude traits) [ 0.0 as: x ]. numerics addSlot: #NegativeEpsilon valued: Magnitude clone. "The reciprocal of NegativeInfinity." ne@NegativeEpsilon = x [ne == x]. _@NegativeEpsilon isZero [False]. _@NegativeEpsilon isNegative [True]. _@(Magnitude traits) / _@NegativeInfinity [ NegativeEpsilon ]. _@(Magnitude traits) / _@NegativeEpsilon [ NegativeInfinity ]. _@(Magnitude traits) * ne@NegativeEpsilon [ne]. x@(Magnitude traits) + _@NegativeEpsilon [x]. _@NegativeEpsilon as: x@(Magnitude traits) [ -0.0 as: x ]. _@PositiveEpsilon negated [NegativeEpsilon]. _@NegativeEpsilon negated [PositiveEpsilon]. numerics addSlot: #Complex valued: Magnitude derive. "Represents a complex number, having a real and imaginary part, which should not be altered per instance." Complex addSlot: #real valued: 0. "The real component." Complex addSlot: #imaginary valued: 0. "The imaginary component." c1@(Complex traits) = c2@(Complex traits) [ c1 real = c2 real and: [c1 imaginary = c2 imaginary] ]. c@(Complex traits) = n@(Magnitude traits) [ c imaginary isZero and: [c real = n] ]. c@(Complex traits) hash [ c real hash bitXor: c imaginary hash ]. c@(Complex traits) real: real imaginary: imaginary [| newC | newC: c clone. newC real: real. newC imaginary: imaginary. newC ]. x@(Magnitude traits) as: c@(Complex traits) "Creates the corresponding complex number for the value, using a corresponding zero coordinate." [ c real: x imaginary: x zero ]. c@(Complex traits) as: x@(Magnitude traits) "Converts to a number if possible, but returns itself otherwise." [ c imaginary isZero ifTrue: [c real] ifFalse: [c] ]. c@(Complex traits) unit [ 1 as: c ]. c@(Complex traits) zero [ 0 as: c ]. c@(Complex traits) isZero [ c real isZero and: [c imaginary isZero] ]. c@(Complex traits) sign "Returns a complex number of unit dimensions in the same quandrant." [ c real: c real sign imaginary: c imaginary sign ]. c@(Complex traits) radius [ (c real squared + c imaginary squared) sqrt ]. c@(Complex traits) abs "The magnitude of the complex as a vector." [ c radius ]. c@(Complex traits) < x [ error: 'Complex numbers are not linearly-ordered.' ]. numerics addSlot: #I valued: (Complex real: 0 imaginary: -1). "The square root of -1." c@(Complex traits) * _@I "The complex number multiplied by -1 sqrt." [ c real: c imaginary negated imaginary: c real ]. c@(Complex traits) theta "The angle between the complex coordinates and the positive real-axis." [ c real isZero ifTrue: [c imaginary isPositive ifTrue: [Pi / 2] ifFalse: [Pi * 3 / 2]] ifFalse: [| tan result | tan: c imaginary / c real. result: tan arcTan. c real isPositive ifTrue: [theta] ifFalse: [Pi + result]] ]. c@(Complex traits) conjugated "Returns the complex conjugate." [ c real: c real imaginary: c imaginary negated ]. c1@(Complex traits) + c2@(Complex traits) [ c1 real: c1 real + c2 real imaginary: c1 imaginary + c2 imaginary ]. c1@(Complex traits) - c2@(Complex traits) [ c1 real: c1 real - c2 real imaginary: c1 imaginary - c2 imaginary ]. c1@(Complex traits) * c2@(Complex traits) [ c1 real: c2 real - (c1 imaginary * c2 imaginary) imaginary: c1 real * c2 imaginary + (c1 imaginary * c2 real) ]. c1@(Complex traits) / c2@(Complex traits) [| denom | denom: c2 real squared + c2 imaginary squared. c1 real: c1 real * c2 real + (c1 imaginary * c2 imaginary) / denom imaginary: c2 real * c1 imaginary - (c2 imaginary * c1 real) / denom ]. c@(Complex traits) sqrt [| r | (c imaginary isZero and: [c real isNegative not]) ifTrue: [^ c real sqrt]. c real: (r: (c radius - c real / 2) sqrt) imaginary: c imaginary / 2 / r ]. c@(Complex traits) exp [| zero im | zero: ((c real zero + c imaginary zero) as: Real). im: (zero as: c imaginary). (zero as: c real) exp * (im cos + (im sin * i)) ]. c@(Complex traits) ln [ c real: c radius ln imaginary: c theta ]. c@(Complex traits) cos [ (c * I) exp + (c * I) negated exp / 2 ]. c@(Complex traits) sin [ (c * I) exp - (c * I) negated exp / 2 ]. c@(Complex traits) tan [ c sin / c cos ]. c@(Complex traits) raisedTo: n [ (n isZero or: [n = 1]) ifTrue: [^ c]. n isNegative ifTrue: [^ (c raisedTo: n negated) reciprocal]. (n * c ln) exp ]. c@(Complex traits) printOn: s [ s nextPut: $(. c real printOn: s. s ; ' + '. c imaginary printOn: s. s ; ' i)'. s ]. "Implicit coercions from Integer to Float." x@(Integer traits) * y@(Float traits) [ (x as: Float) * y ]. x@(Float traits) * y@(Integer traits) [ x * (y as: Float) ]. x@(Integer traits) + y@(Float traits) [ (x as: Float) + y ]. x@(Float traits) + y@(Integer traits) [ x + (y as: Float) ]. x@(Integer traits) - y@(Float traits) [ (x as: Float) - y ]. x@(Float traits) - y@(Integer traits) [ x - (y as: Float) ]. x@(Integer traits) / y@(Float traits) [ (x as: Float) / y ]. x@(Float traits) / y@(Integer traits) [ x / (y as: Float) ].