LimitedPrecisionReal.st
author Stefan Vogel <sv@exept.de>
Wed, 07 Jan 1998 13:04:09 +0100
changeset 3148 1434542209e7
parent 3137 f334b17f0347
child 3185 1c7bd090a822
permissions -rw-r--r--
New #finite, define #isInfinite using #finite.

"
 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 raise.
    ].
"/ 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"
!

// 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"
!

\\ aNumber
    "return the integer remainder of dividing the receiver by aNumber with
    truncation towards negative infinity."

    ^ (self - ((self / aNumber) floor * aNumber)) floor asInteger
! !

!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:3     
     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: 10.1.1997 / 19:59:42 / 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"

    |l v sign max maxF|

    self isNaN ifTrue:[
        ^ DomainErrorSignal raise
    ].

    max := SmallInteger maxVal // 2 + 1.
    maxF := max asFloat.
    ^ (self quo:maxF) * max + (self rem:maxF) truncated

    "
     12345.0 asInteger
     1e15 asInteger
     1e33 asInteger
    "

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

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"

    aStream nextPutAll:self printString
!

printString
    "return a printed representation of the receiver"

    ^ self subclassResponsibility

    "Created: 17.4.1996 / 12:12:20 / cg"
! !

!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 methodsFor:'truncation and rounding'!

fractionPart
    "return a float with value from digits after the decimal point.
     (i.e. the receiver minus its truncated value)"

    ^ self - self truncated asFloat

    "
     1234.56789 fractionPart
     1.2345e6 fractionPart  
    "

    "Modified: 4.11.1996 / 20:26:54 / cg"
!

integerPart
    "return a float with value from digits before the decimal point
     (i.e. the truncated value)"

    ^ self truncated asFloat

    "
     1234.56789 integerPart 
     1.2345e6 integerPart   
    "

    "Modified: 4.11.1996 / 20:26:21 / cg"
! !

!LimitedPrecisionReal class methodsFor:'documentation'!

version
    ^ '$Header: /cvs/stx/stx/libbasic/LimitedPrecisionReal.st,v 1.23 1998-01-07 12:04:09 stefan Exp $'
! !