--- a/Complex.st Fri Jun 13 20:52:21 2003 +0200
+++ b/Complex.st Mon Jun 16 11:14:59 2003 +0200
@@ -22,7 +22,7 @@
ArithmeticValue subclass:#Complex
instanceVariableNames:'real imaginary'
- classVariableNames:''
+ classVariableNames:'ComplexOne ComplexZero'
poolDictionaries:''
category:'Magnitude-Numbers'
!
@@ -53,23 +53,26 @@
documentation
"
- This is an implementation of complex numbers. A complex number has real and
- imaginary parts which must be manipulated simultaneously in any numeric processing.
- Complex numbers can be used in many of the same places that regular numbers
- can be used with one major exception of comparisons, since complex numbers cannot
- be directly compared for size (except through lengths of vectors (see absolute
- value)).
+ This class implements complex numbers.
+ A complex number has real and imaginary parts which must be manipulated simultaneously
+ in any numeric processing.
+ Complex numbers can be used in many of the same places that regular numbers
+ can be used with one major exception of comparisons, since complex numbers cannot
+ be directly compared for size
+ (except through lengths of vectors (see absolute value)).
-Instance variables:
- real <Number> the part of the number which can be expressed as a Real number
- imaginary <Number> the part of the number which, in terms of how the number behaves,
- has been multiplied by 'i' (-1 sqrt)
+ [Instance variables:]
+ real <Number> the part of the number which can be expressed as a Real number
+ imaginary <Number> the part of the number which, in terms of how the number behaves,
+ has been multiplied by 'i' (-1 sqrt)
-Author: Kurt Hebel (hebel@uinova.cerl.uiuc.edu)
+ [Author:]
+ Kurt Hebel (hebel@uinova.cerl.uiuc.edu)
+ minor changes and double dispatching code by cg.
"
!
-example
+examples
"
(5 % 7) real
(5 % 7) imaginary
@@ -84,43 +87,67 @@
(1 % 0) * (2 % 0)
(1 % 0) * (0 % 2)
(1 % 0) * (2 % 3)
+
+ (1 % 2) + 2
+ (1 % 2) * 2
+ 2 + (1 % 2)
+ 2 * (1 % 2)
+
"
! !
!Complex class methodsFor:'instance creation'!
fromReal: aNumber
- "Create a new complex number from the given real number."
- ^ self basicNew setReal: aNumber setImaginary: 0
+ "Create a new complex number from the given real number."
+
+ ^ self basicNew setReal: aNumber setImaginary: 0
+!
+
+imaginary: v
+ "Create a new complex number with 0 as real and given imaginary parts.
+ If the imaginary part is zero, return the real part of the number."
+
+ v = 0 ifTrue: [^ 0].
+ ^ self basicNew setReal: 0 setImaginary: v
+!
+
+real: aNumber
+ "Create a new complex number from the given real number."
+
+ ^ self basicNew setReal: aNumber setImaginary: 0
!
real: u imaginary: v
- "Create a new complex number with the given real and imaginary parts. If the
- imaginary part is zero, return the real part of the number."
- ^v = 0 ifTrue: [u]
- ifFalse: [self basicNew setReal: u setImaginary: v]
+ "Create a new complex number with the given real and imaginary parts. If the
+ imaginary part is zero, return the real part of the number."
+
+ v = 0 ifTrue: [^ u].
+ ^ self basicNew setReal: u setImaginary: v
! !
!Complex class methodsFor:'constants access'!
unity
- "Answer the value which allows, for any given arithmetic value, the following to be true
-
- aNumber * aNumber class unity = aNumber
+ "Answer the value which allows, for any given arithmetic value, the following to be true:
+ aNumber * aNumber class unity = aNumber
+ This must be true regardless of how a given subclass chooses to define #*"
- This must be true regardless of how a given subclass chooses to define #*"
-
- ^self fromReal: 1
+ ComplexOne isNil ifTrue:[
+ ComplexOne := self fromReal: 1
+ ].
+ ^ ComplexOne
!
zero
- "Answer the value which allows, for any given arithmetic value, the following to be true
-
- aNumber + aNumber class zero = aNumber
+ "Answer the value which allows, for any given arithmetic value, the following to be true:
+ aNumber + aNumber class zero = aNumber
+ This must be true regardless of how a given subclass chooses to define #+"
- This must be true regardless of how a given subclass chooses to define #+"
-
- ^self fromReal: 0
+ ComplexZero isNil ifTrue:[
+ ComplexZero := self fromReal: 0
+ ].
+ ^ ComplexZero
! !
!Complex class methodsFor:'exception handling'!
@@ -144,311 +171,554 @@
!Complex methodsFor:'accessing'!
imaginary
- "Return the imaginary part of the complex number."
- ^ imaginary
+ "Return the imaginary part of the complex number."
+
+ ^ imaginary
+!
+
+imaginaryPart
+ "Return the imaginary part of the complex number.
+ An alias for imaginary (for compatibility with other complex implementations)"
+
+ ^ imaginary
!
real
- "Return the real part of the complex number."
- ^ real
+ "Return the real part of the complex number."
+
+ ^ real
+!
+
+realPart
+ "Return the real part of the complex number.
+ An alias for real (for compatibility with other complex implementations)"
+
+ ^ real
! !
!Complex methodsFor:'arithmetic'!
* aNumber
- "Return the product of the receiver and the argument."
-
- | u v r i |
+ "Return the product of the receiver and the argument."
- aNumber isComplex ifTrue:[
- u := aNumber real.
- v := aNumber imaginary.
- r := (real * u) - (imaginary * v).
- i := (real * v) + (imaginary * u).
- i = 0 ifTrue:[ ^ r ].
- ^ Complex real:r imaginary:i
- ].
- ^ self retry: #* coercing: aNumber
+"/ | u v r i |
+"/
+"/ aNumber isComplex ifTrue:[
+"/ u := aNumber real.
+"/ v := aNumber imaginary.
+"/ r := (real * u) - (imaginary * v).
+"/ i := (real * v) + (imaginary * u).
+"/ i = 0 ifTrue:[ ^ r ].
+"/ ^ Complex real:r imaginary:i
+"/ ].
+ ^ aNumber productFromComplex:self.
"Modified: / 8.7.1998 / 12:12:37 / cg"
!
+ aNumber
- "Return the sum of the receiver and the argument."
-
- | r i |
+ "Return the sum of the receiver and the argument."
- aNumber isComplex ifTrue: [
- r := aNumber real + real.
- i := aNumber imaginary + imaginary.
- i = 0 ifTrue:[ ^ r ].
- ^ Complex real:r imaginary:i
- ].
- ^ self retry: #+ coercing: aNumber
+"/ | r i |
+"/
+"/ aNumber isComplex ifTrue: [
+"/ r := aNumber real + real.
+"/ i := aNumber imaginary + imaginary.
+"/ i = 0 ifTrue:[ ^ r ].
+"/ ^ Complex real:r imaginary:i
+"/ ].
+ ^ aNumber sumFromComplex:self.
"Modified: / 8.7.1998 / 12:15:42 / cg"
!
- aNumber
- "Return the difference of the receiver and the argument."
-
- | r i |
+ "Return the difference of the receiver and the argument."
- aNumber isComplex ifTrue: [
- r := real - aNumber real.
- i := imaginary - aNumber imaginary.
- i = 0 ifTrue:[ ^ r ].
- ^ Complex real:r imaginary:i.
- ].
- ^ self retry: #- coercing: aNumber
+"/ | r i |
+"/
+"/ aNumber isComplex ifTrue: [
+"/ r := real - aNumber real.
+"/ i := imaginary - aNumber imaginary.
+"/ i = 0 ifTrue:[ ^ r ].
+"/ ^ Complex real:r imaginary:i.
+"/ ].
+ ^ aNumber differenceFromComplex:self.
"Modified: / 8.7.1998 / 12:15:38 / cg"
!
/ aNumber
- "Return the quotient of the receiver and the argument."
-
- | denom u v r i |
+ "Return the quotient of the receiver and the argument."
- aNumber isComplex ifTrue:[
- u := aNumber real.
- v := aNumber imaginary.
- denom := u * u + (v * v).
- r := u * real + (v * imaginary) / denom.
- i := u * imaginary - (v * real) / denom.
- i = 0 ifTrue:[ ^ r ].
- ^ Complex real:r imaginary:i
- ].
- ^ self retry: #/ coercing: aNumber
+"/ | denom u v r i |
+"/
+"/ aNumber isComplex ifTrue:[
+"/ u := aNumber real.
+"/ v := aNumber imaginary.
+"/ denom := u * u + (v * v).
+"/ r := u * real + (v * imaginary) / denom.
+"/ i := u * imaginary - (v * real) / denom.
+"/ i = 0 ifTrue:[ ^ r ].
+"/ ^ Complex real:r imaginary:i
+"/ ].
+ ^ aNumber quotientFromComplex:self.
"Modified: / 8.7.1998 / 12:15:34 / cg"
!
abs
- "Return the magnitude (or absolute value) of the complex number."
+ "Return the magnitude (or absolute value) of the complex number
+ (thats the distance from the origin in the complex plane)."
- ^ (real * real + (imaginary * imaginary)) sqrt
+ ^ (real * real + (imaginary * imaginary)) sqrt
+
+ "
+ (1 % 1) abs
+ "
!
conjugated
- "Return the complex conjugate of this complex number."
+ "Return the complex conjugate of this complex number
+ (i.e. with imaginary part negated)."
+
+ ^ Complex
+ real: real
+ imaginary: imaginary negated
+!
+
+differenceFromComplex:aComplex
+ "Return the difference of the argument, aComplex and the receiver."
+
+ | r i |
+
+ r := aComplex real - real.
+ i := aComplex imaginary - imaginary.
+ i = 0 ifTrue:[ ^ r ].
+ ^ Complex real:r imaginary:i.
+!
+
+modulus
+ | absReal absImag multiplicand quotient |
+
+ absReal := real abs.
+ absImag := imaginary abs.
+
+ absReal >= absImag ifTrue: [
+ multiplicand := absReal.
+ quotient := imaginary / real
+ ] ifFalse: [
+ multiplicand := absImag.
+ quotient := real / imaginary
+ ].
+ ^ multiplicand * ((1 + (quotient * quotient)) sqrt)
+!
+
+negated
+ "return a new complex with both real and imaginary parts negated"
+
+ ^ Complex
+ real: real negated
+ imaginary: imaginary negated
+!
+
+productFromComplex:aComplex
+ "Return the product of the receiver and the argument, aComplex."
+
+ | u v r i |
- ^ Complex real: real imaginary: imaginary negated
+ u := aComplex real.
+ v := aComplex imaginary.
+ r := (real * u) - (imaginary * v).
+ i := (real * v) + (imaginary * u).
+ i = 0 ifTrue:[ ^ r ].
+ ^ Complex real:r imaginary:i
+!
+
+quotientFromComplex:aComplex
+ "Return the quotient of the argument, aComplex and the receiver."
+
+ | denom nr ni r i |
+
+ nr := aComplex real.
+ ni := aComplex imaginary.
+ denom := real * real + (imaginary * imaginary).
+ r := real * nr + (imaginary * ni) / denom.
+ i := real * ni - (imaginary * nr) / denom.
+ i = 0 ifTrue:[ ^ r ].
+ ^ Complex real:r imaginary:i
+
+"/ is the stuff below better ?
+"/ "Implement complex division (a + ib) / (c + id).
+"/ Due to double dispatch, in this routine
+"/ self = (c + id) and aComplex = (a + ib)."
+"/
+"/ | quotient denominator |
+"/
+"/ self realPart abs >= (self imaginaryPart abs)
+"/ ifTrue: [
+"/ quotient := self imaginaryPart / self realPart.
+"/ denominator := self realPart + (self imaginaryPart * quotient).
+"/ ^ Complex
+"/ real: (aComplex realPart + (aComplex imaginaryPart * quotient)) / denominator
+"/ imaginary: (aComplex imaginaryPart - (aComplex realPart * quotient)) / denominator ]
+"/ ifFalse: [
+"/ quotient := self realPart / self imaginaryPart.
+"/ denominator := (self realPart * quotient) + self imaginaryPart.
+"/ ^ Complex
+"/ real: ((aComplex realPart * quotient) + aComplex imaginaryPart) / denominator
+"/ imaginary: ((aComplex imaginaryPart * quotient) - aComplex realPart) / denominator ]
+!
+
+sumFromComplex:aComplex
+ "Return the sum of the receiver and the argument, aComplex."
+
+ | r i |
+
+ r := aComplex real + real.
+ i := aComplex imaginary + imaginary.
+ i = 0 ifTrue:[ ^ r ].
+ ^ Complex real:r imaginary:i
! !
!Complex methodsFor:'coercing'!
coerce: aNumber
-
- ^aNumber asComplex
+ ^ aNumber asComplex
!
generality
-
- ^150
+ ^ 150
! !
!Complex methodsFor:'comparing'!
< aNumber
- ^Number
- raise: #unorderedSignal
- receiver: self
- selector: #<
- arg: aNumber
- errorString: 'Complex numbers are not well ordered'
+ "raises an error - complex numbers are not well ordered"
+
+ ^ Number
+ raise: #unorderedSignal
+ receiver: self
+ selector: #<
+ arg: aNumber
+ errorString: 'Complex numbers are not well ordered'
+
+ "
+ 1 < (2 % 2)
+ (2 % 2) < 1
+ "
!
= aNumber
- ^ (aNumber real = real) and:[aNumber imaginary = imaginary]
+ "return true, if the argument represents the same numeric value
+ as the receiver, false otherwise"
+
+ ^ aNumber equalFromComplex:self
!
hash
- "Hash is implemented because equals is implemented."
+ "Hash is implemented because equals is implemented."
- ^ real hash
+ ^ real hash
! !
!Complex methodsFor:'converting'!
asComplex
+ "I am a complex - so return the receiver"
- ^self
+ ^ self
!
asFloat
-
- imaginary = 0 ifTrue: [^real asFloat].
- ^Number
- raise: #coercionErrorSignal
- receiver: self
- selector: #asFloat
- errorString: 'Can''t coerce an instance of Complex to a Float'
+ imaginary = 0 ifTrue: [^ real asFloat].
+ ^ Number
+ raise: #coercionErrorSignal
+ receiver: self
+ selector: #asFloat
+ errorString: 'Can''t coerce an instance of Complex to a Float'
!
asInteger
-
- imaginary = 0 ifTrue: [^real asInteger].
- ^Number
- raise: #coercionErrorSignal
- receiver: self
- selector: #asInteger
- errorString: 'Can''t coerce an instance of Complex to an Integer'
+ imaginary = 0 ifTrue: [^real asInteger].
+ ^ Number
+ raise: #coercionErrorSignal
+ receiver: self
+ selector: #asInteger
+ errorString: 'Can''t coerce an instance of Complex to an Integer'
!
asPoint
- "Return the complex number as a point."
- ^ real @ imaginary
+ "Return the complex number as a point."
+
+ ^ real @ imaginary
!
reduceGeneralityIfPossible
- "Answer the receiver transformed to a lower generality, if such a
- transformation is possible without losing information. If not, answer
- the receiver"
+ "Answer the receiver transformed to a lower generality, if such a
+ transformation is possible without losing information.
+ If not, answer the receiver"
- imaginary isZero
- ifTrue: [^real]
- ifFalse: [^self]
+ imaginary isZero
+ ifTrue: [^ real]
+ ifFalse: [^ self]
! !
!Complex methodsFor:'double dispatching'!
-differenceFromFloat: argument
- ^ argument asComplex - self
-!
+differenceFromFloat:aFloat
+ "Return the difference of the argument, aFloat and the receiver."
+
+ "/ ^ aFloat asComplex - self
+
+ | r |
-differenceFromFraction: argument
- ^ argument asComplex - self
+ r := aFloat - real.
+ imaginary = 0 ifTrue:[ ^ r ].
+ ^ Complex real:r imaginary:imaginary
+
+ "
+ (1 % 1) - 1.0
+ 1.0 - (1 % 1)
+ "
!
-differenceFromInteger: argument
- ^ argument asComplex - self
+differenceFromFraction: aFraction
+ ^ aFraction asComplex - self
+!
+
+differenceFromInteger: anInteger
+ ^ anInteger asComplex - self
!
-productFromFloat: argument
- ^ argument asComplex * self
+equalFromComplex:aComplex
+ ^ (aComplex real = real) and:[aComplex imaginary = imaginary]
!
-productFromFraction: argument
- ^ argument asComplex * self
+equalFromFloat:aFloat
+ imaginary = 0 ifFalse:[^ false].
+ ^ real = aFloat
!
-productFromInteger: argument
- ^ argument asComplex * self
+productFromFloat: aFloat
+ "Return the product of the receiver and the argument, aFloat."
+
+ "/ ^ aFloat asComplex * self
+
+ | u r i |
+
+ u := aFloat.
+ r := (real * aFloat).
+ i := (imaginary * aFloat).
+ i = 0 ifTrue:[ ^ r ].
+ ^ Complex real:r imaginary:i
+
+ "
+ (1 % 1) * 2.0
+ (1 % 1) * 0.0
+ 2.0 * (1 % 1)
+ "
!
-quotientFromFloat: argument
- ^ argument asComplex / self
+productFromFraction: aFraction
+ ^ aFraction asComplex * self
!
-quotientFromFraction: argument
- ^ argument asComplex / self
+productFromInteger: anInteger
+ ^ anInteger asComplex * self
+!
+
+quotientFromFloat: aFloat
+ ^ aFloat asComplex / self
!
-quotientFromInteger: argument
- ^ argument asComplex / self
+quotientFromFraction: aFraction
+ ^ aFraction asComplex / self
+!
+
+quotientFromInteger: anInteger
+ ^ anInteger asComplex / self
!
-sumFromFloat: argument
- ^ argument asComplex + self
+sumFromFloat: aFloat
+ "Return the sum of the receiver and the argument, aFloat."
+
+ "/ ^ aFloat asComplex + self
+
+ | r |
+
+ r := aFloat + real.
+ imaginary = 0 ifTrue:[ ^ r ].
+ ^ Complex real:r imaginary:imaginary
+
+ "
+ (1 % 1) + 1.0
+ 1.0 + (1 % 1)
+ "
!
-sumFromFraction: argument
- ^ argument asComplex + self
+sumFromFraction: aFraction
+ ^ aFraction asComplex + self
!
-sumFromInteger: argument
- ^ argument asComplex + self
+sumFromInteger: anInteger
+ ^ anInteger asComplex + self
! !
!Complex methodsFor:'mathematical functions'!
angle
- "Return the radian angle for this Complex number."
+ "Return the radian angle for this Complex number."
- real < 0 ifTrue: [
- imaginary < 0 ifTrue: [
- ^ (imaginary / real) arcTan - Float pi
- ].
- ^ Float pi + (imaginary / real) arcTan
- ].
- ^ (imaginary / real) arcTan
+ real < 0 ifTrue: [
+ imaginary < 0 ifTrue: [
+ ^ (imaginary / real) arcTan - Float pi
+ ].
+ ^ Float pi + (imaginary / real) arcTan
+ ].
+ ^ (imaginary / real) arcTan
+
+ "
+ (1 % 1) angle radiansToDegrees
+ "
!
exp
- "Return the complex exponential of the receiver."
+ "Return the complex exponential of the receiver."
- ^ imaginary cos % imaginary sin * real exp
+ ^ (imaginary cos % imaginary sin) * real exp
!
sqrt
- "Return the square root of the receiver"
+ "Return the square root of the receiver"
+
+ | w quotient absReal absImag |
+
+ ((real = 0) and: [ imaginary = 0 ]) ifTrue: [
+ ^ Complex zero
+ ].
+ absReal := real abs.
+ absImag := imaginary abs.
+
+ absReal >= absImag ifTrue:[
+ quotient := imaginary / real.
+ w := (absReal sqrt) * (((1 + (1 + (quotient * quotient)) sqrt) / 2) sqrt)
+ ] ifFalse: [
+ quotient := real / imaginary.
+ w := (absImag sqrt) * (((quotient abs + (1 + (quotient * quotient)) sqrt) / 2) sqrt)
+ ].
- | u v |
- (imaginary = 0 and: [real >= 0]) ifTrue: [^real sqrt].
- v := (self abs - real / 2) sqrt.
- u := imaginary / 2 / v.
- ^Complex real: u imaginary: v
+ real >= 0 ifTrue:[
+ ^ Complex real: w imaginary: (imaginary / (2 * w))
+ ].
+ imaginary >= 0 ifTrue: [
+ ^ Complex real: absImag / (2 * w) imaginary: w
+ ].
+ ^ Complex real: absImag / (2 * w) imaginary: -1 * w
+!
+
+sqrt_bad
+ "Return the square root of the receiver"
- "-4 asComplex sqrt"
- "-4 asComplex sqrt squared"
+ | u v |
+
+ (imaginary = 0 and: [real >= 0]) ifTrue: [^ real sqrt].
+ v := (self abs - real / 2) sqrt.
+ u := imaginary / 2 / v.
+ ^ Complex real: u imaginary: v
+
+ "
+ -4 asComplex sqrt
+ 4 asComplex sqrt
+ "
+ "
+ -4 asComplex sqrt squared
+ "
! !
!Complex methodsFor:'printing'!
+displayOn: aStream
+ aStream nextPut: $(.
+ self realPart printOn: aStream.
+ self imaginaryPart >= 0
+ ifTrue: [ aStream nextPut: $+ ]
+ ifFalse: [ aStream nextPut: $- ].
+ self imaginaryPart abs printOn: aStream.
+ aStream nextPutAll: 'i)'
+
+ "
+ Complex real:1 imaginary:1
+ "
+!
+
printOn: aStream
- aStream nextPut: $(.
- real storeOn: aStream.
- aStream nextPutAll: '%'.
- imaginary storeOn: aStream.
- aStream nextPut: $).
+ aStream nextPut: $(.
+ real storeOn: aStream.
+ aStream nextPutAll: '%'.
+ imaginary storeOn: aStream.
+ aStream nextPut: $).
!
printString
- ^ '(' , real printString, '%', imaginary printString, ')'
+ ^ '(' , real printString, '%', imaginary printString, ')'
!
storeOn: aStream
- aStream nextPut: $(.
- real storeOn: aStream.
- aStream nextPutAll: '%'.
- imaginary storeOn: aStream.
- aStream nextPut: $).
+ self printOn:aStream
! !
!Complex methodsFor:'private'!
setReal: u setImaginary: v
- real := u.
- imaginary := v.
+ real := u.
+ imaginary := v.
! !
!Complex methodsFor:'testing'!
isComplex
+ "Answer whether the receiver has an imaginary part
+ (i.e. if it is a complex number). Always true here."
- ^true
+ ^ true
!
isReal
- "Return true if this Complex number has a zero imaginary part."
- ^ imaginary = 0
+ "Return true if this Complex number has a zero imaginary part."
+
+ ^ imaginary = 0
!
isZero
- "Answer whether 'self = self class zero'. We can't use #= because
- #= is defined in terms of #isZero"
+ "Answer whether 'self = self class zero'.
+ We can't use #= because #= is defined in terms of #isZero"
- ^real isZero and: [imaginary isZero]
+ ^real isZero and: [imaginary isZero]
!
sign
+ "return a new complex, consisting of the signs of the real and imaginary parts"
- ^Complex real: real sign imaginary: imaginary sign
+ ^ Complex real: real sign imaginary: imaginary sign
+! !
+
+!Complex methodsFor:'truncation & rounding'!
+
+ceiling
+ "blocked: complex numbers have no ceiling"
+
+ ^ self shouldNotImplement
+!
+
+floor
+ "blocked: complex numbers have no floor"
+
+ ^ self shouldNotImplement
! !
!Complex class methodsFor:'documentation'!
version
- ^ '$Header: /cvs/stx/stx/libbasic/Complex.st,v 1.7 2003-04-22 09:44:13 cg Exp $'
+ ^ '$Header: /cvs/stx/stx/libbasic/Complex.st,v 1.8 2003-06-16 09:13:42 cg Exp $'
! !