LimitedPrecisionReal.st
author claus
Fri, 11 Aug 1995 05:05:04 +0200
changeset 384 cc3d110ea879
parent 379 5b5a130ccd09
child 482 2c64ba46a853
permissions -rw-r--r--
.

"
 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 comment:'
COPYRIGHT (c) 1994 by Claus Gittinger
	      All Rights Reserved

$Header: /cvs/stx/stx/libbasic/LimitedPrecisionReal.st,v 1.8 1995-08-11 03:01:23 claus Exp $
'!

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

version
"
$Header: /cvs/stx/stx/libbasic/LimitedPrecisionReal.st,v 1.8 1995-08-11 03:01:23 claus Exp $
"
!

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

!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:'copying'!

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
!

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

    ^ self
!

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

    ^ self
! !
    
!LimitedPrecisionReal methodsFor:'accessing'!

size
   "redefined since reals are kludgy (ByteArry)"

   ^ 0
!

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

!LimitedPrecisionReal methodsFor:'arithmetic'!

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

    ^ aNumber sumFromDouble:self asDouble
!

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

    ^ aNumber differenceFromDouble:self asDouble
!

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

    ^ aNumber productFromDouble:self asDouble
!

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

    ((aNumber == 0) or:[aNumber = 0.0]) ifTrue:[
	^ DivisionByZeroSignal raise.
    ].
    ^ aNumber quotientFromDouble:self asDouble
!

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

    ^ (self / aNumber) floor asInteger
!

\\ 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:'testing'!

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

    ^ self asDouble positive
!

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

    ^ self asDouble negative
! !

!LimitedPrecisionReal methodsFor:'comparing'!

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

    ^ aNumber lessFromDouble:self asDouble
!

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

    ^ self retry:#> coercing:aNumber
!

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

    ^ 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 equal"

    ^ self retry:#= coercing:aNumber
!

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

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

!LimitedPrecisionReal methodsFor:'coercion and converting'!

coerce:aNumber
    "return aNumber converted into receivers type"

    ^ aNumber asDouble
!

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

    ^ 80
!

asFraction
    "return a corresponding fraction
     - 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|

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

    fract := self fractionPart.
    digits := fract printString copyFrom:3.
    power := digits size.
    num := (self - fract) asInteger.
    denom := (10 raisedToInteger:power).
    num := num * denom.
    num := num + (Integer readFromString:digits).
    ^ (Fraction numerator:num denominator:denom) reduced

    "0.3 asFraction"
    "0.5 asFraction"
    "(1/5) asFloat asFraction"
    "(1/8) asFloat asFraction"
    "(1/13) asFloat asFraction -> inexact result due to rounding errors"
!

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

    |l v sign|

    "this is stupid code - rounding errors accumulate; fix later"

    sign := self sign.
    v := self abs.
    (v >= 10.0) ifTrue:[
	l := (v / 10.0) asInteger * 10
    ] ifFalse:[
	l := 0
    ].
    v := v - ((v / 10.0) floor * 10) floor.
    l := l + v truncated.
    ^ l * sign

    "12345.0 asInteger"
    "1e15 asInteger"
! !

!LimitedPrecisionReal methodsFor:'double dispatching'!

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
!

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

!LimitedPrecisionReal methodsFor:'truncation and rounding'!

fractionPart
    "return a float with value from digits after the decimal point"

    ^ self - self truncated asFloat

    "1234.56789 fractionPart"
    "1.2345e6 fractionPart"
! !

!LimitedPrecisionReal methodsFor:'printing & storing'!

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

    aStream nextPutAll:self printString
! !