LimitedPrecisionReal.st
author Claus Gittinger <cg@exept.de>
Thu, 19 Aug 1999 03:20:08 +0200
changeset 4615 e480d1e6090f
parent 4455 2d31d0d986be
child 5238 f7a816a660a3
permissions -rw-r--r--
largFloat -> largeInt conversion fixed.

"
 COPYRIGHT (c) 1994 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.
"

Number subclass:#LimitedPrecisionReal
	instanceVariableNames:''
	classVariableNames:''
	poolDictionaries:''
	category:'Magnitude-Numbers'
!

!LimitedPrecisionReal class methodsFor:'documentation'!

copyright
"
 COPYRIGHT (c) 1994 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
"
    Abstract superclass for single and double (and maybe more) 
    precision real numbers (i.e. Float and Double).

    Due to historic reasons, ST/X's Floats are what Doubles are in ST-80.
    This may change soon (implementing LPReal is a first step towards this).

    [author:]
        Claus Gittinger

    [see also:]
        Fraction FixedPoint
"
! !

!LimitedPrecisionReal class methodsFor:'instance creation'!

new:aNumber
    "catch this message - not allowed for floats/doubles"

    self error:'Floats/Doubles cannot be created with new:'
! !

!LimitedPrecisionReal methodsFor:'accessing'!

at:index
    "redefined to prevent access to individual bytes in a real."

    self error:'not allowed for floats/doubles'
!

at:index put:aValue
    "redefined to prevent access to individual bytes in a real"

    self error:'not allowed for floats/doubles'
!

size
   "redefined since reals are kludgy (ByteArry)"

   ^ 0
! !

!LimitedPrecisionReal methodsFor:'arithmetic'!

* aNumber
    "return the product of the receiver and the argument, aNumber"

"/ as soon as Float are float & Double are doubles,
"/ use:
"/    ^ aNumber productFromDouble:self asDouble

    ^ aNumber productFromFloat:self asFloat

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

+ aNumber
    "return the sum of the receiver and the argument, aNumber"

"/ as soon as Float are float & Double are doubles,
"/ use:
"/    ^ aNumber sumFromDouble:self asDouble

    ^ aNumber sumFromFloat:self asFloat

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

- aNumber
    "return the difference of the receiver and the argument, aNumber"

"/ as soon as Float are float & Double are doubles,
"/ use:
"/    ^ aNumber differenceFromDouble:self asDouble

    ^ aNumber differenceFromFloat:self asFloat

    "Modified: 17.4.1996 / 12:36:07 / cg"
!

/ aNumber
    "return the quotient of the receiver and the argument, aNumber"

    ((aNumber == 0) or:[aNumber = 0.0]) ifTrue:[
        ^ DivisionByZeroSignal raiseRequest.
    ].
"/ as soon as Float are float & Double are doubles,
"/ use:
"/    ^ aNumber quotientFromDouble:self asDouble

    ^ aNumber quotientFromFloat:self asFloat

    "Modified: / 17.4.1996 / 12:36:21 / cg"
    "Modified: / 26.7.1999 / 10:46:11 / stefan"
!

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

    ^ (self / aNumber) floor asInteger

    "Modified: 5.11.1996 / 11:45:37 / cg"
! !

!LimitedPrecisionReal methodsFor:'coercion and converting'!

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  
     3.14159 asFixedPoint:2       
     3.14159 asFixedPoint:3       
     (3.14159 asFixedPoint:2) asFixedPoint:5  
    "

    "Modified: / 5.8.1998 / 13:29:51 / cg"
!

asFraction
    "return a corresponding fraction or integer
     (fractions with 1 as denominator are not allowed/useful)
     - notice, that 'aFract asFloat asFraction' does not always return
     a good fraction ... due to rounding errors when converting to float"

    |fract digits power num denom eI|

    "we (indirectly) use printf which knows the precision of floats"

    fract := self fractionPart.
    fract = 0.0 ifTrue:[
        ^ self asInteger.
    ].

    "/ use printf, so we dont need to know anything
    "/ about float representation here.

    digits := (fract printfPrintString:'%.16f').
    eI := digits size.
    [(digits at:eI) == $0] whileTrue:[
        eI := eI - 1
    ].

    power := eI - 3 + 1.
    num := (self - fract) asInteger.
    denom := (10 raisedToInteger:power).
    num := num * denom.
    num := num + (fract * denom) asInteger.

    ^ Fraction numerator:num denominator:denom

    "
     0.3 asFraction 
     0.5 asFraction 
     (1/5) asFloat asFraction
     (1/8) asFloat asFraction
     (1/13) asFloat asFraction
     3.14159 asFraction 
     1.3 asFraction
     1.0 asFraction
    "

    "Modified: / 25.10.1997 / 16:41:19 / cg"
!

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

    |max maxF|

    self isNaN ifTrue:[
        ^ self class
            raise:#domainErrorSignal
            receiver:self
            selector:#asInteger
            errorString:'receiver is NaN in #asInteger'

    ].

    self abs < 2e16 ifTrue:[
        "/ NOTICE: this must be redefined in float
        "/ subclasses to handle the smallinteger range;
        "/ i.e. this may only be invoked for reals
        "/ which are NOT within the smallInt range.
        "/ otherwise, endless recursion is the consequence.

        max := SmallInteger maxVal // 2 + 1.
        maxF := max asFloat.

        ^ (self quo:maxF) * max + (self rem:maxF) truncated
    ].
    ^ self asTrueFraction

    "
     12345.0 asInteger     
     1e15 asInteger        
     1e33 asInteger asFloat
     1e303 asInteger asFloat
    "

    "Modified: 12.2.1997 / 16:45:07 / cg"
!

coerce:aNumber
    "return aNumber converted into receivers type"

"/ as soon as Float are float & Double are doubles,
"/ use:
"/    ^ aNumber asDouble

    ^ aNumber asFloat

    "Modified: 17.4.1996 / 12:36:46 / cg"
!

fractionalPart
    "This has been renamed to #fractionPart for ST80 compatibility.

     extract the after-decimal fraction part.
     the floats value is 
        float truncated + float fractionalPart"

    self obsoleteMethodWarning:'please use #fractionPart'.
    ^ self fractionPart

    "Modified: / 28.10.1998 / 17:10:12 / cg"
    "Created: / 28.10.1998 / 17:10:32 / cg"
!

generality
    "return the generality value - see ArithmeticValue>>retry:coercing:"

    ^ 80
! !

!LimitedPrecisionReal methodsFor:'comparing'!

< aNumber
    "return true, if the argument is greater"

"/ as soon as Float are float & Double are doubles,
"/ use:
"/    ^ aNumber lessFromDouble:self asDouble

    ^ aNumber lessFromFloat:self asFloat

    "Modified: 17.4.1996 / 13:34:50 / cg"
!

<= aNumber
    "return true, if the argument is greater or equal"

    ^ self retry:#<= coercing:aNumber
!

= aNumber
    "return true, if the arguments value are equal"

    ^ self retry:#= coercing:aNumber
!

> aNumber
    "return true, if the argument is less"

    ^ self retry:#> coercing:aNumber
!

>= aNumber
    "return true, if the argument is less or equal"

    ^ self retry:#>= coercing:aNumber
!

~= aNumber
    "return true, if the arguments value are not equal"

    ^ self retry:#~= coercing:aNumber
! !

!LimitedPrecisionReal methodsFor:'copying'!

deepCopy
    "return a deep copy of myself
     - because storing into floats is not recommended/allowed, its ok to return the receiver"

    ^ self
!

deepCopyUsing:aDictionary
    "return a deep copy of myself
     - because storing into floats is not recommended/allowed, its ok to return the receiver"

    ^ self
!

shallowCopy
    "return a shallow copy of the receiver"

    ^ self
!

simpleDeepCopy
    "return a deep copy of the receiver
     - because storing into floats is not recommended/allowed, its ok to return the receiver"

    ^ self
! !

!LimitedPrecisionReal methodsFor:'double dispatching'!

differenceFromFraction:aFraction
    "sent when a fraction does not know how to subtract the receiver, a float"

    |d|

    d := aFraction denominator.
    ^ (aFraction numerator - (self * d)) / d
!

productFromFraction:aFraction
    "sent when a fraction does not know how to multiply the receiver, a float"

    ^ self * aFraction numerator / aFraction denominator
!

quotientFromFraction:aFraction
    "sent when a fraction does not know how to divide by the receiver, a float"

    ^ aFraction numerator / (self * aFraction denominator)
!

sumFromFraction:aFraction
    "sent when a fraction does not know how to add the receiver, a float"

    |d|

    d := aFraction denominator.
    ^ (self * d + aFraction numerator) / d
! !

!LimitedPrecisionReal methodsFor:'printing & storing'!

printOn:aStream
    "append a printed representation of the receiver to
     the argument, aStream.

     LimitedPrecisonReal and its subclasses use #printString instead of
     #printOn: as basic print mechanism."

    aStream nextPutAll:self printString

    "Modified: / 20.1.1998 / 14:10:46 / stefan"
!

printString
    "return a printed representation of the receiver
     LimitedPrecisonReal and its subclasses use #printString instead of
     #printOn: as basic print mechanism."

    ^ self subclassResponsibility

    "Created: / 17.4.1996 / 12:12:20 / cg"
    "Modified: / 20.1.1998 / 14:10:47 / stefan"
! !

!LimitedPrecisionReal methodsFor:'testing'!

isFinite
   ^ self subclassResponsibility

    "Created: / 7.1.1998 / 12:02:06 / stefan"
!

isInfinite
    "return true, if the receiver is an infinite float (Inf).
     These are not created by ST/X float operations (they raise an exception);
     however, inline C-code could produce them ..."

    ^ (self isFinite or:[self isNaN]) not.

    "
        1.0 isInfinite
        (0.0 uncheckedDivide: 0.0) isInfinite
        (1.0 uncheckedDivide: 0.0) isInfinite
    "

    "Modified: / 7.1.1998 / 12:01:30 / stefan"
!

isNaN
   ^ self subclassResponsibility

    "Modified: 12.2.1997 / 16:45:27 / cg"
!

isReal
    "return true, if the receiver is some kind of real number;
     false is returned here - the method is redefined from Object."

    ^ true
!

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

"/ as soon as Float are float & Double are doubles,
"/ use:
"/    ^ self asDouble negative

    ^ self asFloat negative

    "Modified: 17.4.1996 / 13:35:00 / cg"
!

positive
    "return true if the receiver is greater or equal to zero"

"/ as soon as Float are float & Double are doubles,
"/ use:
"/    ^ self asDouble positive

    ^ self asFloat positive

    "Modified: 17.4.1996 / 13:35:10 / cg"
! !

!LimitedPrecisionReal class methodsFor:'documentation'!

version
    ^ '$Header: /cvs/stx/stx/libbasic/LimitedPrecisionReal.st,v 1.32 1999-08-19 01:20:08 cg Exp $'
! !