ArithmeticValue.st
author Claus Gittinger <cg@exept.de>
Tue, 09 Jul 2019 20:55:17 +0200
changeset 24417 03b083548da2
parent 24301 bf2a904cbeda
child 24711 e821bbd154fa
permissions -rw-r--r--
#REFACTORING by exept class: Smalltalk class changed: #recursiveInstallAutoloadedClassesFrom:rememberIn:maxLevels:noAutoload:packageTop:showSplashInLevels: Transcript showCR:(... bindWith:...) -> Transcript showCR:... with:...

"{ Encoding: utf8 }"

"
 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.
"
"{ Package: 'stx:libbasic' }"

"{ NameSpace: Smalltalk }"

Magnitude subclass:#ArithmeticValue
	instanceVariableNames:''
	classVariableNames:'ArithmeticSignal ConversionErrorSignal DivisionByZeroSignal
		DomainErrorSignal OverflowSignal UnderflowSignal UnorderedSignal'
	poolDictionaries:''
	category:'Magnitude-Numbers'
!

!ArithmeticValue class methodsFor:'documentation'!

copyright
"
 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.
"
!

documentation
"
    ArithmeticValue is an abstract superclass for all things responding to
    arithmetic messages. It was inserted into the hierarchy, to allow objects
    like matrices, functions etc. to share the arithmetic methods defined here.

    Notice, that what used to be signals are now exception classes - the class
    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

        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

        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

    [See also:]
        Number
"
! !

!ArithmeticValue class methodsFor:'Signal constants'!

arithmeticSignal
    "return the parent of all arithmetic signals"

    ^ ArithmeticError
!

coercionErrorSignal
    ^ ArithmeticError

    "Created: / 26-01-2019 / 10:53:12 / Claus Gittinger"
!

divisionByZeroSignal
    "return the signal which is raised on division by zero.
     No longer used - we now have the class based ZeroDivide exception.
     This method is kept for backward compatibility."

    ^ ZeroDivide

    "Modified (comment): / 20-06-2017 / 17:53:33 / cg"
!

domainErrorSignal
    "return the signal which is raised on some math errors,
     when the argument is outside the legal domain.
     (such as arcSin of 2 etc.)"

    ^ DomainError

    "
     2 arcSin
     0 log     - raises infiniteResult, which is a child of DomainError
    "

    "Modified (comment): / 22-09-2017 / 09:50:41 / cg"
!

imaginaryResultSignal
    "return the signal which is raised when an imaginary result would be created
     (such as when taking the sqrt of a negative number).
     This error can be handled by wrapping the computation inside a trapImaginary
     block; then, a complex result is generated."

    ^ ImaginaryResultError

    "
     -2 sqrt
     
     Complex trapImaginary:[ -2 sqrt ]
    "

    "Modified (comment): / 22-09-2017 / 09:53:58 / cg"
!

infiniteResultSignal
    "return the signal which is raised when an infinite result would be created.
     This is a subclass of DomainError.
     (such as when taking the logarithm of zero)"

    ^ InfiniteResultError

    "Created: / 03-07-2017 / 15:46:02 / cg"
    "Modified (comment): / 22-09-2017 / 09:49:15 / cg"
!

operationNotPossibleSignal
    ^ ArithmeticError

    "Modified: / 26-01-2019 / 10:54:35 / Claus Gittinger"
!

overflowSignal
    "return the signal which is raised on overflow conditions (in floats).
     Attention: currently not raised on all architectures; some return NaN"

    ^ OverflowError

    "
     10e300 * 10e30
     
     10q300 * 10e30
    "

    "Modified (comment): / 22-09-2017 / 09:58:49 / cg"
!

rangeErrorSignal
    "return the parent of the overflow/underflow signals"

    ^ RangeError
!

undefinedResultSignal
    ^ ArithmeticError

    "Modified: / 26-01-2019 / 10:54:28 / Claus Gittinger"
!

underflowSignal
    "return the signal which is raised on underflow conditions (in floats)
     Attention: currently not raised on all architectures; some return zero"

    ^ UnderflowError

    "
     10e-300 / 10e30
    "

    "Modified (comment): / 22-09-2017 / 09:58:57 / cg"
!

unorderedSignal
    "return the signal which is raised when numbers are compared,
     for which no ordering is defined (for example: complex numbers)"

    ^ UnorderedNumbersError

    "
     (0 + 3i) > (0 + 4i)
     3i > 4i
    "

    "Modified (comment): / 22-09-2017 / 09:57:28 / cg"
! !

!ArithmeticValue class methodsFor:'class initialization'!

initialize
    "setup the signals"

    "/ Notice that we now use class based exceptions;
    "/ however, for backward compatibility, the class variables
    "/ referring to those are kept for a while, for subclass compatibility.
    "/ Please convert your code to access those via the Signal-constants class
    "/ messages (accessors) instead of referring to the class variables.

    ArithmeticSignal := ArithmeticError.
    "/ 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'!

coerce:aNumber
    "convert the argument aNumber into an instance of the receiver (class) and return it."

    ^ self subclassResponsibility
! !

!ArithmeticValue class methodsFor:'constants'!

NaN
    "return the constant NaN (not a Number)."

    ^ NotANumber new
!

infinity
    "return something which represents positive infinity.
     Warning: do not compare equal against infinities;
     instead, check using isFinite or isInfinite"

    ^ Infinity positive

    "Modified (comment): / 20-06-2017 / 13:45:23 / cg"
    "Modified (comment): / 09-06-2019 / 12:56:30 / Claus Gittinger"
!

nan
    "VW compatibility"

    ^ self NaN
!

negativeInfinity
    "return something which represents negative infinity.
     Warning: do not compare equal against infinities;
     instead, check using isFinite or isInfinite"

    ^ Infinity negative

    "Modified (comment): / 09-06-2019 / 12:56:36 / Claus Gittinger"
!

positiveInfinity
    "return something which represents positive infinity.
     Warning: do not compare equal against infinities;
     instead, check using isFinite or isInfinite"

    ^ self infinity

    "Created: / 09-06-2019 / 12:49:31 / Claus Gittinger"
!

unity
    "return something which represents the unity element (for my instances).
     That is the neutral element for multiplication."

    ^ self subclassResponsibility

    "Modified: / 16-06-2017 / 11:04:36 / cg"
!

zero
    "return something which represents the zero element (for my instances).
     That is the neutral element for addition."

    ^ self subclassResponsibility

    "Modified: / 16-06-2017 / 11:04:33 / cg"
! !

!ArithmeticValue class methodsFor:'error reporting'!

raise:aSignalSymbolOrErrorClass receiver:someNumber selector:sel arguments:argArray errorString:text 
    "ST-80 compatible signal raising. Provided for PD numeric classes.
     aSignalSymbolOrErrorClass is either an Error-subclass, or
     the selector which is sent to myself, to retrieve the Exception class / Signal."

    <context: #return>

    |msg signalOrException|

    msg := MessageSend
                receiver:someNumber
                selector:sel
                arguments:argArray.

    aSignalSymbolOrErrorClass isSymbol ifTrue:[
        signalOrException := self perform:aSignalSymbolOrErrorClass.
    ] ifFalse:[
        signalOrException := aSignalSymbolOrErrorClass.    "/ assume its an Error-Subclass
    ].

    ^ signalOrException
         raiseRequestWith:msg 
         errorString:text 
         in:thisContext sender

    "
     Number 
        raise:#domainErrorSignal
        receiver:1.0
        selector:#foo 
        errorString:'foo bar test'
    "

    "Modified: / 16.11.2001 / 14:12:09 / cg"
! !

!ArithmeticValue class methodsFor:'exception handling'!

trapImaginary:aBlock
    "evaluate aBlock; 
     if any ImaginaryResult 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
                    ].    
                ] ifFalse: [
                    (selector == #nthRoot:) ifTrue: [
                        ex proceedWith:(rcvr abs nthRoot:msgSend argument) 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: / 22-09-2017 / 10:18:14 / 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"
!

trapOverflow:aBlock
    "evaluate aBlock; 
     if an Overflow occurs inside, return INF and proceed."

    ^ OverflowError 
        handle: [:ex |
            |msgSend rcvr|
            
            msgSend := ex parameter.
            rcvr := msgSend receiver.
            ex proceedWith:(rcvr class positiveInfinity)
        ] do: 
            aBlock

    "
     this raises an error:
         1000 factorial asShortFloat

     this returns an imaginary result:
         Number trapOverflow: [ 1000 factorial asShortFloat]
    "

    "Created: / 07-07-2017 / 13:08:06 / cg"
    "Modified: / 09-06-2019 / 12:53:55 / Claus Gittinger"
!

trapUnderflow:aBlock
    "evaluate aBlock; 
     if an Underflow occurs inside, return zero and proceed."

    ^ UnderflowError 
        handle: [:ex |
            |msgSend rcvr|
            
            msgSend := ex parameter.
            rcvr := msgSend receiver.
            ex proceedWith:(rcvr class zero)
        ] do: 
            aBlock

    "
     this raises an error:
         1.0 / (1000 factorial)

     this returns an imaginary result:
         Number trapUnderflow: 1.0 / (1000 factorial)]
    "

    "Created: / 05-07-2017 / 13:16:43 / cg"
! !

!ArithmeticValue class methodsFor:'queries'!

isAbstract
    "Return if this class is an abstract class.
     True is returned for ArithmeticValue here; false for subclasses.
     Abstract subclasses must redefine this again."

    ^ self == ArithmeticValue
! !


!ArithmeticValue methodsFor:'arithmetic'!

* something
    "return the product of the receiver and the argument."

    ^ self subclassResponsibility
!

+ 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 quotient of the receiver and the argument"

    ^ self subclassResponsibility
!

// aNumber
    "return the integer quotient of dividing the receiver by aNumber with
     truncation towards negative infinity.

     Please be aware of the effect of truncation on negative receivers,
     and understand the difference between '//' vs. 'quo:'
     and the corresponding '\\' vs. 'rem:'"

    "/ Note: '^ (self / aNumber) floor' may lead to infinite recursion

    ^ self subclassResponsibility

    "Modified: / 05-11-1996 / 11:46:27 / cg"
    "Modified: / 12-02-1998 / 16:31:36 / stefan"
    "Modified (comment): / 16-11-2017 / 11:26:13 / mawalch"
!

\\ something
    "return the receiver modulo something.
     The remainder has the same sign as the argument, something.
     The following is always true:
        (receiver // something) * something + (receiver \\ something) = receiver

     Please be aware of the effect of truncation on negative receivers,
     and understand the difference between '//' vs. 'quo:'
     and the corresponding '\\' vs. 'rem:'."

    ^ self - ((self // something) * something)

   "
     0.9 \\ 0.4
     0.9 \\ -0.4
    -0.9 \\ 0.4
    -0.9 \\ -0.4
   "

    "Modified: / 12.2.1998 / 19:14:37 / stefan"
!

abs
    "return the absolute value of the receiver"

    (self negative) ifTrue:[^ self negated].
    ^ self
!

copySignTo:aNumber
    "Return a number with same magnitude as aNumber and same sign as self"

    (self negative == aNumber negative) ifTrue:[^ aNumber].
    ^ aNumber negated

    "
     -15 copySignTo:1234  -> -1234
     -15 copySignTo:-1234 -> -1234
     15 copySignTo:1234   -> 1234
     15 copySignTo:-1234  -> 1234
     1.0 copySignTo:0.0   -> 0.0 
     -1.0 copySignTo:0.0  -> -0.0
     1 copySignTo:(1/3)   -> (1/3) 
     -1 copySignTo:(1/3)  -> (-1/3)
    "
!

dist:arg
    "return the distance between the arg and the receiver."

    ^ (arg - self) abs

    "
     (1%1) dist:(0%0)
     (1@1) dist:(0@0)
     (1) dist:(0)
    "
!

modulusOf:aNumber
    "return aNumber modulo the receiver.
     The remainder has the same sign as something.
     Defined for protocol compatibility with ModuloNumber."

    ^ aNumber \\ self
!

negated
    "return the receiver negated"

    ^ self class zero - self
!

quo:something
    "Return the integer quotient of dividing the receiver by the argument
     with truncation towards zero.

     Please be aware of the effect of truncation on negative receivers,
     and understand the difference between '//' vs. 'quo:'
     and the corresponding '\\' vs. 'rem:'.

     The following is always true:
        (receiver quo: aNumber) * aNumber + (receiver rem: aNumber) = receiver
     For positive results, this is the same as #//,
     for negative results, the remainder is ignored.
     I.e.: '9 // 4 = 2' and '-9 // 4 = -3'
     in contrast: '9 quo: 4 = 2' and '-9 quo: 4 = -2'"

    ^ (self / something) truncated
!

reciprocal
    "return the receiver's reciprocal"

    ^ self class unity / self

    "
     (10 + 4i) class unity -> (1+0i)
     (10 + 4i) reciprocal  -> ((5/58)-(1/29)i)
     (4/3) reciprocal  -> (3/4) 
     3 reciprocal  -> (1/3) 
     3.0 reciprocal  -> 0.333333333333333 
     3.0 asLongFloat reciprocal  -> 0.3333333333333333333 
     3.0 asShortFloat reciprocal  -> 0.3333333 
    "
!

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.
     The following is always true:
        (receiver quo: something) * something + (receiver rem: something) = receiver

     Please be aware of the effect of truncation on negative receivers,
     and understand the difference between '//' vs. 'quo:'
     and the corresponding '\\' vs. 'rem:'."

    ^ self - ((self quo:something) * something)
!

uncheckedDivide:aNumber
    "return the quotient of the receiver and the argument, aNumber.
     Do not check for divide by zero (return NaN or Infinity).
     This operation is provided for emulators of other languages/semantics,
     where no exception is raised for these results (i.e. Java).
     It is only defined if the argument's type is the same as the receiver's."

    aNumber isZero ifTrue:[
        "/ protect against NaN and negativeInfinity trying to use me...
        thisContext isRecursive ifTrue:[ 
            self error:'recursive #uncheckedDivide:'.
        ].
        
        self isZero ifTrue:[^ self class NaN].
        self negative ifTrue:[^ self class negativeInfinity].
        ^ self class positiveInfinity.
    ].
    ^ self / aNumber

    "Modified (format): / 18-06-2017 / 23:43:13 / cg"
    "Modified: / 09-06-2019 / 12:53:47 / Claus Gittinger"
! !

!ArithmeticValue methodsFor:'arithmetic destructive'!

*= aNumber
    "Return the product of self multiplied by aNumber.
     The receiver MAY, but NEED NOT be changed to contain the product.
     So this method must be used as: 'a := a *= 5'.
     This method can be redefined for constructed datatypes to do optimisations"

    ^ self * aNumber

    "Created: / 28.4.1999 / 11:46:11 / stefan"
    "Modified: / 28.4.1999 / 11:53:28 / stefan"
!

+= aNumber
    "Return the sum of self and aNumber.
     The receiver MAY, but NEED NOT be changed to contain the sum.
     So this method must be used as: 'a := a += 5'.
     This method can be redefined for constructed datatypes to do optimisations"

    ^ self + aNumber

    "Created: / 28.4.1999 / 10:13:41 / stefan"
    "Modified: / 28.4.1999 / 11:54:11 / stefan"
!

-= aNumber
    "Return the difference of self and aNumber.
     The receiver MAY, but NEED NOT be changed to contain the difference.
     So this method must be used as: 'a := a -= 5'.
     This method can be redefined for constructed datatypes to do optimisations"

    ^ self - aNumber

    "Created: / 28.4.1999 / 10:13:58 / stefan"
    "Modified: / 28.4.1999 / 11:54:37 / stefan"
!

/= aNumber
    "Return the quotient of self and aNumber.
     The receiver MAY, but NEED NOT be changed to contain the quotient.
     So this method must be used as: 'a := a /= 5'.
     This method can be redefined for constructed datatypes to do optimisations"

    ^ self / aNumber

    "Created: / 28.4.1999 / 11:46:22 / stefan"
    "Modified: / 28.4.1999 / 11:55:06 / stefan"
!

div2
    "Return the quotient of self divided by 2.
     The receiver MAY, but NEED NOT be changed to contain the result.
     So this method must be used as: 'a := a div2.
     This method can be redefined for constructed datatypes to do optimisations"

    ^ self // 2

    "Created: / 28.4.1999 / 10:12:44 / stefan"
    "Modified: / 28.4.1999 / 11:56:09 / stefan"
!

mul2
    "Return the product of self multiplied by 2.
     The receiver MAY, but NEED NOT be changed to contain the result.
     So this method must be used as: a := a mul2.
     This method can be redefined for constructed datatypes to do optimisations"

    ^ self * 2

    "Created: / 28.4.1999 / 10:12:55 / stefan"
    "Modified: / 28.4.1999 / 11:56:38 / stefan"
! !

!ArithmeticValue methodsFor:'coercing & converting'!

coerce:aNumber
    "convert the argument aNumber into an instance of the receiver's class and return it."

    ^ self class coerce:aNumber

    "Modified: / 15-06-2017 / 10:27:03 / cg"
!

generality
    "return a number giving the receiver's 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:coercing:,
     which converts the lower-precision number to the higher precision
     number's class, when mixed-type arithmetic is performed."

    ^ self subclassResponsibility

    "Modified: / 5.11.1996 / 15:05:30 / cg"
    "Modified: / 13.2.1998 / 15:36:01 / stefan"
!

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."

    |hasGenerality myGenerality otherGenerality|

    hasGenerality := aNumber respondsTo:#generality.
    hasGenerality ifFalse:[
        (aSymbol == #=) ifTrue:[
            ^ false
        ].
        (aSymbol == #~=) ifTrue:[
            ^ true
        ].
        ^ ArgumentError raiseErrorString:'retry:coercing: argument is not a number'.
    ].

    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; retry should not happen'
     "same generality may happen with Lazy and LazyValue"
     ^ self perform:aSymbol with:aNumber
    
    "
        ([3] lazyValue) * ([2] lazyValue)
    "

    "Modified: / 05-11-1996 / 15:03:38 / cg"
    "Modified: / 06-06-2019 / 23:27:43 / Claus Gittinger"
!

retry:aSymbol coercing:aNumber with:anArgument
    "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."

    |hasGenerality myGenerality otherGenerality|

    hasGenerality := aNumber respondsTo:#generality.
    hasGenerality ifFalse:[
        ^ ArgumentError raiseErrorString:'retry:coercing: argument is not a number'.
    ].

    myGenerality := self generality.
    otherGenerality := aNumber generality.
    (myGenerality > otherGenerality) ifTrue:[
        ^ self perform:aSymbol with:(self coerce:aNumber) with:anArgument
    ].
    (myGenerality < otherGenerality) ifTrue:[
        ^ (aNumber coerce:self) perform:aSymbol with:aNumber with:anArgument
    ].
"/    self error:'retry:coercing: oops - same generality; retry should not happen'
     "same generality may happen with Lazy and LazyValue"
     ^ self perform:aSymbol with:aNumber with:anArgument

    "Modified: / 05-11-1996 / 15:03:38 / cg"
    "Modified: / 06-06-2019 / 23:27:50 / Claus Gittinger"
! !

!ArithmeticValue methodsFor:'converting'!

as32BitIEEEFloatBytesMSB:msb
    ^ self asShortFloat digitBytesMSB:msb

    "
        2  as32BitIEEEFloatBytesMSB:true
        2.0  as32BitIEEEFloatBytesMSB:true
    "
!

as64BitIEEEFloatBytesMSB:msb
    ^ self asFloat digitBytesMSB:msb

    "
        2  as64BitIEEEFloatBytesMSB:true
        2.0  as64BitIEEEFloatBytesMSB:true
    "
!

asDouble
    "ST80 compatibility: return a double with receiver's value.
     Attention: our floats are the identical to ST80's doubles"

   ^ self asFloat

    "Created: / 13.2.1998 / 15:40:14 / stefan"
!

asFixedPoint
    "return the receiver as fixedPoint number.
     Q: what should the scale be here ?"

    ^ self asFraction asFixedPoint

    "
     0.3 asFixedPoint
     0.5 asFixedPoint
     (1/5) asFloat asFixedPoint
     (1/3) asFloat asFixedPoint
     (2/3) asFloat asFixedPoint
     (1/8) asFloat asFixedPoint
     3.14159 asFixedPoint
     0.0000001 asFraction
     0.0000001 asFixedPoint
    "

    "Modified: / 25.10.1997 / 15:36:54 / cg"
!

asFixedPoint:scale
    "return the receiver as fixedPoint number with the given
     number of post-decimal-digits."

    ^ self asFraction asFixedPoint:scale

    "
     0.3 asFixedPoint:4
     0.3 asFixedPoint:3
     0.3 asFixedPoint:2
     0.3 asFixedPoint:1
     0.3 asFixedPoint:0

     0.5 asFixedPoint:3
     (1/5) asFloat asFixedPoint:1
     (1/8) asFloat asFixedPoint:1
     1.0 asFixedPoint:2
     3.14159 asFixedPoint:2
     3.14159 asFixedPoint:3
     (3.14159 asFixedPoint:2) asFixedPoint:5
    "
!

asFixedPointRoundedToScale
    "return the receiver as fixedPoint number, rounded to its scale."

    ^ self asFixedPoint roundedToScale

    "
     0.3 asFixedPoint
     0.5 asFixedPoint
     (2/3) asFloat asFixedPoint
     (1/8) asFloat asFixedPoint
     3.14159 asFixedPoint

     0.3 asFixedPointRoundedToScale
     0.5 asFixedPointRoundedToScale
     (2/3) asFloat asFixedPointRoundedToScale
     (1/8) asFloat asFixedPointRoundedToScale
     3.14159 asFixedPointRoundedToScale
    "

    "Created: / 02-08-2010 / 13:32:16 / cg"
!

asFixedPointRoundedToScale:scale
    "return the receiver as fixedPoint number with the given
     number of post-decimal-digits, rounded to its scale"

    ^ (self asFixedPoint:scale) roundedToScale

    "
     3.14159 asFixedPointRoundedToScale:1
     3.14159 asFixedPointRoundedToScale:2
     3.14159 asFixedPointRoundedToScale:3
     3.14159 asFixedPointRoundedToScale:4
    "

    "Created: / 02-08-2010 / 13:33:11 / cg"
!

asFloat
    "return a float with same value"

   ^ self subclassResponsibility
!

asFloatD
    "return a double precision float with same value.
     Added for ANSI compatibility"

   ^ self asFloat

    "Created: / 7.9.2001 / 13:36:48 / cg"
    "Modified: / 7.9.2001 / 13:38:10 / cg"
!

asFloatE
    "return a single precision float with same value.
     Added for ANSI compatibility"

   ^ self asShortFloat

    "Created: / 7.9.2001 / 13:37:06 / cg"
    "Modified: / 7.9.2001 / 13:38:15 / cg"
!

asFloatQ
    "return a quad precision float with same value.
     Notice that longFloats as returned here may or may not provide more
     precision than a double - depending on the machine's CPU
     (and usually do not provide quad the number of bits of a float)    
     Added for ANSI compatibility"

   ^ self asLongFloat

    "Created: / 07-09-2001 / 13:38:44 / cg"
    "Modified (comment): / 03-07-2017 / 10:19:13 / cg"
!

asFloatQD
    "return a quad double precision float with same value."

   ^ self asQDouble

    "Created: / 03-07-2017 / 10:19:41 / cg"
!

asFraction
    "return a fraction with same value"

   ^ self subclassResponsibility
!

asInteger
    "return an integer with same value - might truncate"

    ^ self truncated
!

asLargeFloat
    "return a largeFloat with same value"

    "WARNING: could loose precision here, if not redefined in concrete classes which
     have more than float precision (i.e. LargeIntegers and Fractions)"

    ^ self asFloat asLargeFloat "/ subclassResponsibility

    "Created: / 07-06-2019 / 02:32:57 / Claus Gittinger"
!

asLimitedPrecisionReal
    "return a float of any precision with same value"

   ^ self asFloat
!

asLongFloat
    "return a longFloat with same value"

    "WARNING: could loose precision here, if not redefined in concrete classes which
     have more than float precision (i.e. LargeIntegers and Fractions)"

    ^ self asFloat asLongFloat "/ subclassResponsibility

    "Modified: / 17.4.1996 / 12:21:35 / cg"
    "Created: / 7.9.2001 / 13:39:31 / cg"
!

asQuadFloat
    "return a quadFloat with same value"

    "WARNING: could loose precision here, if not redefined in concrete classes which
     have more than float precision (i.e. LargeIntegers and Fractions)"

    ^ self asFloat asQuadFloat "/ subclassResponsibility

    "Created: / 07-06-2019 / 02:28:54 / Claus Gittinger"
!

asScaledDecimal:scale
    "return a fixedPoint approximating the receiver's value"

    ^ self asFixedPoint:scale

    "
     1.234 asScaledDecimal:2
    "

    "Created: / 7.9.2001 / 13:46:26 / cg"
    "Modified: / 7.9.2001 / 13:46:44 / cg"
!

asShortFloat
    "return a shortFloat with same value"

   ^ self asFloat asShortFloat

    "Modified: 17.4.1996 / 12:21:35 / cg"
!

degreesToRadians
    "interpreting the receiver as degrees, return the radians"

    ^ self asFloat degreesToRadians
!

radiansToDegrees
    "interpreting the receiver as radians, return the degrees"

    ^ self asFloat radiansToDegrees
! !

!ArithmeticValue methodsFor:'double dispatching'!

bitAndFromInteger:anInteger
    "anInteger does not know how to do bitAnd: with the receiver -
     retry the operation by coercing to Integer"

    |selfAsInteger|

    selfAsInteger := self asInteger.
    self ~= selfAsInteger ifTrue:[
        DomainError raiseRequestErrorString:'non-integer mask in bit-operation'.
    ].

    ^ anInteger bitAnd:selfAsInteger

    "Created: / 01-11-2018 / 11:49:27 / Stefan Vogel"
!

bitOrFromInteger:anInteger
    "anInteger does not know how to do bitOr: with the receiver -
     retry the operation by coercing to Integer"

    |selfAsInteger|

    selfAsInteger := self asInteger.
    self ~= selfAsInteger ifTrue:[
        DomainError raiseRequestErrorString:'non-integer mask in bit-operation'.
    ].

    ^ anInteger bitOr:selfAsInteger

    "Created: / 01-11-2018 / 11:49:09 / Stefan Vogel"
!

bitXorFromInteger:anInteger
    "anInteger does not know how to do bitXor: with the receiver -
     retry the operation by coercing to Integer"

    |selfAsInteger|

    selfAsInteger := self asInteger.
    self ~= selfAsInteger ifTrue:[
        DomainError raiseRequestErrorString:'non-integer mask in bit-operation'.
    ].

    ^ anInteger bitXor:selfAsInteger

    "Created: / 01-11-2018 / 11:58:53 / Stefan Vogel"
!

differenceFromComplex:aComplex
    "aComplex does not know how to subtract the receiver -
     retry the operation by coercing to higher generality"

    ^ aComplex retry:#- coercing:self

    "Modified (comment): / 12-06-2017 / 20:34:41 / cg"
!

differenceFromFixedPoint:aFixedPoint
    "aFixedPoint does not know how to subtract the receiver -
     retry the operation by coercing to higher generality"

    ^ aFixedPoint retry:#- coercing:self

    "Created: / 05-11-1996 / 14:55:51 / cg"
    "Modified (comment): / 12-06-2017 / 20:34:33 / cg"
!

differenceFromFloat:aFloat
    "aFloat does not know how to subtract the receiver -
     retry the operation by coercing to higher generality"

    ^ aFloat retry:#- coercing:self

    "Modified (comment): / 12-06-2017 / 20:34:23 / cg"
!

differenceFromFraction:aFraction
    "aFraction does not know how to subtract the receiver -
     retry the operation by coercing to higher generality"

    ^ aFraction retry:#- coercing:self

    "Modified (comment): / 12-06-2017 / 20:34:16 / cg"
!

differenceFromInteger:anInteger
    "anInteger does not know how to subtract the receiver -
     retry the operation by coercing to higher generality"

    ^ anInteger retry:#- coercing:self

    "Modified (comment): / 12-06-2017 / 20:34:07 / cg"
!

differenceFromLargeFloat:aLargeFloat
    "aLargeFloat does not know how to subtract the receiver -
     retry the operation by coercing to higher generality"

    ^ aLargeFloat retry:#- coercing:self

    "Modified (comment): / 12-06-2017 / 20:34:00 / cg"
!

differenceFromLongFloat:aLongFloat
    "aLongFloat does not know how to subtract the receiver -
     retry the operation by coercing to higher generality"

    ^ aLongFloat retry:#- coercing:self

    "Created: / 17-04-1996 / 12:33:16 / cg"
    "Modified (comment): / 12-06-2017 / 20:33:50 / cg"
!

differenceFromQuadFloat:aQuadFloat
    "aQuadFloat does not know how to subtract the receiver -
     retry the operation by coercing to higher generality"

    ^ aQuadFloat retry:#- coercing:self

    "Created: / 07-06-2019 / 02:20:52 / Claus Gittinger"
!

differenceFromShortFloat:aShortFloat
    "aShortFloat does not know how to subtract the receiver -
     retry the operation by coercing to higher generality"

    ^ aShortFloat retry:#- coercing:self

    "Created: / 17-04-1996 / 12:33:16 / cg"
    "Modified (comment): / 12-06-2017 / 20:33:43 / cg"
!

equalFromComplex:aComplex
    "aComplex does not know how to compare to the receiver -
     retry the operation by coercing to higher generality"

    ^ aComplex retry:#= coercing:self

    "Modified (comment): / 12-06-2017 / 20:33:26 / cg"
!

equalFromFixedPoint:aFixedPoint
    "aFixedPoint does not know how to compare to the receiver -
     retry the operation by coercing to higher generality"

    ^ aFixedPoint retry:#= coercing:self

    "Modified (comment): / 12-06-2017 / 20:33:17 / cg"
!

equalFromFloat:aFloat
    "aFloat does not know how to compare to the receiver -
     retry the operation by coercing to higher generality"

    ^ aFloat retry:#= coercing:self

    "Modified (comment): / 12-06-2017 / 20:33:09 / cg"
!

equalFromFraction:aFraction
    "aFraction does not know how to compare to the receiver -
     retry the operation by coercing to higher generality"

    ^ aFraction retry:#= coercing:self

    "Modified (comment): / 12-06-2017 / 20:33:01 / cg"
!

equalFromInteger:anInteger
    "anInteger does not know how to compare to the receiver -
     retry the operation by coercing to higher generality"

    ^ anInteger retry:#= coercing:self

    "Modified (comment): / 12-06-2017 / 20:32:53 / cg"
!

equalFromLargeFloat:aLargeFloat
    "aLargeFloat does not know how to compare to the receiver -
     retry the operation by coercing to higher generality"

    ^ aLargeFloat retry:#= coercing:self

    "Modified (comment): / 12-06-2017 / 20:32:45 / cg"
!

equalFromLongFloat:aLongFloat
    "aLongFloat does not know how to compare to the receiver -
     retry the operation by coercing to higher generality"

    ^ aLongFloat retry:#= coercing:self

    "Modified (comment): / 12-06-2017 / 20:32:36 / cg"
!

equalFromQuadFloat:aQuadFloat
    "aQuadFloat does not know how to compare to the receiver -
     retry the operation by coercing to higher generality"

    ^ aQuadFloat retry:#= coercing:self

    "Created: / 07-06-2019 / 02:21:11 / Claus Gittinger"
!

equalFromShortFloat:aShortFloat
    "aShortFloat does not know how to compare to the receiver -
     retry the operation by coercing to higher generality"

    ^ aShortFloat retry:#= coercing:self

    "Modified (comment): / 12-06-2017 / 20:32:28 / cg"
!

integerQuotientFromInteger:anInteger
    "anInteger does not know how to divide by the receiver -
     retry the operation by coercing to higher generality"

    ^ anInteger retry:#// coercing:self

    "Created: / 09-08-2010 / 19:49:26 / cg"
!

isAlmostEqualToFromFloat:aFloat nEpsilon:nE
    "aFloat does not know how to compare to the receiver -
     retry the operation by coercing to higher generality"

    ^ aFloat retry:#isAlmostEqualTo:nEpsilon: coercing:self with:nE

    "Modified (comment): / 07-06-2019 / 02:23:00 / Claus Gittinger"
!

isAlmostEqualToFromLargeFloat:aLargeFloat nEpsilon:nE
    "aLargeFloat does not know how to compare to the receiver -
     retry the operation by coercing to higher generality"

    ^ aLargeFloat retry:#isAlmostEqualTo:nEpsilon: coercing:self with:nE

    "Created: / 07-06-2019 / 02:24:57 / Claus Gittinger"
!

isAlmostEqualToFromLongFloat:aLongFloat nEpsilon:nE
    "aLongFloat does not know how to compare to the receiver -
     retry the operation by coercing to higher generality"

    ^ aLongFloat retry:#isAlmostEqualTo:nEpsilon: coercing:self with:nE

    "Created: / 07-06-2019 / 02:22:01 / Claus Gittinger"
!

isAlmostEqualToFromQuadFloat:aQuadFloat nEpsilon:nE
    "aQuadFloat does not know how to compare to the receiver -
     retry the operation by coercing to higher generality"

    ^ aQuadFloat retry:#isAlmostEqualTo:nEpsilon: coercing:self with:nE

    "Created: / 07-06-2019 / 02:22:15 / Claus Gittinger"
!

isAlmostEqualToFromShortFloat:aShortFloat nEpsilon:nE
    "aShortFloat does not know how to compare to the receiver -
     retry the operation by coercing to higher generality"

    ^ aShortFloat retry:#isAlmostEqualTo:nEpsilon: coercing:self with:nE

    "Modified (comment): / 07-06-2019 / 02:23:25 / Claus Gittinger"
!

lessFromFixedPoint:aFixedPoint
    "aFixedPoint does not know how to compare to the receiver -
     Return true if aFixedPoint < self.
     retry the operation by coercing to higher generality"

    ^ aFixedPoint retry:#< coercing:self

    "Created: / 05-11-1996 / 14:56:12 / cg"
    "Modified (comment): / 12-06-2017 / 20:32:12 / cg"
!

lessFromFloat:aFloat
    "aFloat does not know how to compare to the receiver -
     Return true if aFloat < self.
     retry the operation by coercing to higher generality"

    ^ aFloat retry:#< coercing:self

    "Modified (comment): / 12-06-2017 / 20:32:02 / cg"
!

lessFromFraction:aFraction
    "aFraction does not know how to compare to the receiver -
     Return true if aFraction < self.
     retry the operation by coercing to higher generality"

    ^ aFraction retry:#< coercing:self

    "Modified (comment): / 12-06-2017 / 20:31:53 / cg"
!

lessFromInteger:anInteger
    "anInteger does not know how to compare to the receiver -
     Return true if anInteger < self.
     retry the operation by coercing to higher generality"

    ^ anInteger retry:#< coercing:self

    "Modified (comment): / 12-06-2017 / 20:31:44 / cg"
!

lessFromLargeFloat:aLargeFloat
    "aLargeFloat does not know how to compare to the receiver -
     Return true if aLargeFloat < self.
     retry the operation by coercing to higher generality"

    ^ aLargeFloat retry:#< coercing:self

    "Modified (comment): / 12-06-2017 / 20:31:36 / cg"
!

lessFromLongFloat:aLongFloat
    "aLongFloat does not know how to compare to the receiver -
     Return true if aLongFloat < self.
     retry the operation by coercing to higher generality"

    ^ aLongFloat retry:#< coercing:self

    "Modified: / 17-04-1996 / 12:33:33 / cg"
    "Modified (comment): / 12-06-2017 / 20:31:28 / cg"
!

lessFromQuadFloat:aQuadFloat
    "aQuadFloat does not know how to compare to the receiver -
     Return true if aQuadFloat < self.
     retry the operation by coercing to higher generality"

    ^ aQuadFloat retry:#< coercing:self

    "Created: / 07-06-2019 / 02:23:41 / Claus Gittinger"
!

lessFromShortFloat:aShortFloat
    "aShortFloat does not know how to compare to the receiver -
     Return true if aShortFloat < self.
     retry the operation by coercing to higher generality"

    ^ aShortFloat retry:#< coercing:self

    "Modified: / 17-04-1996 / 12:33:33 / cg"
    "Modified (comment): / 12-06-2017 / 20:31:18 / cg"
!

moduloFromInteger:anInteger
    "anInteger does not know how to compute the modulo from the receiver -
     retry the operation by coercing to higher generality"

    ^ anInteger retry:#\\ coercing:self

    "Created: / 12-02-2012 / 20:38:13 / cg"
!

productFromComplex:aComplex
    "aComplex does not know how to multiply the receiver -
     retry the operation by coercing to higher generality"

    ^ aComplex retry:#* coercing:self

    "Modified (comment): / 12-06-2017 / 20:31:06 / cg"
!

productFromFixedPoint:aFixedPoint
    "aFixedPoint does not know how to multiply the receiver -
     retry the operation by coercing to higher generality"

    ^ aFixedPoint retry:#* coercing:self

    "Created: / 05-11-1996 / 14:56:28 / cg"
    "Modified (comment): / 12-06-2017 / 20:30:56 / cg"
!

productFromFloat:aFloat
    "aFloat does not know how to multiply the receiver -
     retry the operation by coercing to higher generality"

    ^ aFloat retry:#* coercing:self

    "Modified (comment): / 12-06-2017 / 20:30:46 / cg"
!

productFromFraction:aFraction
    "aFraction does not know how to multiply the receiver -
     retry the operation by coercing to higher generality"

    ^ aFraction retry:#* coercing:self

    "Modified (comment): / 12-06-2017 / 20:30:38 / cg"
!

productFromInteger:anInteger
    "anInteger does not know how to multiply the receiver -
     retry the operation by coercing to higher generality"

    ^ anInteger retry:#* coercing:self

    "Modified (comment): / 12-06-2017 / 20:29:21 / cg"
!

productFromLargeFloat:aLargeFloat
    "aLargeFloat does not know how to multiply the receiver -
     retry the operation by coercing to higher generality"

    ^ aLargeFloat retry:#* coercing:self

    "Created: / 17-04-1996 / 12:33:48 / cg"
    "Modified (comment): / 12-06-2017 / 20:29:13 / cg"
!

productFromLongFloat:aLongFloat
    "aLongFloat does not know how to multiply the receiver -
     retry the operation by coercing to higher generality"

    ^ aLongFloat retry:#* coercing:self

    "Created: / 17-04-1996 / 12:33:48 / cg"
    "Modified (comment): / 12-06-2017 / 20:29:05 / cg"
!

productFromQuadFloat:aQuadFloat
    "aQuadFloat does not know how to multiply the receiver -
     retry the operation by coercing to higher generality"

    ^ aQuadFloat retry:#* coercing:self

    "Created: / 07-06-2019 / 02:24:05 / Claus Gittinger"
!

productFromShortFloat:aShortFloat
    "aShortFloat does not know how to multiply the receiver -
     retry the operation by coercing to higher generality"

    ^ aShortFloat retry:#* coercing:self

    "Created: / 17-04-1996 / 12:33:48 / cg"
    "Modified (comment): / 12-06-2017 / 20:28:56 / cg"
!

quotientFromComplex:aComplex
    "aComplex does not know how to divide by the receiver -
     retry the operation by coercing to higher generality"

    ^ aComplex retry:#/ coercing:self
!

quotientFromFixedPoint:aFixedPoint
    "aFixedPoint does not know how to divide by the receiver -
     retry the operation by coercing to higher generality"

    ^ aFixedPoint retry:#/ coercing:self

    "Created: 5.11.1996 / 14:56:41 / cg"
!

quotientFromFloat:aFloat
    "aFloat does not know how to divide by the receiver -
     retry the operation by coercing to higher generality"

    ^ aFloat retry:#/ coercing:self
!

quotientFromFraction:aFraction
    "aFraction does not know how to divide by the receiver -
     retry the operation by coercing to higher generality"

    ^ aFraction retry:#/ coercing:self
!

quotientFromInteger:aQDouble
    "aQDouble does not know how to divide by the receiver -
     retry the operation by coercing to higher generality"

    ^ aQDouble retry:#/ coercing:self

    "Modified (comment): / 12-06-2017 / 20:35:45 / cg"
!

quotientFromLargeFloat:aLargeFloat
    "aLargeFloat does not know how to divide by the receiver -
     retry the operation by coercing to higher generality"

    ^ aLargeFloat retry:#/ coercing:self

    "Created: 17.4.1996 / 12:34:00 / cg"
!

quotientFromLongFloat:aLongFloat
    "aLongFloat does not know how to divide by the receiver -
     retry the operation by coercing to higher generality"

    ^ aLongFloat retry:#/ coercing:self

    "Created: 17.4.1996 / 12:34:00 / cg"
!

quotientFromQuadFloat:aQuadFloat
    "aQuadFloat does not know how to divide by the receiver -
     retry the operation by coercing to higher generality"

    ^ aQuadFloat retry:#/ coercing:self

    "Created: / 07-06-2019 / 02:25:19 / Claus Gittinger"
!

quotientFromShortFloat:aShortFloat
    "aShortFloat does not know how to divide by the receiver -
     retry the operation by coercing to higher generality"

    ^ aShortFloat retry:#/ coercing:self

    "Created: 17.4.1996 / 12:34:00 / cg"
!

raisedFromFloat:aFloat
    "aFloat does not know how to be raised to the receiver"

    self isNumber ifTrue:[
        self isFloat ifFalse:[
            ^ self asFloat raisedFromFloat:aFloat
        ].
    ].
    ^ self raisedFromNumber:aFloat

    "Created: / 01-07-2017 / 21:18:54 / cg"
    "Modified: / 02-07-2017 / 00:44:47 / cg"
!

raisedFromNumber:aNumber
    "aNumber does not know how to be raised to the receiver 
     (i.e. how to compute aNumber^self)"

    ^ self class
        raise:#domainErrorSignal
        receiver:aNumber
        selector:#raisedTo:
        arguments:(Array with:self)
        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
    "aFloat does not know how to compute the remainder with the receiver -
     retry the operation by coercing to higher generality"

    ^ aFloat retry:#rem: coercing:self
!

remainderFromLargeFloat:aLargeFloat
    "aLargeFloat does not know how to compute the remainder with the receiver -
     retry the operation by coercing to higher generality"

    ^ aLargeFloat retry:#rem: coercing:self

    "Created: / 07-06-2019 / 02:25:57 / Claus Gittinger"
!

remainderFromLongFloat:aLongFloat
    "aLongFloat does not know how to compute the remainder with the receiver -
     retry the operation by coercing to higher generality"

    ^ aLongFloat retry:#rem: coercing:self

    "Created: / 07-06-2019 / 02:25:43 / Claus Gittinger"
!

remainderFromQuadFloat:aQuadFloat
    "aQuadFloat does not know how to compute the remainder with the receiver -
     retry the operation by coercing to higher generality"

    ^ aQuadFloat retry:#rem: coercing:self

    "Created: / 07-06-2019 / 02:26:08 / Claus Gittinger"
!

remainderFromShortFloat:aShortFloat
    "aShortFloat does not know how to compute the remainder with the receiver -
     retry the operation by coercing to higher generality"

    ^ aShortFloat retry:#rem: coercing:self
!

sumFromComplex:aComplex
    "aComplex does not know how to add the receiver -
     retry the operation by coercing to higher generality"

    ^ aComplex retry:#+ coercing:self

    "Modified (comment): / 12-06-2017 / 20:27:25 / cg"
!

sumFromFixedPoint:aFixedPoint
    "aFixedPoint does not know how to add the receiver -
     retry the operation by coercing to higher generality"

    ^ aFixedPoint retry:#+ coercing:self

    "Created: / 05-11-1996 / 14:56:56 / cg"
    "Modified (comment): / 12-06-2017 / 20:27:38 / cg"
!

sumFromFloat:aFloat
    "aFloat does not know how to add the receiver -
     retry the operation by coercing to higher generality"

    ^ aFloat retry:#+ coercing:self

    "Modified (comment): / 12-06-2017 / 20:27:47 / cg"
!

sumFromFraction:aFraction
    "aFraction does not know how to add the receiver -
     retry the operation by coercing to higher generality"

    ^ aFraction retry:#+ coercing:self

    "Modified (comment): / 12-06-2017 / 20:27:55 / cg"
!

sumFromInteger:anInteger
    "anInteger does not know how to add the receiver -
     retry the operation by coercing to higher generality"

    ^ anInteger retry:#+ coercing:self

    "Modified (comment): / 12-06-2017 / 20:28:03 / cg"
!

sumFromLargeFloat:aLargeFloat
    "aLargeFloat does not know how to add the receiver -
     retry the operation by coercing to higher generality"

    ^ aLargeFloat retry:#+ coercing:self

    "Created: / 17-04-1996 / 12:34:10 / cg"
    "Modified (comment): / 12-06-2017 / 20:28:11 / cg"
!

sumFromLongFloat:aLongFloat
    "aLongFloat does not know how to add the receiver -
     retry the operation by coercing to higher generality"

    ^ aLongFloat retry:#+ coercing:self

    "Created: / 17-04-1996 / 12:34:10 / cg"
    "Modified (comment): / 12-06-2017 / 20:28:19 / cg"
!

sumFromQuadFloat:aQuadFloat
    "aQuadFloat does not know how to add the receiver -
     retry the operation by coercing to higher generality"

    ^ aQuadFloat retry:#+ coercing:self

    "Created: / 07-06-2019 / 02:26:36 / Claus Gittinger"
!

sumFromShortFloat:aShortFloat
    "aShortFloat does not know how to add the receiver -
     retry the operation by coercing to higher generality"

    ^ aShortFloat retry:#+ coercing:self

    "Created: / 17-04-1996 / 12:34:10 / cg"
    "Modified (comment): / 12-06-2017 / 20:28:39 / cg"
! !

!ArithmeticValue methodsFor:'mathematical functions'!

** aNumber
    "Answer the receiver raised to the power of the argument, aNumber."
    "same as Number>>raisedTo:"

    ^self raisedTo: aNumber

    "Created: / 15-07-2006 / 15:11:05 / cg"
    "Modified: / 17-07-2006 / 12:51:33 / cg"
!

basicRaisedToInteger:exp
    "return the receiver raised to exp.
     Warning: if the receiver is a float/double, 
     currently INF may be returned on overflow. 
     This may be changed silently to raise an error in future versions."

    |result e t|

    "use the addition chaining algorithm,
     which is much faster for big exponents"

    result := 1.
    t := self.
    exp < 0 ifTrue:[
        e := exp negated.
    ] ifFalse:[
        e := exp.
    ].

    [e ~~ 0] whileTrue:[
        [(e bitAnd:1) == 0] whileTrue:[
            e := e bitShift:-1.
            t := t * t.
        ].
        e := e - 1.
        result := result * t.
    ].

    (exp < 0) ifTrue:[
        ^ 1 / result
    ].

    ^ result

    "
     (2.0 raisedToInteger:216)
     (2 raisedToInteger:216)
     (2 raisedTo:216)
            -> 105312291668557186697918027683670432318895095400549111254310977536

     (2 raisedToInteger:216) asFloat
     (2 raisedTo:216) asFloat
            -> 1.05312E+65

     (2 raisedToInteger:500)
     (2 raisedTo:500)
            -> 3273390607896141870013189696827599152216642046043064789483291368096133796404674554883270092325904157150886684127560071009217256545885393053328527589376
     (2 raisedTo:-500)
            -> (1/3273390607896141870013189696827599152216642046043064789483291368096133796404674554883270092325904157150886684127560071009217256545885393053328527589376)
     2 raisedToInteger:10
            -> 1024
    -2 raisedToInteger:10
            -> 1024
     -2 raisedToInteger:9
            -> -512
     10 raisedToInteger:-10
            -> (1/10000000000)
     2 raisedToInteger:0
            -> 1
     2 raisedToInteger:-1
            -> (1/2)

     Time millisecondsToRun:[
        10000 timesRepeat:[
            (2 raisedToInteger:500)
        ]
     ]

     Time millisecondsToRun:[
        |bigNum|
        bigNum := 2 raisedToInteger:500.
        10 timesRepeat:[
            (bigNum raisedToInteger:500)
        ]
     ]
    "

    "Created: / 27-04-1999 / 15:19:22 / stefan"
    "Modified (comment): / 13-06-2017 / 17:35:41 / cg"
!

raisedTo: aNumber
    "return the receiver raised to aNumber (i.e. self ^ aNumber)"

    aNumber isInteger ifTrue:[
        ^ self raisedToInteger:aNumber
    ].
    self raisedFromNumber:aNumber.      "/ this raises an error.

    "
     2 raisedTo:16
     2.0 raisedTo:16

     3 raisedTo:4
     10@10 raisedTo:4
     10@10 raisedTo:4.0
    "

    "Modified (format): / 01-07-2017 / 20:59:35 / cg"
!

raisedToInteger:exp
    "return the receiver raised to exp.
     Warning: if the receiver is a float/double, 
     currently INF may be returned on overflow. 
     This may be changed silently to raise an error in future versions."

    ^ self basicRaisedToInteger:exp

    "
     (2.0 raisedToInteger:10000)
     (2 raisedToInteger:10000)
     (2 raisedToInteger:-10000)

     (2.0 raisedToInteger:216)
     (2 raisedToInteger:216)
     (2 raisedTo:216)
            -> 105312291668557186697918027683670432318895095400549111254310977536

     (2 raisedToInteger:216) asFloat
     (2 raisedTo:216) asFloat
            -> 1.05312E+65

     (2 raisedToInteger:500)
     (2 raisedTo:500)
            -> 3273390607896141870013189696827599152216642046043064789483291368096133796404674554883270092325904157150886684127560071009217256545885393053328527589376
     2 raisedToInteger:10
            -> 1024
    -2 raisedToInteger:10
            -> 1024
     -2 raisedToInteger:9
            -> -512
     10 raisedToInteger:-10
            -> (1/10000000000)
     2 raisedToInteger:0
            -> 1
     2 raisedToInteger:-1
            -> (1/2)

     Time millisecondsToRun:[
        10000 timesRepeat:[
            (2 raisedToInteger:500)
        ]
     ]

     Time millisecondsToRun:[
        |bigNum|
        bigNum := 2 raisedToInteger:500.
        10 timesRepeat:[
            (bigNum raisedToInteger:500)
        ]
     ]
    "

    "Created: / 27-04-1999 / 15:19:22 / stefan"
    "Modified (comment): / 13-06-2017 / 17:35:20 / cg"
!

squared
    "return receiver * receiver"

    ^ self * self
! !

!ArithmeticValue methodsFor:'queries'!

respondsToArithmetic
    "return true, if the receiver responds to arithmetic messages"

    ^ true
! !

!ArithmeticValue methodsFor:'testing'!

denominator
    "return the denominator of the receiver"

    ^ 1
!

even
    "return true if the receiver is divisible by 2.
     This is only defined for whole-numbers (integers)."

    ^ self class
        raise:#domainErrorSignal
        receiver:self
        selector:#even
        arguments:#()
        errorString:'Receiver must be a whole-number'

    "/ No no no, the following is bad: 
    "/      ^ self truncated asInteger even

    "
     2.4 even
     2.0 even
    "

    "Modified (comment): / 03-07-2017 / 14:10:01 / cg"
!

isComplex
    "Answer whether the receiver has an imaginary part
     (i.e. if it is a complex number). Always false here."

    ^ false

    "Modified: / 9.7.1998 / 10:19:27 / cg"
!

isFinite
    "return true, if the receiver is finite
     i.e. it can be represented as a rational number."

    ^ true
!

isInfinite
    ^ false
!

isNegativeInfinity
    ^ self negative and:[self isInfinite]
!

isNegativeZero
    "return false - must be redefined by subclasses which can represent a negative zero
     (i.e. limitedPrecisionReal classes)"

    ^ false
!

isPositiveInfinity
    ^ self positive and:[self isInfinite]
!

isReal
    "return true, if the receiver is some kind of real number (as opposed to a complex);
     false is returned here - the method is only redefined in Number (and Complex)."

    ^ false

    "Modified: / 6.11.2001 / 13:20:20 / cg"
    "Created: / 6.11.2001 / 13:26:29 / cg"
!

isZero
    "return false - must be redefined by subclasses which can represent a negative zero
     (i.e. limitedPrecisionReal classes)"

    ^ self = self class zero
!

negative
    "return true if the receiver is less than zero."

    ^ self < self class zero
!

numerator
    "return the numerator of the receiver."

    ^ self
!

odd
    "return true if the receiver is not divisible by 2"

    ^ self even not
!

positive
    "return true, if the receiver is greater or equal to zero (not negative)"

    ^ self negative not
!

sign
    "return the sign of the receiver (-1, 0 or 1)"

    |zero|

    zero := self class zero.
    (self < zero) ifTrue:[^ -1].
    (zero < self) ifTrue:[^ 1].
    ^ 0
!

strictlyPositive
    "return true, if the receiver is greater than zero"

    ^ self class zero < self
! !

!ArithmeticValue methodsFor:'truncation & 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
!

roundTo:aNumber
    "return the receiver rounded to multiples of aNumber"

    ^ (self / aNumber) rounded * aNumber

    "
     0 roundTo:4
     1 roundTo:4
     2 roundTo:4
     3 roundTo:4
     4 roundTo:4
     5 roundTo:4
     6 roundTo:4
     7 roundTo:4

     7.123 roundTo:0.1
     7.523 roundTo:0.1
     7.583 roundTo:0.1 
     7.623 roundTo:0.1
     7.623 roundTo:0.01 
     7.628 roundTo:0.01 
    "
!

roundUpTo:aNumber
    "return the receiver rounded up to the next multiple of aNumber"

    ^ (self / aNumber) ceiling * aNumber

    "
     0 roundUpTo:4
     1 roundUpTo:4
     2 roundUpTo:4
     3 roundUpTo:4
     4 roundUpTo:4
     5 roundUpTo:4
     6 roundUpTo:4
     7 roundUpTo:4
     8 roundUpTo:4
     (3@4) roundUpTo:8
     (3@4) roundUpTo:(5 @ 4)
     (3@3) roundUpTo:(5 @ 4) 
    "
!

rounded
    "return the integer nearest the receiver"

    self negative ifTrue:[
	^ (self - 0.5) ceiling
    ].
    ^ (self + 0.5) floor

    "Modified: 5.11.1996 / 11:31:59 / cg"
!

truncateTo:aNumber
    "return the receiver truncated to multiples of aNumber"

    |t|
    
    aNumber <= 0 ifTrue:[ArgumentError raiseErrorString:'argument must be positive'].
    
    t := (self / aNumber) floor * aNumber.
    (aNumber isInteger) ifTrue:[
        ^ t asInteger
    ].    
    ^ t

    "
     truncate to multiples of 4 
        123.456 truncateTo:4
        124.456 truncateTo:4
     truncate to multiples of 2 
        122.456 truncateTo:2
        123.456 truncateTo:2
        124.456 truncateTo:2
     normal truncate
        123.456 truncateTo:1
        124.456 truncateTo:1
     truncate to decimal digits    
        123.456 truncateTo:0.1
        123.987 truncateTo:0.1
        123.456 truncateTo:0.01
    "

    "Modified: / 06-06-2019 / 23:27:55 / Claus Gittinger"
!

truncated
    "return the receiver truncated towards zero"

    self negative ifTrue:[
	^ self ceiling
    ].
    ^ self floor
! !

!ArithmeticValue class methodsFor:'documentation'!

version
    ^ '$Header$'
!

version_CVS
    ^ '$Header$'
! !


ArithmeticValue initialize!