'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 ^real@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) !