--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ArithVal.st Fri Jul 16 11:39:45 1993 +0200
@@ -0,0 +1,613 @@
+"
+ COPYRIGHT (c) 1993 by Claus Gittinger
+ All Rights Reserved
+
+ This software is furnished under a license and may be used
+ only in accordance with the terms of that license and with the
+ inclusion of the above copyright notice. This software may not
+ be provided or otherwise made available to, or used by, any
+ other person. No title to or ownership of the software is
+ hereby transferred.
+"
+
+Magnitude subclass:#ArithmeticValue
+ instanceVariableNames:''
+ classVariableNames:'DivisionByZeroSignal DomainErrorSignal
+ OverflowSignal UnderflowSignal
+ AnyArithmeticSignal'
+ poolDictionaries:''
+ category:'Magnitude-Numbers'
+!
+
+ArithmeticValue comment:'
+
+COPYRIGHT (c) 1993 by Claus Gittinger
+ All Rights Reserved
+
+ArithmeticValue is an abstract superclass for all things responding to
+arithmetic messages. It was inserted into the hierarchy, to allow things
+like matrices, functions etc. share the arithmetic methods defined here.
+
+(In the old hierarchy these had to be Numbers to do that
+ - which is not quite correct)
+
+%W% %E%
+'!
+
+!ArithmeticValue class methodsFor:'initialization' !
+
+initialize
+ "setup the signals"
+
+ DomainErrorSignal := (Signal new) mayProceed:false.
+ DomainErrorSignal notifierString:'domain error'.
+
+ DivisionByZeroSignal := (Signal new) mayProceed:false.
+ DivisionByZeroSignal notifierString:'division by zero'.
+
+ OverflowSignal := (Signal new) mayProceed:false.
+ OverflowSignal notifierString:'overflow'.
+
+ UnderflowSignal := (Signal new) mayProceed:false.
+ UnderflowSignal notifierString:'underflow'.
+
+ AnyArithmeticSignal := SignalSet with:DomainErrorSignal
+ with:DivisionByZeroSignal
+ with:OverflowSignal
+ with:UnderflowSignal.
+! !
+
+!ArithmeticValue class methodsFor:'signal access' !
+
+domainErrorSignal
+ "return the signal which is raised on math errors
+ (such as log of 0 etc.)"
+
+ ^ DomainErrorSignal
+!
+
+divisionByZeroSignal
+ "return the signal which is raised on division by zero"
+
+ ^ DivisionByZeroSignal
+!
+
+overflowSignal
+ "return the signal which is raised on overflow conditions (in floats)"
+
+ ^ OverflowSignal
+!
+
+underflowSignal
+ "return the signal which is raised on underflow conditions (in floats)"
+
+ ^ UnderflowSignal
+!
+
+anyArithmeticSignal
+ "return a signalSet with all possible arithmetic signals"
+
+ ^ AnyArithmeticSignal
+! !
+
+!ArithmeticValue methodsFor:'converting' !
+
+degreesToRadians
+ "interpreting the receiver as radians, return the degrees"
+
+ ^ self asFloat degreesToRadians
+!
+
+radiansToDegrees
+ "interpreting the receiver as degrees, return the radians"
+
+ ^ self asFloat radiansToDegrees
+!
+
+asInteger
+ "return an integer with same value - might truncate"
+
+ ^ self truncated
+!
+
+asFloat
+ "return a float with same value"
+
+ ^ self subclassResponsibility
+!
+
+asFraction
+ "return a fraction with same value"
+
+ ^ self subclassResponsibility
+!
+
+coerce:aNumber
+ "convert aNumber into an instance of the receivers class and return it."
+
+ ^ self subclassResponsibility
+!
+
+generality
+ "return a number giving the receivers generality, that number is
+ used to convert one of the arguments in a mixed expression.
+ The generality has to be defined in subclasses,
+ such that gen(a) > gen(b) iff, conversion of b into a's class
+ does not cut precision. For example, Integer has 40, Float has 80,
+ meaning that if we convert a Float to an Integer, some precision may
+ be lost. The generality is used by ArithmeticValue>>retry:cuercing:"
+
+ ^ self subclassResponsibility
+!
+
+retry:aSymbol coercing:aNumber
+ "arithmetic represented by the binary operator, aSymbol,
+ could not be performed with the receiver and the argument, aNumber,
+ because of the differences in representation.
+ Coerce either the receiver or the argument, depending on which has higher
+ generality, and try again.
+ If the operation is compare for same value (=), return false if
+ the argument is not a Number.
+ If the generalities are the same, create an error message, since this
+ means that a subclass has not been fully implemented."
+
+ |myGenerality otherGenerality|
+
+ (aSymbol == #=) ifTrue:[
+ (aNumber respondsTo:#generality) ifFalse:[^ false]
+ ] ifFalse:[
+ (aNumber respondsTo:#generality) ifFalse:[
+ self error:'retry:coercing: argument is not a number'.
+ ^ self
+ ]
+ ].
+ myGenerality := self generality.
+ otherGenerality := aNumber generality.
+ (myGenerality > otherGenerality) ifTrue:[
+ ^ self perform:aSymbol with:(self coerce:aNumber)
+ ].
+ (myGenerality < otherGenerality) ifTrue:[
+ ^ (aNumber coerce:self) perform:aSymbol with:aNumber
+ ].
+ self error:'retry:coercing: oops - same generality'
+! !
+
+!ArithmeticValue methodsFor:'queries' !
+
+respondsToArithmetic
+ "return true, if the receiver responds to arithmetic messages"
+
+ ^ true
+! !
+
+!ArithmeticValue methodsFor:'arithmetic' !
+
++ something
+ "return the sum of the receiver and the argument"
+
+ ^ self subclassResponsibility
+!
+
+- something
+ "return the difference of the receiver and the argument"
+
+ ^ self subclassResponsibility
+!
+
+* something
+ "return the product of the receiver and the argument"
+
+ ^ self subclassResponsibility
+!
+
+/ something
+ "return the quotient of the receiver and the argument"
+
+ ^ self subclassResponsibility
+!
+
+// something
+ "return the integer quotient of the receiver and the argument"
+
+ ^ (self / something) floor
+!
+
+\\ something
+ "return the integer modulu of the receiver and the argument"
+
+ ^ self - ((self // something) * something)
+!
+
+quo:something
+ "Return the integer quotient of dividing the receiver by the argument
+ with truncation towards zero."
+
+ ^ (self / something) truncated
+!
+
+rem:something
+ "Return the integer remainder of dividing the receiver by the argument
+ with truncation towards zero.
+ The remainder has the same sign as the receiver."
+
+ ^ self - ((self quo:something) * something)
+!
+
+abs
+ "return the absolute value of the receiver"
+
+ (self negative) ifTrue:[^ self negated].
+ ^ self
+!
+
+negated
+ "return the receiver negated"
+
+ ^ self class zero - self
+!
+
+reciprocal
+ "return the receivers reciprocal"
+
+ ^ self class unity / self
+! !
+
+!ArithmeticValue methodsFor:'comparing'!
+
+>= something
+ "return true, if the argument is less or equal than the receiver"
+
+ ^ (self < something) not
+!
+
+> something
+ "return true, if the argument is less than the receiver"
+
+ ^ something < self
+!
+
+<= something
+ "return true, if the argument is greater or equal than the receiver"
+
+ ^ (something < self) not
+!
+
+< something
+ "return true, if the argument is greater than the receiver"
+
+ ^ self subclassResponsibility
+!
+
+compare:arg ifLess:lessBlock ifEqual:equalBlock ifGreater:greaterBlock
+ "three-way compare - thanks to Self for this idea.
+ Can be redefined in subclasses to do it with a single comparison if
+ comparison is expensive."
+
+ self < arg ifTrue:[
+ ^ lessBlock value
+ ].
+ self = arg ifTrue:[
+ ^ equalBlock value
+ ].
+ ^ greaterBlock value
+! !
+
+!ArithmeticValue methodsFor:'truncation and rounding'!
+
+ceiling
+ "return the integer nearest the receiver towards positive infinity."
+
+ |anInteger|
+
+ anInteger := self // 1. "truncates towards negative infinity"
+ anInteger = self ifTrue:[^ anInteger].
+ ^ anInteger + 1
+!
+
+floor
+ "return the receiver truncated towards negative infinity"
+
+ ^ self // 1
+!
+
+truncated
+ "return the receiver truncated towards zero"
+
+ ^ self floor asInteger
+!
+
+truncateTo:aNumber
+ "return the receiver truncated to multiples of aNumber"
+
+ ^ ((self / aNumber) floor * aNumber) asInteger
+!
+
+rounded
+ "return the integer nearest the receiver"
+
+ ^ (self + 0.5) floor asInteger
+!
+
+roundTo:aNumber
+ "return the receiver rounded to multiples of aNumber"
+
+ ^ (self / aNumber) rounded * aNumber
+! !
+
+!ArithmeticValue methodsFor:'double dispatching'!
+
+sumFromInteger:anInteger
+ "the receiver does not know how to add an integer -
+ retry the operation by coercing to higher generality"
+
+ ^ anInteger retry:#+ coercing:self
+!
+
+sumFromFloat:aFloat
+ "the receiver does not know how to add a float -
+ retry the operation by coercing to higher generality"
+
+ ^ aFloat retry:#+ coercing:self
+!
+
+sumFromFraction:aFraction
+ "the receiver does not know how to add a fraction -
+ retry the operation by coercing to higher generality"
+
+ ^ aFraction retry:#+ coercing:self
+!
+
+differenceFromInteger:anInteger
+ "the receiver does not know how to subtract from an integer -
+ retry the operation by coercing to higher generality"
+
+ ^ anInteger retry:#- coercing:self
+!
+
+differenceFromFloat:aFloat
+ "the receiver does not know how to subtract from a float -
+ retry the operation by coercing to higher generality"
+
+ ^ aFloat retry:#- coercing:self
+!
+
+differenceFromFraction:aFraction
+ "the receiver does not know how to subtract from a fraction -
+ retry the operation by coercing to higher generality"
+
+ ^ aFraction retry:#- coercing:self
+!
+
+productFromInteger:anInteger
+ "the receiver does not know how to multiply an integer -
+ retry the operation by coercing to higher generality"
+
+ ^ anInteger retry:#* coercing:self
+!
+
+productFromFloat:aFloat
+ "the receiver does not know how to multiply a float -
+ retry the operation by coercing to higher generality"
+
+ ^ aFloat retry:#* coercing:self
+!
+
+productFromFraction:aFraction
+ "the receiver does not know how to multiply a fraction -
+ retry the operation by coercing to higher generality"
+
+ ^ aFraction retry:#* coercing:self
+!
+
+quotientFromInteger:anInteger
+ "the receiver does not know how to divide an integer -
+ retry the operation by coercing to higher generality"
+
+ ^ anInteger retry:#/ coercing:self
+!
+
+quotientFromFloat:aFloat
+ "the receiver does not know how to divide a float -
+ retry the operation by coercing to higher generality"
+
+ ^ aFloat retry:#/ coercing:self
+!
+
+quotientFromFraction:aFraction
+ "the receiver does not know how to divide a fraction -
+ retry the operation by coercing to higher generality"
+
+ ^ aFraction retry:#/ coercing:self
+!
+
+lessFromInteger:anInteger
+ "the receiver does not know how to compare to an integer -
+ retry the operation by coercing to higher generality"
+
+ ^ anInteger retry:#< coercing:self
+!
+
+lessFromFloat:aFloat
+ "the receiver does not know how to compare to a float -
+ retry the operation by coercing to higher generality"
+
+ ^ aFloat retry:#< coercing:self
+!
+
+lessFromFraction:aFraction
+ "the receiver does not know how to compare to a fraction -
+ retry the operation by coercing to higher generality"
+
+ ^ aFraction retry:#< coercing:self
+! !
+
+!ArithmeticValue methodsFor:'misc math'!
+
+squared
+ "return receiver * receiver"
+
+ ^ self * self
+!
+
+exp
+ "return e ^ receiver"
+
+ ^ self asFloat exp
+!
+
+ln
+ "return the natural logarithm of the receiver"
+
+ ^ self asFloat ln
+!
+
+log
+ "return log base 10 of the receiver"
+
+ ^ self log:10
+!
+
+log:aNumber
+ "return log base aNumber of the receiver"
+
+ ^ self ln / aNumber ln
+!
+
+sqrt
+ "return the square root of the receiver"
+
+ ^ self asFloat sqrt
+!
+
+floorLog:radix
+ "return the logarithm truncated as an integer"
+
+ ^ (self log:radix) floor
+!
+
+raisedTo:aNumber
+ "return the receiver raised to aNumber"
+
+ aNumber = 0 ifTrue:[^ 1].
+ aNumber = 1 ifTrue:[^ self].
+ aNumber isInteger ifTrue:[
+ ^ self raisedToInteger:aNumber
+ ].
+ ^ self asFloat raisedTo:aNumber
+!
+
+raisedToInteger:anInteger
+ "return the receiver raised to anInteger"
+
+ |count result|
+
+ result := self coerce:1.
+ count := anInteger abs.
+ count timesRepeat:[result := result * self].
+ (anInteger < 0) ifTrue:[
+ ^ 1 / result
+ ].
+ ^ result
+! !
+
+!ArithmeticValue methodsFor:'trigonometric'!
+
+sin
+ "return the sine of the receiver (interpreted as radians)"
+
+ ^ self asFloat sin
+!
+
+cos
+ "return the cosine of the receiver (interpreted as radians)"
+
+ ^ self asFloat cos
+!
+
+tan
+ "return the tangens of the receiver (interpreted as radians)"
+
+ ^ self asFloat tan
+!
+
+arcCos
+ "return the arccosine of the receiver (in radians)"
+
+ ^ self asFloat arcCos
+!
+
+arcSin
+ "return the arcsine of the receiver (in radians)"
+
+ ^ self asFloat arcSin
+!
+
+arcTan
+ "return the arctangens of the receiver (in radians)"
+
+ ^ self asFloat arcTan
+! !
+
+!ArithmeticValue methodsFor:'error handling'!
+
+divideByZeroError
+ "report a division by zero error"
+
+ DivisionByZeroSignal raise
+ "self error:'division by zero'"
+! !
+
+!ArithmeticValue methodsFor:'testing'!
+
+negative
+ "return true, if the receiver is < 0"
+
+ " this would lead to infinite recursion ...
+ ^ (self < 0)
+ "
+ ^ self subclassResponsibility
+!
+
+positive
+ "return true, if the receiver is >= 0"
+
+ ^ self negative not
+!
+
+strictlyPositive
+ "return true, if the receiver is > 0"
+
+ ^ (self > 0)
+!
+
+sign
+ "return the sign of the receiver"
+
+ (self < 0) ifTrue:[^ -1].
+ (self > 0) ifTrue:[^ 1].
+ ^ 0
+!
+
+even
+ "return true if the receiver is divisible by 2"
+
+ ^ self truncated asInteger even
+!
+
+odd
+ "return true if the receiver is not divisible by 2"
+
+ ^ self even not
+!
+
+denominator
+ "return the denominator of the receiver"
+
+ ^ 1
+!
+
+numerator
+ "return the numerator of the receiver."
+
+ ^ self
+! !