"
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 position0Based.
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 class methodsFor:'queries'!
exponentCharacter
^ $s
! !
!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."
"/ notice:
"/ the following code handles some common cases,
"/ and exists as an optimization, to speed up those cases.
"/ also notice, that checks for those cases must be inlinable without
"/ a message send; otherwise double-dispatch is just as fast.
(aNumber isMemberOf:SmallInteger) ifTrue:[
^ self class
numerator:(numerator * aNumber)
denominator:denominator
scale: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|
"/ notice:
"/ the following code handles some common cases,
"/ and exists as an optimization, to speed up those cases.
"/ also notice, that checks for those cases must be inlinable without
"/ a message send; otherwise double-dispatch is just as fast.
(aNumber isMemberOf:SmallInteger) ifTrue:[
"save a multiplication if possible"
denominator == 1 ifTrue:[
n := numerator + aNumber.
] ifFalse:[
n := numerator + (aNumber * denominator).
].
^ self class
numerator:n
denominator:denominator
scale:scale
].
^ aNumber sumFromFixedPoint:self
"
((1/3) asFixedPoint:2) + 1
((1/3) asFixedPoint:2) + (1/3)
"
"
|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|
"/ notice:
"/ the following code handles some common cases,
"/ and exists as an optimization, to speed up those cases.
"/ also notice, that checks for those cases must be inlinable without
"/ a message send; otherwise double-dispatch is just as fast.
(aNumber isMemberOf:SmallInteger) ifTrue:[
"save a multiplication if possible"
denominator == 1 ifTrue:[
n := numerator - aNumber.
] ifFalse:[
n := numerator - (aNumber * denominator).
].
^ self class
numerator:n
denominator:denominator
scale: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."
"/ notice:
"/ the following code handles some common cases,
"/ and exists as an optimization, to speed up those cases.
"/ also notice, that checks for those cases must be inlinable without
"/ a message send; otherwise double-dispatch is just as fast.
(aNumber isMemberOf:SmallInteger) ifTrue:[
^ self class
numerator:numerator
denominator:(denominator * aNumber)
scale: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 fixedPoint with the same value as the receiver,
and newScale number of post-decimal digits"
newScale == scale ifTrue:[^ self].
^ 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'!
differenceFromFixedPoint:aFixedPoint
|n d otherNumerator otherDenominator|
otherNumerator := aFixedPoint numerator.
otherDenominator := aFixedPoint denominator.
"save a multiplication if possible"
denominator = otherDenominator ifTrue:[
n := otherNumerator - numerator.
d := otherDenominator.
] ifFalse:[
n := (otherNumerator * denominator) - (numerator * otherDenominator).
d := denominator * otherDenominator.
].
^ self class
numerator:n
denominator:d
scale:(scale max:aFixedPoint scale)
"
((1/3) asFixedPoint:2) - ((1/3) asFixedPoint:2)
((1/3) asFixedPoint:2) - ((2/3) asFixedPoint:2)
(1/3) - ((2/3) asFixedPoint:2)
((1/3) asFixedPoint:2) - ((1/3) asFixedPoint:4)
((1/3) asFixedPoint:2) - ((2/3) asFixedPoint:4)
"
!
differenceFromFraction:aFraction
|n d otherNumerator otherDenominator|
otherNumerator := aFraction numerator.
otherDenominator := aFraction denominator.
"save a multiplication if possible"
denominator = otherDenominator ifTrue:[
n := otherNumerator - numerator.
d := otherDenominator.
] ifFalse:[
n := (otherNumerator * denominator) - (numerator * otherDenominator).
d := denominator * otherDenominator.
].
^ self class
numerator:n
denominator:d
scale:scale
"
(1/3) - ((2/3) asFixedPoint:2)
"
!
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
!
productFromFixedPoint:aFixedPoint
^ aFixedPoint class
numerator:(aFixedPoint numerator * numerator)
denominator:(aFixedPoint denominator * denominator)
scale:(scale max:aFixedPoint scale)
"
((1/3) asFixedPoint:2) * ((1/3) asFixedPoint:4)
(1/3) * ((1/3) asFixedPoint:4)
"
!
productFromFraction:aFraction
^ self class
numerator:(aFraction numerator * numerator)
denominator:(aFraction denominator * denominator)
scale:scale
"
(1/3) * ((1/3) asFixedPoint:4)
"
!
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"
!
quotientFromFixedPoint:aFixedPoint
^ aFixedPoint class
numerator:(aFixedPoint numerator * denominator)
denominator:(aFixedPoint denominator * numerator)
scale:(scale max:aFixedPoint scale)
"
((1/3) asFixedPoint:2) / ((1/3) asFixedPoint:2)
((1/3) asFixedPoint:2) / ((1/3) asFixedPoint:4)
"
!
quotientFromFraction:aFraction
^ aFraction class
numerator:(aFraction numerator * denominator)
denominator:(aFraction denominator * numerator)
scale:scale
"
((1/3) asFixedPoint:2) / ((1/3) asFixedPoint:2)
((1/3) asFixedPoint:2) / ((1/3) asFixedPoint:4)
"
!
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"
!
sumFromFixedPoint:aFixedPoint
|n d otherNumerator otherDenominator|
otherNumerator := aFixedPoint numerator.
otherDenominator := aFixedPoint denominator.
"save a multiplication if possible"
denominator = otherDenominator ifTrue:[
n := numerator + otherNumerator.
d := otherDenominator.
] ifFalse:[
n := (numerator * otherDenominator) + (otherNumerator * denominator).
d := denominator * otherDenominator.
].
^ self class
numerator:n
denominator:d
scale:(scale max:aFixedPoint scale)
"
((1/3) asFixedPoint:2) + ((1/3) asFixedPoint:2)
((1/3) asFixedPoint:2) + ((2/3) asFixedPoint:2)
((1/3) asFixedPoint:2) + ((1/3) asFixedPoint:4)
"
!
sumFromFraction:aFraction
|n d otherNumerator otherDenominator|
otherNumerator := aFraction numerator.
otherDenominator := aFraction denominator.
"save a multiplication if possible"
denominator = otherDenominator ifTrue:[
n := numerator + otherNumerator.
d := otherDenominator.
] ifFalse:[
n := (numerator * otherDenominator) + (otherNumerator * denominator).
d := denominator * otherDenominator.
].
^ self class
numerator:n
denominator:d
scale:scale
"
(1/3) + ((1/3) asFixedPoint:2)
"
!
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.
scale > 0 ifTrue:[
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:'1.5')
(FixedPoint fromString:'1.5') withScale:2
(FixedPoint fromString:'1.5') withScale:1
(FixedPoint fromString:'1.5') withScale:0
(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.27 2003-06-16 09:14:24 cg Exp $'
! !