Q: What is the difference between a neurotic and a psychotic?
A: A psychotic really thinks 2+2 = 5
   A neurotic knows 2+2 = 4, but just can't stand it.   ;^)

I really can't stand some of the oddities of Complex numbers in Squeak
[Note Mantis bug 311 -- http://bugs.squeak.org/view.php?id=3311].

I would find the following to be more rational:

3 asComplex.                        "no change--> (3+0i)"
3 asComplex isNumber.       "no change--> true"
-1 asComplex < 1 asComplex. "--> true"
-4 sqrt.        "--> 2.0i"
-3 ln.  "--> (1.098612288668382+3.141592653589793i)"
((1/2) + 2.1i) sin arcSin. "--> (0.500000000000001+2.1i)"
((((1/2) + 2.1i) sin  arcSin)  roundTo: 0.000001) = ((1/2) + 2.1i). "--> true"
((((1/2) + 2.1i) tanH arcTanH) roundTo: 0.000001) = ((1/2) + 2.1i). "--> true"

Attached is a change set which adds a number of tests for Complex and the 
changes for Complex which allow those tests to pass in Pharo1.0beta update: 
#10413.  Note that Complex becomes a subclass of Magnitude.

I thought it would be useful to post the code first for your thoughts and any 
code cleanups.  As an occasional Smalltalk user, you may wish to correct some 
of my idioms.  Please forgive an old newbie.

Thanks in advance,
-KenD     [[email protected]]

PS:  Yes this is MIT.  I signed and sent in the copyright form..
'From Pharo1.0beta of 16 May 2008 [Latest update: #10411] on 11 August 2009 at 
4:17:57 pm'!
Magnitude subclass: #Complex
        instanceVariableNames: 'real imaginary'
        classVariableNames: ''
        poolDictionaries: ''
        category: 'Kernel-Numbers'!

!Complex methodsFor: 'accessing' stamp: 'KenD 8/9/2009 10:03'!
imag
        "Convenience alias for #imaginary"
        ^ imaginary! !

!Complex methodsFor: 'arithmetic' stamp: 'KenD 8/9/2009 14:52'!
< other
        "self < other if other's real-part is to the right or the real-parts 
are equal and the oher's imaginary part is larger"
        | otherCpx |
        otherCpx := other asComplex.
        ^self real < otherCpx real
                        or: [self real = otherCpx real  and: [self imag < 
otherCpx imag]]! !

!Complex methodsFor: 'arithmetic' stamp: 'KenD 8/10/2009 15:29'!
conjugate

        ^ Complex real: real imaginary: (imaginary negated)! !

!Complex methodsFor: 'arithmetic' stamp: 'KenD 8/10/2009 15:22'!
inverse

        ^(self / (self norm))! !

!Complex methodsFor: 'arithmetic' stamp: 'KenD 8/10/2009 15:32'!
norm

        ^(self * (self conjugate))! !

!Complex methodsFor: 'converting' stamp: 'KenD 8/9/2009 19:13'!
adaptToPoint: rcvr andSend: selector
        "If I am involved in arithmetic with a Point, convert me to a Point."
        ^ rcvr perform: selector with: (self asPoint)! !

!Complex methodsFor: 'converting' stamp: 'KenD 8/9/2009 14:49'!
asComplex
        ^self! !

!Complex methodsFor: 'converting' stamp: 'KenD 8/9/2009 19:14'!
asPoint
        ^r...@imaginary! !

!Complex methodsFor: 'converting' stamp: 'KenD 8/10/2009 15:59'!
asString

   ((imaginary = 0) | (imaginary = nil))
          ifTrue: [ ^ real ifNil: ['0'] ifNotNil: [real asString]]
          ifFalse: [
                ((real = 0) | (real = nil))
                ifTrue: [ ^ (imaginary asString), 'i']
                ifFalse: [ ^ '(' , (real asString) , ' + ' , (imaginary 
asString) , 'i)'].
          ].! !

!Complex methodsFor: 'mathematical functions' stamp: 'KenD 8/9/2009 19:16'!
angle
        "Answer my angle in radians"
        ^ ((imaginary / real) arcTan)! !

!Complex methodsFor: 'mathematical functions' stamp: 'KenD 8/9/2009 20:49'!
arcCos
        ^(((Float pi)/2) - (self arcSin))! !

!Complex methodsFor: 'mathematical functions' stamp: 'KenD 8/10/2009 15:44'!
arcCosH
        | x y az az2 hairy |
        x := real asFloat.
        y := imaginary asFloat.
   az := (self abs).
        az2 := az squared.
   hairy := ((((az2 - 1) squared) + (4 * y * y)) sqrt).

        ^Complex real: (1/2 * ((hairy + az2) arcCosH))
            imaginary: (1/2 * (y signum) 
                        * ((Float pi) - ((x signum) * ((hairy - az2) 
arcCos))))! !

!Complex methodsFor: 'mathematical functions' stamp: 'KenD 8/10/2009 15:44'!
arcSin
        | x y az az2 hairy |
        x := real.
        y := imaginary.
   az := (self abs).
        az2 := az squared.
   hairy := ((((az2 - 1) squared) + (4 * y * y)) sqrt).

        ^Complex real: ((1/2) * (x signum) * ((hairy - az2) arcCos))
           imaginary: ((1/2) * (y signum) * ((hairy + az2) arcCosH))! !

!Complex methodsFor: 'mathematical functions' stamp: 'KenD 8/9/2009 19:39'!
arcSinH

        ^(self + ((1 + (self squared)) sqrt)) ln! !

!Complex methodsFor: 'mathematical functions' stamp: 'KenD 8/10/2009 16:06'!
arcTan

        | x y |
        x := real.
        y := imaginary.
        ^Complex real: (1/2 * 
                                        ((x ~= 0) 
                                                ifTrue: [(2 * x) arcTan: (1 - 
((self abs) squared))]
                                                ifFalse: [ 
                                                        ((y abs) > 1)
                                                        ifTrue: [(Float pi) * 
(x signum)]
                                                        ifFalse: [0].
                                                ])
                                        )
           imaginary: (1/2 * (((2 * y) / (1 + ((self abs) squared))) 
arcTanH)).! !

!Complex methodsFor: 'mathematical functions' stamp: 'KenD 8/10/2009 17:13'!
arcTanH
        | x y az2 |
        x := real.
        y := imaginary.
        az2 := (self abs) squared.

        ^ Complex real: (1/2 * (((2 * x) / (1 + az2)) arcTanH))
            imaginary: (1/2 * 
                                        ((y ~= 0) 
                                        ifTrue: [(2 * y) arcTan: (1 - az2)]
                                        ifFalse: [
                                                ((x abs) > 1)
                                                ifTrue: [((Float pi) negated) * 
(x signum)]
                                                ifFalse: [0]
                                        ]))! !

!Complex methodsFor: 'mathematical functions' stamp: 'KenD 8/10/2009 15:50'!
cos
        "Answer receiver's cosine."
"       | x y |
        x := real.
        y := imaginary.
        ^ Complex real: ((x cos) * (y cosH))
                imaginary: (((x sin) * (y sinH)) negated)"
        | iself |
        iself := 1 i * self.
        ^ (iself exp + iself negated exp) / 2! !

!Complex methodsFor: 'mathematical functions' stamp: 'KenD 8/10/2009 16:10'!
cosH
        "Answer receiver's hyperbolic cosine."

        | x y |
        x := real asFloat.
        y := imaginary asFloat.
        ^ Complex real: ((x cosH) * (y cos)) 
                imaginary: ((x sinH) * (y sin))
        "^ (self exp + self negated exp) / 2"! !

!Complex methodsFor: 'mathematical functions' stamp: 'KenD 8/9/2009 19:22'!
cotH
        "Answer the hyperbolic cotangent of the receiver taken as an angle in 
radians."

        ^ ( (self exp) + ((self negated) exp) ) / ( (self exp) - ((self 
negated) exp) )! !

!Complex methodsFor: 'mathematical functions' stamp: 'KenD 8/9/2009 19:23'!
cscH
        "Answer the hyperbolic cosecant of the receiver taken as an angle in 
radians."

        ^ 2 / ( (self exp) - ((self negated) exp) ) ! !

!Complex methodsFor: 'mathematical functions' stamp: 'KenD 8/9/2009 16:40'!
exp
        "Answer the exponential of the receiver."
        | x y e2x |
        x := real.
        y := imaginary.
        e2x := x exp.
        ^ (Complex real: (e2x * (y cos)) imaginary: (e2x * (y sin)))! !

!Complex methodsFor: 'mathematical functions' stamp: 'KenD 8/9/2009 18:42'!
ln
" See Mantis bug-1815
        | x y |
        x := real.
        y := imaginary.
        ^ (Complex real: ( 1/2 * ((((self abs) squared) asFloat) ln) )
             imaginary: (y arcTan: x))"
        ^ self abs ln + (1 i * self arg)! !

!Complex methodsFor: 'mathematical functions' stamp: 'KenD 8/9/2009 19:17'!
magnitude
        "answer my magnitude (length from self as point to origin"
        ^self abs! !

!Complex methodsFor: 'mathematical functions' stamp: 'KenD 8/9/2009 19:23'!
secH
        "Answer the hyperbolic secant of the receiver taken as an angle in 
radians."

        ^ 2 / ( (self exp) + ((self negated) exp) ) ! !

!Complex methodsFor: 'mathematical functions' stamp: 'KenD 8/10/2009 15:11'!
sinH
         "Answer the hyperbolic sine of the receiver taken as an angle in 
radians."

        "^ (self exp - self negated exp) / 2"
        | x y |
        x := real asFloat.
        y := imaginary asFloat.
        ^ Complex real: ((x sinH) * (y cos))
                imaginary: ((x cosH) * (y sin))! !

!Complex methodsFor: 'mathematical functions' stamp: 'KenD 8/9/2009 15:01'!
sqrt
        | az |
        az := self abs.
        ^Complex real: (((az + real) / 2) sqrt) 
           imaginary: ((imaginary signum) * (((az - real) / 2) sqrt))! !

!Complex methodsFor: 'mathematical functions' stamp: 'KenD 8/9/2009 19:10'!
squared
        "Answer the receiver multipled by itself."
"       | x y |
        x := real.
        y := imaginary.
        ^ Complex real: ((x + y) * (x - y))
             imaginary: (2 * x * y)"
        ^self * self! !

!Complex methodsFor: 'mathematical functions' stamp: 'KenD 8/10/2009 15:54'!
tan
        "Answer receivers tangent."
        | x2 y2 |
        x2 := (real * 2).
        y2 := (imaginary * 2).
        ^Complex real: ((x2 sin) / ((x2 cos) + (y2 cosH)))
           imaginary: ((y2 tanH) / (1 + ((x2 cos) / (y2 cosH))))
        "^ self sin / self cos"! !

!Complex methodsFor: 'mathematical functions' stamp: 'KenD 8/9/2009 19:11'!
tanH
        | x2 y2 |
        x2 := (real * 2) asFloat.
        y2 := (imaginary * 2) asFloat.
        ^ Complex real: ((x2 tanH) / (1 + ((y2 cos)/(x2 cosH))))
            imaginary: ((y2 sin) / ((x2 cosH) + (y2 cos)))! !

!Complex methodsFor: 'printing' stamp: 'KenD 8/9/2009 16:17'!
printOn: aStream
        (real = 0)
        ifTrue: [
                imaginary printOn: aStream.
                aStream nextPut: $i]
        ifFalse: [
                aStream nextPut: $(.
                real printOn: aStream.
                (imaginary < 0)
                        ifFalse:  [aStream nextPut: $+].
                imaginary printOn: aStream.
                aStream nextPut: $i.
                aStream nextPut: $) ]
! !

!Complex methodsFor: 'private' stamp: 'KenD 8/9/2009 16:21'!
signum
        "NB: signum(0) is 1 [required]"
        | za |
        za := self abs.
        (za = 0)
        ifTrue: [^ real signum]
        ifFalse: [^self / za]! !

!Complex methodsFor: 'truncation and rounding' stamp: 'KenD 8/9/2009 19:20'!
ceiling
        "distribute"
        ^Complex real: (real ceiling) imaginary: (imaginary ceiling)! !

!Complex methodsFor: 'truncation and rounding' stamp: 'KenD 8/9/2009 19:20'!
floor
        "distribute"
        ^Complex real: (real floor) imaginary: (imaginary floor)! !

!Complex methodsFor: 'truncation and rounding' stamp: 'KenD 8/9/2009 19:20'!
reduce
        "distribute"
        ^Complex real: (real reduce) imaginary: (imaginary reduce)! !

!Complex methodsFor: 'truncation and rounding' stamp: 'KenD 8/9/2009 16:29'!
roundTo: quantum
        "distribute."

        ^Complex real: (real roundTo: quantum) 
                          imaginary: (imaginary roundTo: quantum)! !

!Complex methodsFor: 'truncation and rounding' stamp: 'KenD 8/9/2009 16:35'!
roundUpTo: quantum
        "distribute."

        ^Complex real: (real roundUpTo: quantum) 
                          imaginary: (imaginary roundUpTo: quantum)! !

!Complex methodsFor: 'truncation and rounding' stamp: 'KenD 8/9/2009 16:37'!
truncateTo: aNumber
        "distribute."

        ^Complex real: (real truncateTo: aNumber) 
                          imaginary: (imaginary truncateTo: aNumber)! !

!Complex methodsFor: 'truncation and rounding' stamp: 'KenD 8/9/2009 16:36'!
truncated
        "distribute."

        ^Complex real: (real truncated) 
                          imaginary: (imaginary truncated)! !


!Complex class methodsFor: 'deprecated' stamp: 'KenD 8/10/2009 15:20'!
quickCheck: aStream

"Expected Result
================================
Sample Complex usage:
 3.2i prints as: 3.2i
     a = ((1/2) + 2.1i)
     b = ((3/4) + 5.7i)
 a + b = ((5/4) + 7.8i)
 a - b = ((-1/4) + -3.6i)
 a * b = (-11.595 + 4.425i)
 a * 3 = (1.5 + 6.3i)
 3 * b = (2.25 + 17.1i)
 a / b = (0.373497 + -0.038575i)
 a / 3 = (0.166667 + 0.7i)
 3 / b = (0.0680735 + -0.517359i)
sin(a) = (1.98689 + 3.52951i)
cos(a) = (3.63698 + -1.92818i)
tan(a) = (0.0248288 + 0.983615i)
 ln(3) = 1.09861
ln(-3) = (1.09861 + 3.14159i)
 ln(a) = (0.769508 + 1.33705i)
exp(3) = 20.0855
exp(a) = (-0.832351 + 1.42319i)
conjugate(a) = ((1/2) + -2.1i)
  inverse(a) = (0.107296 + 0.450644i)
     norm(a) = 4.66
asin(sin(a)) = (0.5 + 2.1i)
acos(cos(a)) = (0.5 + 2.1i)
atan(tan(a)) = (0.5 + 2.1i)
  abs(a - b) = 3.60867
 norm(a - b) = 13.0225
     sinh(a) = (-0.263073 + 0.973377i)
     cosh(a) = (-0.569278 + 0.449814i)
     tanh(a) = (1.11624 + -0.827849i)
asinh(sinh(a)) = (-0.5 + 1.04159i)
acosh(cosh(a)) = (0.5 + 2.1i)
atanh(tanh(a)) = (0.5 + 2.1i)
"

        | a b |
        aStream cr.
        aStream show: 'Sample Complex usage:'.
        aStream cr.
        aStream show: ' 3.2i prints as: ' , (3.2i asString).

        a := Complex real: 1/2 imaginary: 2.1 .
        b := Complex real: 3/4 imaginary: 5.7 .

        aStream cr.
        aStream show: '     a = ' , (a asString).
        aStream cr.
        aStream show: '     b = ' , (b asString).
        aStream cr.
        aStream show: ' a + b = ' , ((a + b) asString).
        aStream cr.
        aStream show: ' a - b = ' , ((a - b) asString).
        aStream cr.
        aStream show: ' a * b = ' , ((a * b) asString).
        aStream cr.
        aStream show: ' a * 3 = ' , ((a * 3) asString).
        aStream cr.
        aStream show: ' 3 * b = ' , ((3 * b) asString).
        aStream cr.
        aStream show: ' a / b = ' , ((a / b) asString).
        aStream cr.
        aStream show: ' a / 3 = ' , ((a / 3) asString).
        aStream cr.
        aStream show: ' 3 / b = ' , ((3 / b) asString).

        aStream cr.
        aStream show: 'sin(a) = ' , ((a sin) asString).
        aStream cr.
        aStream show: 'cos(a) = ' , ((a cos) asString).
        aStream cr.
        aStream show: 'tan(a) = ' , ((a tan) asString).

        aStream cr.
        aStream show: ' ln(3) = ' , ((3 ln) asString).
        aStream cr.
        aStream show: 'ln(-3) = ' , ((-3 ln) asString).
        aStream cr.
        aStream show: ' ln(a) = ' , ((a ln) asString).
        aStream cr.
        aStream show: 'exp(3) = ' , ((3 exp) asString).
        aStream cr.
        aStream show: 'exp(a) = ' , ((a exp) asString).

        aStream cr.
        aStream show: 'conjugate(a) = ' , ((a conjugate) asString).
        aStream cr.
        aStream show: '  inverse(a) = ' , ((a inverse) asString).
        aStream cr.
        aStream show: '     norm(a) = ' , ((a norm) asString).

        aStream cr.
        aStream show: 'asin(sin(a)) = ' , (((a sin) arcSin) asString).
        aStream cr.
        aStream show: 'acos(cos(a)) = ' , (((a cos) arcCos) asString).
        aStream cr.
        aStream show: 'atan(tan(a)) = ' , (((a tan) arcTan) asString).

        aStream cr.
        aStream show: '  abs(a - b) = ' , (((a - b) abs) asString).
        aStream cr.
        aStream show: ' norm(a - b) = ' , (((a - b) norm) asString).

        aStream cr.
        aStream show: '     sinh(a) = ' , ((a sinH) asString).
        aStream cr.
        aStream show: '     cosh(a) = ' , ((a cosH) asString).
        aStream cr.
        aStream show: '     tanh(a) = ' , ((a tanH) asString).
        aStream cr.
        aStream show: 'asinh(sinh(a)) = ' , (((a sinH) arcSinH) asString).
        aStream cr.
        aStream show: 'acosh(cosh(a)) = ' , (((a cosH) arcCosH) asString).
        aStream cr.
        aStream show: 'atanh(tanh(a)) = ' , (((a tanH) arcTanH) asString).
        aStream cr.
        aStream show: ''
! !


!ComplexTest methodsFor: 'tests' stamp: 'KenD 8/11/2009 14:52'!
testCompare
   "Anything along either the real or imaginary number line should compare 
sanely"
        self assert: (-1i < 1i).
        self assert: (-1 asComplex < 1 asComplex).
        "Kinda silly if the following did not work"
        self assert: (1 + -1i) < (1 + 1i).! !

!ComplexTest methodsFor: 'tests' stamp: 'KenD 8/9/2009 14:54'!
testConversion
        "self run: #testConversion"
        "self debug: #testConversion"
        
        self assert: ((1 + 2i) + 1) =  (2 + 2 i).
        self assert: (1 + (1 + 2i)) =  (2 + 2 i).
        self assert: ((1 + 2i) + 1.0) =  (2.0 + 2 i).
        self assert: (1.0 + (1 + 2i)) =  (2.0 + 2 i).
        self assert: ((1 + 2i) + (2/3)) = ((5/3) + 2 i ).
        self assert: ((2/3) + (1 + 2i)) = ((5/3) + 2 i ).
        self assert: (1 + 0i) = 1 asComplex.! !

!ComplexTest methodsFor: 'tests' stamp: 'KenD 8/9/2009 19:27'!
testExpLn
        "self run: #testMath"

        | a epsilon |
        a := ((1/2) + 2.1i).
        epsilon := 0.00001.
        "Because of rounding, the following do not compare exactly."
        self assert: ((3 ln)  roundTo: epsilon) = (1.09861 roundTo: epsilon).
        self assert: ((-3 ln) roundTo: epsilon) = ((1.09861 + 3.14159i) 
roundTo: epsilon).
        self assert: ((a ln)  roundTo: epsilon) = ((0.769508 + 1.33705i) 
roundTo: epsilon).
        self assert: ((3 exp) roundTo: epsilon) = (20.08553692318767 roundTo: 
epsilon).
        self assert: ((a exp) roundTo: epsilon) 
                        = ((-0.832350511083887 + 1.423191643861584i) roundTo: 
epsilon).
! !

!ComplexTest methodsFor: 'tests' stamp: 'KenD 8/11/2009 13:56'!
testHyperbolicMath
        | a epsilon |
        a := ((1/2) + 2.1i).
        epsilon := 0.00001.
        "Because of rounding, the following do not compare exactly."
        self assert: ((a sinH) roundTo: epsilon) = ((-0.263073 + 0.973377i) 
roundTo: epsilon).
        self assert: ((a cosH) roundTo: epsilon) = ((-0.569278 + 0.449814i) 
roundTo: epsilon).
        self assert: ((a tanH) roundTo: epsilon) = ((1.11624 + -0.827849i) 
roundTo: epsilon).
        self assert: ((a sinH arcSinH) roundTo: epsilon)  "bogus, but same as 
Chez Scheme"
                        = ((-0.5 + 1.041592653589793i) roundTo: epsilon).
        self assert: ((a cosH arcCosH) roundTo: epsilon)  = a.
        self assert: ((a tanH arcTanH) roundTo: epsilon) = a.
! !

!ComplexTest methodsFor: 'tests' stamp: 'KenD 8/9/2009 14:52'!
testLess
        self assert: ((1 negated asComplex) < (1 asComplex)).
        self assert: (((1 negated)i) < (1i)).! !

!ComplexTest methodsFor: 'tests' stamp: 'KenD 8/11/2009 14:51'!
testMath

        | a b epsilon |
        a := ((1/2) + 2.1i).
    b := ((3/4) + 5.7i).
        epsilon := 0.00001.
        "Because of rounding, the following do not compare exactly."
        self assert: ((a + b) roundTo: epsilon) = (((5/4) + 7.8i) roundTo: 
epsilon).
        self assert: ((a - b) roundTo: epsilon) = (((-1/4) + -3.6i) roundTo: 
epsilon).
        self assert: ((a * b) roundTo: epsilon) = ((-11.595 + 4.425i) roundTo: 
epsilon).
        self assert: ((a * 3) roundTo: epsilon) = ((1.5 + 6.3i) roundTo: 
epsilon).
        self assert: ((3 * b) roundTo: epsilon) = ((2.25 + 17.1i) roundTo: 
epsilon).
        self assert: ((a / b) roundTo: epsilon) 
                        = ((0.3734967097798956 + -0.0385749943272067i) roundTo: 
epsilon).
        self assert: ((a / 3) roundTo: epsilon) 
                        = ((0.1666666666666666 + 0.7i) roundTo: epsilon).
        self assert: ((3 / b) roundTo: epsilon)
                         = ((0.068073519400953 -0.517358747447243i) roundTo: 
epsilon).

! !

!ComplexTest methodsFor: 'tests' stamp: 'KenD 8/9/2009 16:22'!
testPrivate
        self assert: (0 signum = 1).
        self assert: (-3 signum = -1).
        self assert: (3 signum = 1).
        self assert: (2 asComplex signum) = 1 asComplex.
        self assert: (0+0i signum = 1).! !

!ComplexTest methodsFor: 'tests' stamp: 'KenD 8/9/2009 10:39'!
testSqrt
        self assert: (-4 sqrt) = (2.0i).! !

!ComplexTest methodsFor: 'tests' stamp: 'KenD 8/11/2009 14:16'!
testTrig
        | a epsilon |
        a := ((1/2) + 2.1i).
        epsilon := 0.00001.
        "Because of rounding, the following do not compare exactly."
        self assert: ((a sin) roundTo: epsilon) 
                        = ((1.986889573868458 + 3.529511343338503i) roundTo: 
epsilon).
        self assert: ((a cos) roundTo: epsilon) 
                        = ((3.63698 + -1.92818i) roundTo: epsilon).
        self assert: ((a tan) roundTo: epsilon) = ((0.0248288 + 0.983615i) 
roundTo: epsilon).
        self assert: ((a sin arcSin) roundTo: epsilon) = a.
        self assert: ((a cos arcCos) roundTo: epsilon) = a.
        self assert: ((a tan arcTan) roundTo: epsilon) = a.
   self assert: (-1 arcCos) = (Float pi).
        self assert: (Float pi) cos = -1.0.
        self assert: (Float pi / 2) sin = 1.0.
        self assert: (((Float pi / 4) tan) roundTo: epsilon) = 1.0.
        self assert: (1 arcCos) = 0.0.
        self assert: (1 arcSin) = ((Float pi) / 2).
        self assert: (1 arcTan) = ((Float pi) / 4).
        self assert: (-1 arcCos) = (Float pi).
        ! !


!Number methodsFor: 'converting' stamp: 'KenD 8/9/2009 14:49'!
asComplex
        ^Complex real: self imaginary: 0! !

!Number methodsFor: 'mathematical functions' stamp: 'KenD 8/9/2009 19:29'!
log
        "Answer the base-10 log of the receiver."
        (self < 0)
        ifTrue: [ ^ (self asComplex) log: 10 ]
        ifFalse: [ ^self asFloat log ].! !

!Number methodsFor: 'mathematical functions' stamp: 'KenD 8/9/2009 20:58'!
sqrt
        "Answer the square root of the receiver."

        (self < 0)
        ifTrue: [^self asComplex sqrt]
        ifFalse: [^self asFloat sqrt]! !

!Number methodsFor: 'private' stamp: 'KenD 8/9/2009 15:03'!
signum
        "private For complex number implementation. NB: 0 signum -> 1"

        (self < 0)
                ifTrue: [ ^ -1 ]
                ifFalse: [ ^ 1 ].! !


!Float methodsFor: 'mathematical functions' stamp: 'KenD 8/9/2009 19:47'!
arcCosH
        "answer hyperbolic arc cosine of self"

        (self >= 1)
                ifTrue: [ ^ (self * (1 + ((1 - (1 / (self * self))) sqrt))) ln]
                ifFalse: [
                        ((self abs) <= 1)
                        ifTrue: [ ^ (((1 - (self * self)) sqrt) arcTan: self)i ]
                        ifFalse: [ ^ Complex real: ((self negated) arcCosH) 
                                                                  imaginary: 
(Float pi)].
                ].! !

!Float methodsFor: 'mathematical functions' stamp: 'KenD 8/9/2009 19:47'!
arcSinH
        "answer hyperbolic arc sine of self"

        ^(1/2 * (self signum) * ((1 + (self squared * 2)) arcCosH))! !

!Float methodsFor: 'mathematical functions' stamp: 'KenD 8/10/2009 17:16'!
arcTan: denominator
        "Answer the angle in radians.
         Optional. See Object documentation whatIsAPrimitive."

        | result |

        (self = 0.0) ifTrue: [ (denominator > 0.0) ifTrue: [ result := 0 ]
                                                                                
    ifFalse: [ result := Pi ]
                                                ]
                            ifFalse: [(denominator = 0.0)
                                        ifTrue: [ (self > 0.0) ifTrue: [ result 
:= Halfpi ]
                                                                                
                ifFalse: [ result := Halfpi negated ]
                                                        ]
                                        ifFalse: [ (denominator > 0) ifTrue: [ 
result := (self / denominator) arcTan ]
                                                                 ifFalse: [ 
result := ((self / denominator) arcTan) + Pi 
                                                                        "(self 
> 0) ifTrue: [result := ((self / denominator) arcTan) + Pi ]
                                                                                
                                        ifFalse: [result := ((self / 
denominator) arcTan) - Pi]"
                                                                                
        ]
                                                        ].
                                                ].
        
        ^ result
! !

!Float methodsFor: 'mathematical functions' stamp: 'KenD 8/9/2009 20:54'!
arcTanH
        "answer hyperbolic arc tangent of self"

        | az |
        az := self abs.
        (az < 1)
          ifTrue: [^ (1/2) * (((1 + self) / (1 - self)) ln)]
          ifFalse: [^ Complex real: ((1/self) arcTanH) 
                         imaginary: ((((Float pi)/2) * (self signum)) 
negated)].! !

!Float methodsFor: 'mathematical functions' stamp: 'KenD 8/9/2009 19:48'!
cosH
        "Answer the hyperbolic cosine of the receiver taken as an angle in 
radians."

        ^ ( (self exp) + ((self negated) exp) ) / 2
! !

!Float methodsFor: 'mathematical functions' stamp: 'KenD 8/9/2009 19:48'!
cotH
        "Answer the hyperbolic cotangent of the receiver taken as an angle in 
radians."

        ^ ( (self exp) + ((self negated) exp) ) / ( (self exp) - ((self 
negated) exp) ) ! !

!Float methodsFor: 'mathematical functions' stamp: 'KenD 8/9/2009 19:48'!
cscH
        "Answer the hyperbolic cosecant of the receiver taken as an angle in 
radians."

        ^ 2 / ( (self exp) - ((self negated) exp) )! !

!Float methodsFor: 'mathematical functions' stamp: 'KenD 8/9/2009 16:50'!
ln
        "Answer the natural logarithm of the receiver.
         PrimOp fails for complex case."

        (self <= 0.0)
                ifTrue: [^ self asComplex ln ]
                ifFalse: [^ self lnPrivate ].! !

!Float methodsFor: 'mathematical functions' stamp: 'KenD 8/9/2009 19:49'!
secH
        "Answer the hyperbolic secant of the receiver taken as an angle in 
radians."

        ^ 2 / ( (self exp) + ((self negated) exp) )! !

!Float methodsFor: 'mathematical functions' stamp: 'KenD 8/9/2009 19:49'!
sinH
        "Answer the hyperbolic sine of the receiver taken as an angle in 
radians."

        ^ ( (self exp) - ((self negated) exp) ) / 2! !

!Float methodsFor: 'mathematical functions' stamp: 'KenD 8/9/2009 21:23'!
tanH
        "Answer the hyperbolic tangent of the receiver taken as an angle in 
radians."

        ^ ( (self exp) - ((self negated) exp) ) / ( (self exp) + ((self 
negated) exp) ) ! !

!Float methodsFor: 'private' stamp: 'KenD 8/9/2009 16:50'!
lnPrivate
        "Answer the natural logarithm of the receiver.
         Optional. See Object documentation whatIsAPrimitive."

        | expt n mant x div pow delta sum eps |

        "Taylor series"
        self <= 0.0 ifTrue: [self error: 'ln is only defined for x > 0.0'].

        "get a rough estimate from binary exponent"
        expt := self exponent.
        n := Ln2 * expt.
        mant := self timesTwoPower: 0 - expt.

        "compute fine correction from mantinssa in Taylor series"
        "mant is in the range [0..2]"
        "we unroll the loop to avoid use of abs"
        x := mant - 1.0.
        div := 1.0.
        pow := delta := sum := x.
        x := x negated.  "x <= 0"
        eps := Epsilon * (n abs + 1.0).
        [delta > eps] whileTrue: [
                "pass one: delta is positive"
                div := div + 1.0.
                pow := pow * x.
                delta := pow / div.
                sum := sum + delta.
                "pass two: delta is negative"
                div := div + 1.0.
                pow := pow * x.
                delta := pow / div.
                sum := sum + delta].

        ^ n + sum

        "2.718284 ln 1.0"! !


!Point methodsFor: 'converting' stamp: 'KenD 8/10/2009 16:40'!
asComplex
        ^Complex real: x imaginary: y! !


!Float reorganize!
('arithmetic' * + - / abs negated reciprocal)
('comparing' < <= = > >= closeTo: hash ~=)
('converting' adaptToComplex:andSend: adaptToFraction:andCompare: 
adaptToFraction:andSend: adaptToInteger:andCompare: adaptToInteger:andSend: 
asApproximateFraction asApproximateFractionAtOrder: asComplex asFloat 
asFraction asIEEE32BitWord asTrueFraction degreesToRadians isInf 
radiansToDegrees)
('copying' deepCopy shallowCopy veryDeepCopyWith:)
('mathematical functions' arcCos arcCosH arcSin arcSinH arcTan arcTan: arcTanH 
cos cosH cotH cscH degreeCos degreeSin exp floorLog: ln log reciprocalFloorLog: 
reciprocalLogBase2 safeArcCos secH sin sinH sqrt tan tanH timesTwoPower:)
('printing' absByteEncode:base: absPrintExactlyOn:base: absPrintOn:base: 
byteEncode:base: hex printOn:base: printPaddedWith:to: 
printShowingDecimalPlaces: storeOn:base:)
('testing' hasContentsInExplorer isFinite isFloat isInfinite isLiteral isNaN 
isPowerOfTwo isZero sign)
('truncation and round off' exponent fractionPart integerPart predecessor 
reduce rounded significand significandAsInteger successor truncated)
('private' absPrintOn:base:digitCount: lnPrivate)
!


!Number reorganize!
('arithmetic' * + - / // \\ abs arg negated quo: reciprocal rem:)
('comparing' closeTo:)
('converting' @ adaptToCollection:andSend: adaptToFloat:andCompare: 
adaptToFloat:andSend: adaptToFraction:andSend: adaptToInteger:andSend: 
adaptToPoint:andSend: adaptToString:andSend: asB3DVector3 asComplex asDuration 
asFloatD asFloatE asFloatQ asInteger asNumber asPoint asScaledDecimal 
asScaledDecimal: asSmallAngleDegrees asSmallPositiveDegrees day days 
degreesToRadians hour hours i milliSecond milliSeconds minute minutes 
nanoSecond nanoSeconds radiansToDegrees second seconds sign: week weeks)
('filter streaming' byteEncode:)
('intervals' to: to:by: to:by:do: to:do:)
('mathematical functions' arcCos arcSin arcTan arcTan: cos degreeCos degreeSin 
exp floorLog: interpolateTo:at: ln log log: raisedTo: raisedToInteger: sin sqrt 
squared tan)
('printing' defaultLabelForInspector isOrAreStringWith: printOn: printOn:base: 
printShowingDecimalPlaces: printString printStringBase: storeOn: storeOn:base: 
storeStringBase: stringForReadout)
('testing' basicType even isDivisibleBy: isInf isInfinite isNaN isNumber isZero 
negative odd positive sign strictlyPositive)
('truncation and round off' ceiling detentBy:atMultiplesOf:snap: floor 
fractionPart integerPart reduce roundTo: roundUpTo: rounded truncateTo: 
truncated)
('private' signum)
!


!Complex class reorganize!
('instance creation' abs:arg: new real:imaginary:)
('deprecated' quickCheck:)
!

Complex removeSelector: #cosh!
Complex removeSelector: #imag:!
Complex removeSelector: #quickCheck:!
Complex removeSelector: #sinh!
Complex removeSelector: #truncate!

!Complex reorganize!
('accessing' imag imaginary real)
('arithmetic' * + - / < abs arg conjugate divideFastAndSecureBy: 
divideSecureBy: inverse negated norm reciprocal)
('comparing' = hash)
('converting' adaptToCollection:andSend: adaptToFloat:andSend: 
adaptToFraction:andSend: adaptToInteger:andSend: adaptToPoint:andSend: 
asComplex asPoint asString)
('mathematical functions' angle arcCos arcCosH arcSin arcSinH arcTan arcTanH 
cos cosH cotH cscH exp ln log: magnitude secH sin sinH sqrt squared tan tanH)
('printing' printOn:)
('testing' isComplex isNumber isZero)
('private' imaginary: real: signum)
('truncation and rounding' ceiling floor reduce roundTo: roundUpTo: truncateTo: 
truncated)
!

_______________________________________________
Pharo-project mailing list
[email protected]
http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project

Reply via email to