FixedPoint.st
author Claus Gittinger <cg@exept.de>
Tue, 26 Nov 2002 11:45:55 +0100
changeset 6895 2434bee328c1
parent 6894 64f27ed2753f
child 6897 7282c0dc54d3
permissions -rw-r--r--
checkin from browser

"
     This is public domain code, not covered by the ST/X copyright.
     Code is provided 'as is', as a goody, without any warranty.

     this comes from:

     Jan Steinman, Bytesmiths
     2002 Parkside Court, West Linn, OR 97068-2767 USA, +1 503 657 7703
     Friedlistrasse 19, CH-3006, Bern, Switzerland, +41 31 999 3946

     this code was published in comp.lang.smalltalk; 
     added here as an example ...
"

"{ Package: 'stx:libbasic' }"

Fraction subclass:#FixedPoint
	instanceVariableNames:'scale'
	classVariableNames:'PI_1000'
	poolDictionaries:''
	category:'Magnitude-Numbers'
!

FixedPoint comment:'
Description: This class implements infinite precision fixed-point numbers. 
It doesn''t really do anything too interesting except creating instances, converting, and printing, 
since its superclass Fraction does all the work.

Test: "''123456789012345678901234567890.123456789'' asFixed * 1000000000 = 123456789012345678901234567890123456789"

Notes: 1) The current implementation does not convert arbitrarily-based String representations, 
          which shouldn''t be too much a problem for financial types.'
!

!FixedPoint class methodsFor:'documentation'!

copyright
"
     This is public domain code, not covered by the ST/X copyright.
     Code is provided 'as is', as a goody, without any warranty.

     this comes from:

     Jan Steinman, Bytesmiths
     2002 Parkside Court, West Linn, OR 97068-2767 USA, +1 503 657 7703
     Friedlistrasse 19, CH-3006, Bern, Switzerland, +41 31 999 3946

     this code was published in comp.lang.smalltalk; 
     added here as an example ...
"
!

documentation
"
    Description: This class implements infinite precision fixed-point numbers,
    which internally hold exact (fractional) results, but print themself with
    a limited number of digits after the decimal point. 
    These can be used in computation, where rounding errors should not accumulate,
    but only a limited precision is required for the final result.
    (i.e. business applications)

    It doesn't really do anything too interesting except creating instances, 
    converting, and printing, since its superclass Fraction does all the work.

    Test: 
        '123456789012345678901234567890.123456789' asFixedPoint * 1000000000
        -> 123456789012345678901234567890123456789'

    Notes: 1) The current implementation does not convert arbitrarily-based 
              String representations, which shouldn't be too much a problem 
              for financial types.

           2) the implementation is a hack - it has not been optimized for speed
              in particular.

    Mixed mode arithmetic:
        fix op fix       -> fix, scale is max. of operands
        fix op fraction  -> fix; scale is fix's scale
        fix op integer   -> fix; scale is fix's scale
        fix op float     -> float

    [author:]
        Jan Steinman, Bytesmiths
        adapted, modified & enhanced by Claus Gittinger

    [see also:]
        Integer Float Number Fraction
"
!

examples
"
                                                                [exBegin]
     |a b r|

     a := (FixedPoint fromString:'123.456').
     b := '1.10' asFixedPoint.
     r := a + b.
     Transcript showCR:r.
     Transcript showCR:(r withScale:2).
     Transcript showCR:(r withScale:1).
     Transcript showCR:(r rounded).
                                                                [exEnd]

                                                                [exBegin]
     |a b r|

     a := (FixedPoint fromString:'0.9999999').
     b := 0.0000001 asFixedPoint. 
     r := a + b.
     Transcript showCR:r.
     Transcript showCR:(r withScale:2).
     Transcript showCR:(r withScale:1).
     Transcript showCR:(r rounded).
                                                                [exEnd]

                                                                [exBegin]
     |a b r|

     a := (FixedPoint fromString:'0.9999998').
     b := (FixedPoint fromString:'0.0000001').
     r := a + b.
     Transcript showCR:r.
     Transcript showCR:(r withScale:2).
     Transcript showCR:(r withScale:1).
     Transcript showCR:(r rounded).
                                                                [exEnd]

                                                                [exBegin]
     |a b r|

     a := (FixedPoint fromString:'1.0').
     b := (FixedPoint fromString:'0.0000001').
     r := a + b.
     Transcript showCR:r.
     Transcript showCR:(r withScale:2).
     Transcript showCR:(r withScale:1).
     Transcript showCR:(r rounded).
                                                                [exEnd]

                                                                [exBegin]
     |a b r|

     a := (FixedPoint fromString:'0.99').
     b := (FixedPoint fromString:'0.0000001').
     r := a + b.
     Transcript showCR:r.
     Transcript showCR:(r withScale:2).
     Transcript showCR:(r withScale:1).
     Transcript showCR:(r rounded).
                                                                [exEnd]

"
! !

!FixedPoint class methodsFor:'instance creation'!

numerator:n denominator:d 
    self shouldNotImplement. "use #numerator:denominator:scale"
    "/ ^ self numerator:n denominator:d scale:(d log max:n log) ceiling

    "
     self numerator:123 denominator:100    
    "
!

numerator:n denominator:d scale:s
    ^ self basicNew
        setNumerator:n denominator:d scale:s
        "/ ; reduced
!

readFrom:aStringOrStream 
    "return the next FixedPoint from the (character-)stream aStream. 

     NOTICE:   
       This behaves different from the default readFrom:, in returning
       0 (instead of raising an error) in case no number can be read.
       It is unclear, if this is the correct behavior (ST-80 does this)
       - depending on the upcoming ANSI standard, this may change."

    ^ self readFrom:aStringOrStream onError:0

    "
     FixedPoint readFrom:'123.456'
     FixedPoint readFrom:'3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679821480865132823066470938446095505822317253594081284811174502841027019385211055596446229489549303819644288109756659334461284756482337867831652712019091456485669234603486104543266482133936072602491412737245870066063155881748815209209628292540917153643678925903600113305305488204665213841469519415116094330572703657595919530921861173819326117931051185480744623799627495673518857527248912279381830119491298336733624406566430860213949463952247371907021798609437027705392171762931767523846748184676694051320005681271452635608277857713427577896091736371787214684409012249534301465495853710507922796892589235420199561121290219608640344181598136297747713099605187072113499999983729780499510597317328160963185950244594553469083026425223082533446850352619311881710100031378387528865875332083814206171776691473035982534904287554687311595628638823537875937519577818577805321712268066130019278766111959092164201989380952572010654858632788'
     FixedPoint readFrom:(ReadStream on:'foobar')     
     FixedPoint readFrom:(ReadStream on:'foobar') onError:nil  
    "

    "Modified: / 25.10.1997 / 15:30:29 / cg"
!

readFrom:aStringOrStream onError:exceptionBlock
    "return an instance of me as described on the string or stream, aStringOrStream.
     If an error occurs during conversion, return the result
     from evaluating exceptionBlock"

    | aStream sign integerPart fractionStream char fractionPart scale |

    aStream := aStringOrStream readStream.

    aStream peek == $- ifTrue:[
        sign := -1.
        aStream next.
    ] ifFalse:[
        sign := 1
    ].

    (aStream atEnd or:[aStream peek isLetter]) ifTrue: [^ exceptionBlock value].

    integerPart := (aStream upTo:$.) asNumber.
    (aStream atEnd or: [aStream peek isLetter]) ifTrue: [
        fractionPart := 0.
        scale := 1.
    ] ifFalse:[
        fractionStream := ReadWriteStream on:(String new: 10).
        [
            char := aStream next.
            char ~~ nil and:[char isDigit]
        ] whileTrue:[
            fractionStream nextPut:char
        ].

        scale := fractionStream positionStartingAt0.
        fractionStream reset.
        fractionPart := Number readFrom:fractionStream.
    ].

    ^ self basicNew 
        setNumerator:(integerPart * (10 raisedTo:scale) + fractionPart) * sign
        scale:scale

    "
     FixedPoint readFrom:'1.00' 
     FixedPoint readFrom:'123.456'
     FixedPoint readFrom:'-123.456' 
     FixedPoint readFrom:'123' 
     FixedPoint readFrom:'-123' 
     FixedPoint readFrom:'-123.abcd' onError:[47.5] 
     FixedPoint readFrom:'-1a.bcd' onError:[47.5] 
     FixedPoint readFrom:'foot' onError:['bad fixedpoint'] 
    "

    "Created: / 25.10.1997 / 15:28:59 / cg"
    "Modified: / 25.10.1997 / 15:31:47 / cg"
! !

!FixedPoint class methodsFor:'constants'!

pi
    "pi with 1000 valid digits..."

    PI_1000 isNil ifTrue:[
        PI_1000 := self
                     readFrom:'3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679821480865132823066470938446095505822317253594081284811174502841027019385211055596446229489549303819644288109756659334461284756482337867831652712019091456485669234603486104543266482133936072602491412737245870066063155881748815209209628292540917153643678925903600113305305488204665213841469519415116094330572703657595919530921861173819326117931051185480744623799627495673518857527248912279381830119491298336733624406566430860213949463952247371907021798609437027705392171762931767523846748184676694051320005681271452635608277857713427577896091736371787214684409012249534301465495853710507922796892589235420199561121290219608640344181598136297747713099605187072113499999983729780499510597317328160963185950244594553469083026425223082533446850352619311881710100031378387528865875332083814206171776691473035982534904287554687311595628638823537875937519577818577805321712268066130019278766111959092164201989380952572010654858632788'
    ].
    ^ PI_1000.

    "
     self pi squared    
     self pi reciprocal 
     1 / self pi 
     self pi * 1000000000000000000000000000000000000000000    
    "
! !


!FixedPoint methodsFor:'accessing'!

scale
    "return the number of places of significance that is carried by the receiver."

    ^ scale

    "Modified: 12.4.1997 / 11:21:05 / cg"
! !

!FixedPoint methodsFor:'arithmetic'!

* aNumber
    "return the product of the receiver and the argument, aNumber.
     Redefined to care for the scale if the argument is another fixPoint number.
     The results scale is the maximum of the receivers scale and the arguments
     scale."

    aNumber isInteger ifTrue:[
        ^ self class 
                numerator:(numerator * aNumber)
                denominator:denominator
                scale:scale
    ].
    aNumber isFraction ifTrue:[
        ^ self class 
            numerator:(numerator * aNumber numerator) 
            denominator:(denominator * aNumber denominator)
            scale:(scale max:aNumber scale)
    ].
    ^ aNumber productFromFixedPoint:self

    "                       
     |a r|

     a := (FixedPoint fromString:'123.456').
     r := a * 5.    
     Transcript showCR:r.    
     Transcript showCR:(r withScale:2).
    "

    "                       
     |a b r|

     a := (FixedPoint fromString:'123.456').
     b := (FixedPoint fromString:'1.10').
     r := a * b.    
     Transcript showCR:r.    
     Transcript showCR:(r withScale:2).
    "

    "                       
     |a b r|

     a := (FixedPoint fromString:'123.456').
     b := (FixedPoint fromString:'-1.10').
     r := a * b.    
     Transcript showCR:r.    
     Transcript showCR:(r withScale:2).
    "

    "
     |a b r|

     a := (FixedPoint fromString:'0.9999999').
     b := (FixedPoint fromString:'0.9999999').
     r := a * b.    
     Transcript show:'fixed (exact)  : '; showCR:r.    
     Transcript show:'fixed (scale2) : '; showCR:(r withScale:2).

     Transcript show:'float (inexact): '; showCR:(0.9999999 * 0.9999999).
    "

    "
     |a b r|

     a := 1.
     b := (FixedPoint fromString:'0.9999999').
     r := a * b.    
     Transcript show:'fixed (exact)  : '; showCR:r.    
     Transcript show:'fixed (scale2) : '; showCR:(r withScale:2).

     Transcript show:'float (inexact): '; showCR:(0.9999999 * 0.9999999).
    "

    "                       
     |a r|

     a := (FixedPoint fromString:'123.456').
     r := a * 5.0.    
     Transcript showCR:r.    
     Transcript showCR:(r withScale:2).
    "

    "                       
     |a r|

     a := (FixedPoint fromString:'123.456').
     r := 5.0 * a.    
     Transcript showCR:r.    
     Transcript showCR:(r withScale:2).
    "
!

+ aNumber
    "return the sum of the receiver and the argument, aNumber.
     Redefined to care for the scale if the argument is another fixPoint number.
     The results scale will be the maximum of the receivers and the
     arguments scale."

    |n d|

    (aNumber isInteger or:[aNumber isFraction]) ifTrue:[
        n := aNumber numerator.
        d := aNumber denominator.

        "save a multiplication if possible"
        denominator == d ifTrue:[
            ^ self class 
                numerator:(numerator + n) 
                denominator:d
                scale:scale
        ].

        ^ self class 
                numerator:((numerator * d) + (n * denominator))
                denominator:(denominator * d)
                scale:scale
    ].
    aNumber isFixedPoint ifTrue:[  
        n := aNumber numerator.
        d := aNumber denominator.

        "save a multiplication if possible"
        denominator == d ifTrue:[
            n := numerator + n
        ] ifFalse:[
            n := (numerator * d) + (n * denominator).
            d := denominator * d.
        ].
        ^ self class 
                numerator:n 
                denominator:d
                scale:(scale max:aNumber scale)
    ].
    ^ aNumber sumFromFixedPoint:self

    "
     |a b|

     a := (FixedPoint fromString:'123.456').
     b := (FixedPoint fromString:'1.10').
     a + b
    "

    "
     |a b|

     a := (FixedPoint fromString:'0.9999999').
     b := (FixedPoint fromString:'0.0000001').
     a + b                   
    "

    "
     |a b|

     a := (FixedPoint fromString:'0.99').
     b := (FixedPoint fromString:'0.0000001').
     a + b                             
    "

    "
     |a b|

     a := (FixedPoint fromString:'0.99').
     b := (FixedPoint fromString:'0.0000001').
     (a + b) withScale:2  
    "

    "
     |a b|

     a := (FixedPoint fromString:'0.99').
     b := (FixedPoint fromString:'0.0000001').
     (a + b) withScale:1  
    "

    "
     |a b|

     a := 1.
     b := (FixedPoint fromString:'0.0000001').
     Transcript showCR:((a + b) withScale:1).
     Transcript showCR:(a + b)
    "
!

- aNumber
    "return the difference of the receiver and the argument, aNumber.
     Redefined to care for the scale if the argument is another fixPoint number.
     The results scale is the maximum of the receivers scale and the arguments
     scale."

    |n d|

    (aNumber isInteger or:[aNumber isFraction]) ifTrue:[
        n := aNumber numerator.
        d := aNumber denominator.

        "save a multiplication if possible"
        denominator == d ifTrue:[
            ^ self class 
                numerator:(numerator - n) 
                denominator:d
                scale:scale
        ].

        ^ self class 
                numerator:((numerator * d) - (n * denominator))
                denominator:(denominator * d)
                scale:scale
    ].
    aNumber isFixedPoint ifTrue:[
        n := aNumber numerator.
        d := aNumber denominator.

        "save a multiplication if possible"
        denominator == d ifTrue:[
            n := numerator - n
        ] ifFalse:[
            n := (numerator * d) - (n * denominator).
            d := denominator * d
        ].
        ^ self class 
                numerator:n 
                denominator:d
                scale:(scale max:aNumber scale)
    ].
    ^ aNumber differenceFromFixedPoint:self

    "
     |a b|

     a := (FixedPoint fromString:'123.456').
     b := (FixedPoint fromString:'1.10').
     a - b    
    "

    "
     |a b|

     a := (FixedPoint fromString:'0.9999999').
     b := (FixedPoint fromString:'0.0000009').
     a - b                   
    "

    "
     |a b|

     a := (FixedPoint fromString:'0.99').
     b := (FixedPoint fromString:'0.0000001').
     a - b                          
    "

    "
     |a b|

     a := (FixedPoint fromString:'0.99').
     b := (FixedPoint fromString:'0.0000001').
     (a - b) withScale:2  
    "

    "
     |a b|

     a := (FixedPoint fromString:'0.99').
     b := (FixedPoint fromString:'0.0000001').
     (a - b) withScale:1  
    "

    "
     |a b|

     a := (FixedPoint fromString:'0.0000001').
     b := (FixedPoint fromString:'0.99').
     (a - b) withScale:2   
    "

    "
     |a b|

     a := 1.
     b := (FixedPoint fromString:'0.0000001').
     Transcript showCR:((a - b) withScale:1).
     Transcript showCR:(a - b)
    "
!

/ aNumber
    "return the quotient of the receiver and the argument, aNumber.
     Redefined to care for the scale if the argument is another fixPoint number.
     The results scale is the maximum of the receivers scale and the arguments
     scale."

    aNumber isInteger ifTrue:[
        ^ self class 
                numerator:numerator
                denominator:(denominator * aNumber)
                scale:scale
    ].

    aNumber isFraction ifTrue:[
        ^ self class 
            numerator:(numerator * aNumber denominator) 
            denominator:(denominator * aNumber numerator)
            scale:(scale max:aNumber scale)
    ].
    ^ aNumber quotientFromFixedPoint:self

    "                       
     |a r|                     

     a := (FixedPoint fromString:'123.456').
     r := a / 5.    
     Transcript showCR:r.    
     Transcript showCR:(r withScale:2).
     Transcript showCR:(r withScale:9).
    "

    "                       
     |a b r|

     a := (FixedPoint fromString:'123.456').
     b := (FixedPoint fromString:'1.10').
     r := a / b.    
     Transcript showCR:r.    
     Transcript showCR:(r withScale:2).
    "

    "                       
     |a b r|

     a := (FixedPoint fromString:'-123.456').
     b := (FixedPoint fromString:'-1.10').
     r := a / b.    
     Transcript showCR:r.    
     Transcript showCR:(r withScale:2).
    "

    "                       
     |a b r|

     a := (FixedPoint fromString:'123.456').
     b := (FixedPoint fromString:'-1.10').
     r := a / b.    
     Transcript showCR:r.    
     Transcript showCR:(r withScale:2).
    "

    "
     |a b r|

     a := 1.
     b := (FixedPoint fromString:'0.9999999').
     r := a / b.    
     Transcript show:'fixed (exact)  : '; showCR:r.    
     Transcript show:'fixed (scale2) : '; showCR:(r withScale:2).

     Transcript show:'float (inexact): '; showCR:(1 / 0.9999999).
    "
!

negated
    "redefined from Fraction to preserve scale"

    ^ self class 
        numerator:(numerator negated)
        denominator:denominator
        scale:scale
!

reciprocal
    "redefined from Fraction to preserve scale"

    numerator == 1 ifTrue:[^ denominator].
    ^ self class 
        numerator:denominator
        denominator:numerator
        scale:scale
! !

!FixedPoint methodsFor:'coercing & converting'!

asFixedPoint
    "return the receiver as a fixedPoint number - thats the receiver itself"

    ^ self

    "Modified: 10.1.1997 / 19:53:14 / cg"
!

asFixedPoint:newScale
    "return a copy of the receiver, with newScale number of post-decimal
     digits"

    ^ self class
        numerator:numerator
        denominator:denominator
        scale:newScale

    "
     '12345.12345' asFixedPoint:2   
     (FixedPoint fromString:'12345.12345') asFixedPoint:2 

     ((FixedPoint fromString:'0.33333333')
      + 
      (FixedPoint fromString:'0.33333333')
     ) asFixedPoint:2   
    "

    "Modified: 12.4.1997 / 11:20:37 / cg"
!

asFraction
    "return the receiver as a fraction"

    ^ (Fraction
        numerator:numerator
        denominator:denominator)

    "
     (FixedPoint fromString:'0.2')           
     (FixedPoint fromString:'0.2') asFraction
     (FixedPoint fromString:'0.2') asFloat
     (FixedPoint fromString:'0.2') asShortFloat
     (FixedPoint fromString:'0.2') asInteger
    "
!

coerce:aNumber
    "return aNumber converted into receivers type"

    ^ aNumber asFixedPoint

!

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

    ^ 65

    "
     (FixedPoint fromString:'1.001') + 1      
     (FixedPoint fromString:'1.001') + 1.0    
     (FixedPoint fromString:'1.001') + (1/2)   
     (FixedPoint fromString:'1.001') + 1.0 asShortFloat 
     (FixedPoint fromString:'1.001') + 1 asLargeInteger 

     1 + (FixedPoint fromString:'1.001') 
     1.0 + (FixedPoint fromString:'1.001')      
     (1/2) + (FixedPoint fromString:'1.001')    
     1.0 asShortFloat + (FixedPoint fromString:'1.001')
     1 asLargeInteger + (FixedPoint fromString:'1.001')
    "
! !

!FixedPoint methodsFor:'double dispatching'!

differenceFromInteger:anInteger
    "sent when an integer does not know how to subtract the receiver.
     Redefined here to preserve the scale."

    ^ (self class 
        numerator:((anInteger * denominator) - numerator)
        denominator:denominator
        scale:scale)
!

productFromInteger:anInteger
    "sent when an integer does not know how to multiply the receiver.
     Redefined here to preserve the scale."

    ^ (self class 
        numerator:(anInteger * numerator)
        denominator:denominator
        scale:scale)

    "Modified: 5.11.1996 / 10:32:28 / cg"
!

quotientFromInteger:anInteger
    "sent when an integer does not know how to divide by the receiver.
     Redefined here to preserve the scale."

    ^ (self class 
        numerator:(anInteger * denominator)
        denominator:numerator
        scale:scale)

    "Modified: 5.11.1996 / 10:32:35 / cg"
!

sumFromInteger:anInteger
    "sent when an integer does not know how to add the receiver.
     Redefined here to preserve the scale."

    ^ (self class 
        numerator:(numerator + (anInteger * denominator))
        denominator:denominator
        scale:scale)

    "Modified: 5.11.1996 / 10:32:43 / cg"
! !

!FixedPoint methodsFor:'printing & storing'!

printOn: aStream 
    "append to the argument, aStream, a printed representation of the receiver.
     For printout, only scale post-decimal digits are printed
     (and the printout is rounded to that many digits)"

    |e integerPart fractionPart negative num|

    numerator < 0 ifTrue:[
        negative := true.
        num := numerator negated.
    ] ifFalse:[
        negative := false.
        num := numerator.
    ].
    integerPart := (num // denominator).
    e := 10 raisedTo:scale.
    fractionPart := (num \\ denominator).

    "/ the most common case is a denominator fitting the scale
    "/ (fixedPoint numbers are created this way)

    e == denominator ifFalse:[
        fractionPart := fractionPart * (e * 10) // denominator.
        fractionPart := (fractionPart roundTo:10) // 10.

        fractionPart >= e ifTrue:[
            integerPart := integerPart + 1.
            fractionPart := 0.
        ]
    ].

    "/
    "/ add a 1000..., so we can (mis-)use integer-printString ...
    "/ the highest-1 will be cutoff after padding.
    "/
    fractionPart := e + fractionPart.

    negative ifTrue:[
        aStream nextPut:$-
    ].
    integerPart printOn:aStream.
    aStream nextPut: $..
    ((fractionPart printStringPaddedTo:scale with:$0) copyFrom:2) printOn:aStream

    "
     (FixedPoint fromString:'0.66666666')               
     (FixedPoint fromString:'0.66666666') withScale:2   
     (FixedPoint fromString:'0.99999999')               
     (FixedPoint fromString:'0.99999999') withScale:2   
     (FixedPoint fromString:'1.00000001')               
     (FixedPoint fromString:'1.00000001') withScale:2   
     (FixedPoint fromString:'1.005')                    
     (FixedPoint fromString:'1.005') withScale:2        
     (FixedPoint fromString:'1.005') withScale:1        

     (FixedPoint fromString:'-0.66666666')              
     (FixedPoint fromString:'-0.66666666') withScale:2   
     (FixedPoint fromString:'-0.99999999')              
     (FixedPoint fromString:'-0.99999999') withScale:2   
     (FixedPoint fromString:'-1.00000001')              
     (FixedPoint fromString:'-1.00000001') withScale:2   
     (FixedPoint fromString:'-1.005')                   
     (FixedPoint fromString:'-1.005') withScale:2       
     (FixedPoint fromString:'-1.005') withScale:1       
     (FixedPoint fromString:'-1.05')                    
     (FixedPoint fromString:'-1.05') withScale:2      
     (FixedPoint fromString:'-1.05') withScale:1      
     (FixedPoint fromString:'-1.04')                  
     (FixedPoint fromString:'-1.04') withScale:2      
     (FixedPoint fromString:'-1.04') withScale:1      
    "

    "
     |a b r|

     a := (FixedPoint fromString:'0.66666666') withScale:2.
     b := (FixedPoint fromString:'0.33333333').
     r := (a + b) withScale:4.
     Transcript show:'printout with scale of 4 :'; showCR:r.
     Transcript show:'more precise value       :'; showCR:(r withScale:8)
    "

    "Modified: 12.4.1997 / 11:20:51 / cg"
! !

!FixedPoint methodsFor:'private'!

reduced
    |gc|

    scale isNil ifTrue:[
        "/ to catch inherited Fraction reduce calls
        self error:'should not happen'.
        scale := 3
    ].

    (denominator < 0) ifTrue:[
        numerator := numerator negated.
        denominator := denominator negated
    ].

    denominator == 1 ifTrue:[^ numerator].
    numerator == 1 ifTrue:[^ self].
    numerator == 0 ifTrue:[^ 0].

    gc := numerator gcd:denominator.
    gc < 0 ifTrue:[
        gc := gc negated
    ].
    gc := gc gcd:(10 raisedToInteger:scale).

    (gc ~~ 1) ifTrue:[
        numerator := numerator // gc.
        denominator := denominator // gc.
        denominator == 1 ifTrue:[^ numerator].
    ].

    ^ self
!

scale:newScale 
    "set the scale."

    scale := newScale.

    "Modified: / 12.4.1997 / 11:22:02 / cg"
    "Created: / 5.8.1998 / 13:28:49 / cg"
!

setNumerator:nInteger denominator:d scale:s 
    "initialize the instance variables.
     Assumes that the fraction as specified by numerator and denominator
     is already reduced."

    scale := s.
    super
        setNumerator:nInteger 
        denominator:d

    "Modified: 12.4.1997 / 11:21:47 / cg"
!

setNumerator:nInteger scale:s 
    "initialize the instance variables.
     Assumes that the fraction as specified by numerator and denominator
     is already reduced."

    scale := s.
    super
        setNumerator:nInteger 
        denominator:(10 raisedTo:s)

    "Modified: 12.4.1997 / 11:21:55 / cg"
!

setScale:newScale 
    "initialize the scale instance variables."

    scale := newScale.

    "Modified: 12.4.1997 / 11:22:02 / cg"
! !


!FixedPoint methodsFor:'testing'!

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

    ^ true


! !

!FixedPoint class methodsFor:'documentation'!

version
    ^ '$Header: /cvs/stx/stx/libbasic/FixedPoint.st,v 1.23 2002-11-26 10:45:55 cg Exp $'
! !