--- a/ArithmeticValue.st Mon Jul 03 15:56:06 2017 +0200
+++ b/ArithmeticValue.st Mon Jul 03 15:56:39 2017 +0200
@@ -47,29 +47,29 @@
variables and signal accessors remain here for backward compatibility.
[class variables:]
- ArithmeticSignal <Error> parent of all arithmetic signals
- (never raised itself)
- New: now a reference to ArithmeticError
+ ArithmeticSignal <Error> parent of all arithmetic signals
+ (never raised itself)
+ New: now a reference to ArithmeticError
- DomainErrorSignal <Error> raised upon float errors
- (for example range in trigonometric)
- New: now a reference to DomainError
+ DomainErrorSignal <Error> raised upon float errors
+ (for example range in trigonometric)
+ New: now a reference to DomainError; no longer a classVar
- DivisionByZeroSignal <Error> raised when division by 0 is attempted
- New: now a reference to ZeroDivide
+ DivisionByZeroSignal <Error> raised when division by 0 is attempted
+ New: now a reference to ZeroDivide
- OverflowSignal <Error> raised on overflow/underflow conditions
- UnderflowSignal in float arithmetic.
- Notice: some OperatingSystems do not
- provide enough information for ST/X to
- extract the real reason for the floatException
- thus raising DomainErrorSignal in these cases.
+ OverflowSignal <Error> raised on overflow/underflow conditions
+ UnderflowSignal in float arithmetic.
+ Notice: some OperatingSystems do not
+ provide enough information for ST/X to
+ extract the real reason for the floatException
+ thus raising DomainErrorSignal in these cases.
[author:]
- Claus Gittinger
+ Claus Gittinger
[See also:]
- Number
+ Number
"
! !
@@ -105,6 +105,15 @@
^ ImaginaryResultError
!
+infiniteResultSignal
+ "return the signal which is raised when an infinite result would be created
+ (such as when taking the logarithm of zero)"
+
+ ^ InfiniteResultError
+
+ "Created: / 03-07-2017 / 15:46:02 / cg"
+!
+
operationNotPossibleSignal
^ Error
!
@@ -150,12 +159,14 @@
"/ messages (accessors) instead of referring to the class variables.
ArithmeticSignal := ArithmeticError.
- DomainErrorSignal := DomainError.
+ "/ DomainErrorSignal := DomainError.
DivisionByZeroSignal := ZeroDivide.
UnorderedSignal := UnorderedNumbersError.
ConversionErrorSignal := ConversionError.
OverflowSignal := OverflowError.
UnderflowSignal := UnderflowError.
+
+ "Modified: / 03-07-2017 / 14:05:10 / cg"
! !
!ArithmeticValue class methodsFor:'coercing & converting'!
@@ -250,6 +261,126 @@
"Modified: / 16.11.2001 / 14:12:09 / cg"
! !
+!ArithmeticValue class methodsFor:'exception handling'!
+
+trapImaginary:aBlock
+ "evaluate aBlock;
+ if any DomainError occurs inside, which would return an imaginary result,
+ (eg. square root of negative number),
+ convert the result to a complex number and proceed.
+
+ This allows for regular (failing) code to transparently convert to complex."
+
+ ^ ImaginaryResultError
+ handle: [:ex |
+ |msgSend selector rcvr|
+
+ msgSend := ex parameter.
+ selector := msgSend selector.
+ rcvr := msgSend receiver.
+ (selector == #sqrt or: [selector == #sqrtTruncated]) ifTrue: [
+ (rcvr isNumber and:[rcvr isReal]) ifTrue:[
+ ex proceedWith:(rcvr abs perform:selector) i
+ ] ifFalse:[
+ msgSend receiver: rcvr asComplex.
+ ex proceedWith: msgSend value
+ ].
+ ] ifFalse: [
+ (selector == #integerSqrt) ifTrue: [
+ (rcvr isInteger) ifTrue:[
+ ex proceedWith:(rcvr abs integerSqrt) i
+ ] ifFalse:[
+ ex proceedWith:(rcvr abs asComplex sqrt floor) i
+ ].
+ ]
+ ].
+ ex reject
+ ] do:
+ aBlock
+
+ "
+ this raises an error:
+ -2 sqrt
+
+ this returns an imaginary result:
+ Complex trapImaginary: [-2 sqrt]
+
+ of course, this one as well:
+ -2 asComplex sqrt
+ "
+
+ "failing code:
+ |a|
+
+ a := -2.
+ (a sqrt + 5) * 17.
+ "
+ "complex code:
+ |a|
+
+ Complex trapImaginary:[
+ a := -2.
+ (a sqrt + 5) * 2.
+ ]
+ "
+
+ "Modified: / 03-07-2017 / 15:53:49 / cg"
+!
+
+trapInfinity:aBlock
+ "evaluate aBlock;
+ if any DomainError occurs inside, which would return an infinite result,
+ (eg. ln of zero),
+ convert the result to infinity and proceed.
+
+ This allows for regular (failing) code to transparently convert to infinity and behave
+ similar to other systems which do that."
+
+ ^ InfiniteResultError
+ handle: [:ex |
+ |msgSend selector rcvr|
+
+ msgSend := ex parameter.
+ selector := msgSend selector.
+ rcvr := msgSend receiver.
+ ((selector == #ln)
+ or:[selector == #log10
+ or:[selector == #integerLog10]]) ifTrue: [
+ (rcvr isNumber) ifTrue:[
+ ex proceedWith:(rcvr class negativeInfinity )
+ ].
+ ].
+ ex reject
+ ] do:
+ aBlock
+
+ "
+ this raises an error:
+ 0 ln
+
+ this returns an imaginary result:
+ Number trapInfinity: [0 ln]
+ "
+
+ "failing code:
+ |a|
+
+ a := 0.
+ a ln isFinite.
+ "
+ "fixed code:
+ |a|
+
+ Number trapInfinity:[
+ a := 0.
+ a ln isFinite.
+ ]
+ "
+
+ "Created: / 03-07-2017 / 14:25:57 / cg"
+ "Modified: / 03-07-2017 / 15:53:40 / cg"
+! !
+
!ArithmeticValue class methodsFor:'queries'!
isAbstract
@@ -1226,7 +1357,8 @@
!
raisedFromNumber:aNumber
- "aNumber does not know how to be raised to the receiver"
+ "aNumber does not know how to be raised to the receiver
+ (i.e. how to compute aNumber^self)"
^ self class
raise:#domainErrorSignal
@@ -1236,6 +1368,7 @@
errorString:'bad receiver/arg in raisedTo:'
"Created: / 01-07-2017 / 21:17:06 / cg"
+ "Modified (comment): / 03-07-2017 / 14:06:53 / cg"
!
remainderFromFloat:aFloat
@@ -1520,21 +1653,24 @@
even
"return true if the receiver is divisible by 2.
- Only defined for whole-numbers."
+ This is only defined for whole-numbers (integers)."
^ self class
- raise:DomainError
+ raise:#domainErrorSignal
receiver:self
selector:#even
arguments:#()
errorString:'Receiver must be a whole-number'
- "/ No, this is bad: ^ self truncated asInteger even
+ "/ No no no, the following is bad:
+ "/ ^ self truncated asInteger even
"
- 2.4 even
- 2.0 even
+ 2.4 even
+ 2.0 even
"
+
+ "Modified (comment): / 03-07-2017 / 14:10:01 / cg"
!
isComplex