--- a/Fraction.st Fri Jun 13 20:52:21 2003 +0200
+++ b/Fraction.st Mon Jun 16 11:14:59 2003 +0200
@@ -207,32 +207,21 @@
* aNumber
"return the product of the receiver and the argument, aNumber"
- |n d|
-
- "/
"/ 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.
"/
"/ Conceptionally, (and for most other argument types),
"/ mixed arithmetic is implemented by double dispatching
"/ (see the message send at the bottom)
- "/
- aNumber isInteger ifTrue:[
+ (aNumber isMemberOf:SmallInteger) ifTrue:[
^ self class
numerator:(numerator * aNumber)
denominator:denominator
].
- aNumber isFraction ifTrue:[
- aNumber isFixedPoint ifFalse:[ "/ the value was corrent, but the scale is lost
- n := numerator * aNumber numerator.
- d := denominator * aNumber denominator.
- ^ self class
- numerator:n
- denominator:d
- ]
- ].
(aNumber isMemberOf:Float) ifTrue:[
^ (numerator * aNumber) / denominator
].
@@ -245,42 +234,23 @@
+ aNumber
"return the sum of the receiver and the argument, aNumber"
- |n d|
-
- "/
"/ 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.
"/
"/ Conceptionally, (and for most other argument types),
"/ mixed arithmetic is implemented by double dispatching
"/ (see the message send at the bottom)
- "/
- aNumber isInteger ifTrue:[
+ (aNumber isMemberOf:SmallInteger) ifTrue:[
^ self class
- numerator:(numerator + (denominator * aNumber))
- denominator:denominator
- ].
- aNumber isFraction ifTrue:[
- aNumber isFixedPoint ifFalse:[ "/ the value was correct, but the scale is lost
- 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
- ]
+ numerator:(numerator + (denominator * aNumber))
+ denominator:denominator
].
(aNumber isMemberOf:Float) ifTrue:[
- ^ aNumber + self asFloat
+ ^ (numerator asFloat / denominator asFloat) + aNumber
].
^ aNumber sumFromFraction:self
@@ -291,40 +261,21 @@
- aNumber
"return the difference of the receiver and the argument, aNumber"
- |n d|
-
- "/
"/ 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.
"/
"/ Conceptionally, (and for most other argument types),
"/ mixed arithmetic is implemented by double dispatching
"/ (see the message send at the bottom)
- "/
- aNumber isInteger ifTrue:[
+ (aNumber isMemberOf:SmallInteger) ifTrue:[
^ self class
numerator:(numerator - (denominator * aNumber))
denominator:denominator
].
- aNumber isFraction ifTrue:[
- aNumber isFixedPoint ifFalse:[ "/ the value was corrent, but the scale is lost
- 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
- ]
- ].
(aNumber isMemberOf:Float) ifTrue:[
^ (numerator asFloat / denominator asFloat) - aNumber
].
@@ -345,32 +296,21 @@
/ aNumber
"return the quotient of the receiver and the argument, aNumber"
- |n d|
-
- "/
"/ 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.
"/
"/ Conceptionally, (and for most other argument types),
"/ mixed arithmetic is implemented by double dispatching
"/ (see the message send at the bottom)
- "/
- aNumber isInteger ifTrue:[
+ (aNumber isMemberOf:SmallInteger) ifTrue:[
^ self class
numerator:numerator
denominator:(denominator * aNumber)
].
- aNumber isFraction ifTrue:[
- aNumber isFixedPoint ifFalse:[ "/ the value was corrent, but the scale is lost
- n := numerator * aNumber denominator.
- d := denominator * aNumber numerator.
- ^ self class
- numerator:n
- denominator:d
- ]
- ].
(aNumber isMemberOf:Float) ifTrue:[
^ numerator / (denominator * aNumber)
].
@@ -514,6 +454,51 @@
^ self asInteger asLargeInteger
!
+asLongFloat
+ "return a long float with (approximately) my value"
+
+ |num den numShift denShift bits|
+
+ (numerator class == SmallInteger and:[denominator class == SmallInteger]) ifTrue:[
+ ^ (numerator asLongFloat) / (denominator asLongFloat)
+ ].
+
+ "Do it the hard way: reduce magnitude and undo reduction on the quotient"
+
+ bits := LongFloat precision * 2. "number of bits to preserve (conservative)"
+ num := numerator abs.
+ numShift := bits - num highBit. "(num highBit - bits) negated"
+ numShift < 0 ifTrue:[num := num bitShift:numShift] ifFalse:[numShift := 0].
+
+ den := denominator.
+ denShift := bits - den highBit. "(den highBit - bits) negated"
+ denShift < 0 ifTrue:[den := den bitShift:denShift] ifFalse:[denShift := 0].
+
+ ^ (num asLongFloat / den asLongFloat) * (2.0 raisedToInteger:denShift-numShift) * (num sign)
+
+ "
+ (5/9) asLongFloat
+ (-5/9) asLongFloat
+ (500000000000/900000000000) asLongFloat
+ (-500000000000/900000000000) asLongFloat
+ (500000000000/9) asLongFloat
+ (5/900000000000) asLongFloat
+ 89012345678901234567 asFloat / 123456789123456789 asLongFloat
+ (89012345678901234567 / 123456789123456789) asLongFloat
+
+ (
+ 180338700661043257034670206806167960222709397862806840937993331366591676308781197477183367018067356365812757479444845320188679437752013593674158587947149815441890236037219685250845721864713487208757788709113534916165172927384095182655935222723385253851776639985379367854545495930551624041981995105743408203125
+ /
+ 180331613628627651967947866455016278082980736719853750685591387625058011528928110602436691256100991596843001549483950600930062886280582766771424470965440873615557144641435276844465734361353086032476712374317224249252177316815544331763696909434844464464323192083930469387098582956241443753242492675781250
+ ) asLongFloat
+
+ 180338700661043257034670206806167960222709397862806840937993331366591676308781197477183367018067356365812757479444845320188679437752013593674158587947149815441890236037219685250845721864713487208757788709113534916165172927384095182655935222723385253851776639985379367854545495930551624041981995105743408203125
+ asLongFloat /
+ 180331613628627651967947866455016278082980736719853750685591387625058011528928110602436691256100991596843001549483950600930062886280582766771424470965440873615557144641435276844465734361353086032476712374317224249252177316815544331763696909434844464464323192083930469387098582956241443753242492675781250
+ asLongFloat
+ "
+!
+
asShortFloat
"return a short float with (approximately) my value"
@@ -548,21 +533,9 @@
"return true if the receiver is less
than aNumber, false otherwise."
- |d n|
-
(aNumber isMemberOf:SmallInteger) ifTrue:[
^ numerator < (denominator * aNumber)
].
- aNumber isFraction ifTrue:[
- d := aNumber denominator.
- n := aNumber numerator.
-
- "/ save a multiplication if possible
- d == denominator ifTrue:[
- ^ numerator < n
- ].
- ^ (numerator * d) < (denominator * n)
- ].
^ aNumber lessFromFraction:self
"Modified: 5.11.1996 / 10:30:52 / cg"
@@ -578,19 +551,7 @@
].
^ numerator = aNumber
].
- aNumber isFraction ifTrue:[
- denominator = aNumber denominator ifTrue:[
- ^ numerator = aNumber numerator
- ].
- ^ self sameFractionValueAs:aNumber
- ].
- (aNumber isInteger) ifTrue:[
- (denominator == 1) ifFalse:[
- ^ numerator = (aNumber * denominator)
- ].
- ^ numerator = aNumber
- ].
- ^ self retry:#= coercing:aNumber
+ ^ aNumber equalFromFraction:self
"Modified: / 7.7.1998 / 17:17:07 / cg"
!
@@ -600,24 +561,10 @@
than aNumber, false otherwise."
"optional - could use inherited method ..."
- |d n|
-
(aNumber isMemberOf:SmallInteger) ifTrue:[
^ numerator > (denominator * aNumber)
].
- aNumber isFraction ifTrue:[
- d := aNumber denominator.
- n := aNumber numerator.
-
- "/ save a multiplication if possible
- d == denominator ifTrue:[
- ^ numerator > n
- ].
- ^ (numerator * d) > (denominator * n)
- ].
- ^ self retry:#> coercing:aNumber
-
- "Modified: 5.11.1996 / 10:31:28 / cg"
+ ^ aNumber < self
!
hash
@@ -658,72 +605,249 @@
!Fraction methodsFor:'double dispatching'!
+differenceFromFixedPoint:aFixedPoint
+ |n d otherDenominator otherNumerator|
+
+ otherDenominator := aFixedPoint denominator.
+ otherNumerator := aFixedPoint numerator.
+
+ "save a multiplication if possible"
+ otherDenominator == denominator ifTrue:[
+ n := otherNumerator - numerator.
+ d := otherDenominator.
+ ] ifFalse:[
+ n := (otherNumerator * denominator) - (numerator * otherDenominator).
+ d := otherDenominator * denominator.
+ ].
+ ^ aFixedPoint class
+ numerator:n
+ denominator:d
+ scale:(aFixedPoint scale)
+
+ "
+ ((1/3) asFixedPoint:2) - (1/3)
+ ((1/3) asFixedPoint:2) - (2/3)
+ "
+!
+
differenceFromFloat:aFloat
"sent when a float does not know how to subtract the receiver, a fraction"
^ (aFloat * denominator - numerator) / denominator
!
+differenceFromFraction:aFraction
+ |n d otherDenominator otherNumerator|
+
+ otherDenominator := aFraction denominator.
+ otherNumerator := aFraction numerator.
+
+ "save a multiplication if possible"
+ otherDenominator == denominator ifTrue:[
+ n := otherNumerator - numerator.
+ d := otherDenominator.
+ ] ifFalse:[
+ n := (otherNumerator * denominator) - (numerator * otherDenominator).
+ d := otherDenominator * denominator.
+ ].
+ ^ aFraction class
+ numerator:n
+ denominator:d
+
+ "
+ ((1/3) asFixedPoint:2) - (1/3)
+ ((1/3) asFixedPoint:2) - (2/3)
+ "
+!
+
differenceFromInteger:anInteger
"sent when an integer does not know how to subtract the receiver, a fraction"
- ^ (self class
+ ^ self class
numerator:((anInteger * denominator) - numerator)
- denominator:denominator)
+ denominator:denominator
"Modified: 28.7.1997 / 19:08:53 / cg"
!
+equalFromFraction:aFraction
+ denominator = aFraction denominator ifFalse:[^ false].
+ ^ numerator = aFraction numerator
+!
+
+equalFromInteger:anInteger
+ "sent when an integer does not know how to compare to the receiver, a fraction"
+
+ "as I am always reduced, this test should not be required.
+ However, it is here for subclasses and to allow comparing unnormalized fractions,
+ which might be encountered internally"
+
+ denominator = 1 ifFalse:[^ false].
+ ^ numerator = anInteger
+!
+
+lessFromFraction:aFraction
+ "sent when a fraction does not know how to compare to the receiver"
+
+ |n d|
+
+ d := aFraction denominator.
+ n := aFraction numerator.
+
+ "/ save a multiplication if possible
+ d == denominator ifTrue:[
+ ^ n < numerator
+ ].
+ ^ (denominator * n) < (numerator * d)
+!
+
lessFromInteger:anInteger
"sent when an integer does not know how to compare to the receiver, a fraction"
^ (denominator * anInteger) < numerator
!
+productFromFixedPoint:aFixedPoint
+ ^ aFixedPoint class
+ numerator:(aFixedPoint numerator * numerator)
+ denominator:(aFixedPoint denominator * denominator)
+ scale:(aFixedPoint scale)
+
+ "
+ ((1/3) asFixedPoint:2) * 2
+ ((1/3) asFixedPoint:2) * (1/2)
+ ((1/3) asFixedPoint:2) * (3/2)
+ "
+!
+
productFromFloat:aFloat
"sent when a float does not know how to multiply the receiver, a fraction"
^ aFloat * numerator / denominator
!
+productFromFraction:aFraction
+ ^ aFraction class
+ numerator:(aFraction numerator * numerator)
+ denominator:(aFraction denominator * denominator)
+
+ "
+ ((1/3) asFixedPoint:2) * 2
+ ((1/3) asFixedPoint:2) * (1/2)
+ ((1/3) asFixedPoint:2) * (3/2)
+ "
+!
+
productFromInteger:anInteger
"sent when an integer does not know how to multiply the receiver, a fraction"
- ^ (self class
+ ^ self class
numerator:(anInteger * numerator)
- denominator:denominator)
+ denominator:denominator
"Modified: 28.7.1997 / 19:06:22 / cg"
!
+quotientFromFixedPoint:aFixedPoint
+ ^ aFixedPoint class
+ numerator:(aFixedPoint numerator * denominator)
+ denominator:(aFixedPoint denominator * numerator)
+ scale:(aFixedPoint scale)
+
+ "
+ ((1/3) asFixedPoint:2) / 2
+ ((1/3) asFixedPoint:2) / (1/2)
+ "
+!
+
quotientFromFloat:aFloat
"sent when a float does not know how to divide by the receiver, a fraction"
^ (aFloat * denominator) / numerator
!
+quotientFromFraction:aFraction
+ ^ aFraction class
+ numerator:(aFraction numerator * denominator)
+ denominator:(aFraction denominator * numerator)
+
+ "
+ (1/3) / (1/2)
+ (1/3) / (3/2)
+ "
+!
+
quotientFromInteger:anInteger
"sent when an integer does not know how to divide by the receiver, a fraction"
- ^ (self class
+ ^ self class
numerator:(anInteger * denominator)
- denominator:numerator)
+ denominator:numerator
"Modified: 28.7.1997 / 19:08:46 / cg"
!
+sumFromFixedPoint:aFixedPoint
+ |n d otherDenominator otherNumerator|
+
+ otherDenominator := aFixedPoint denominator.
+ otherNumerator := aFixedPoint numerator.
+
+ "save a multiplication if possible"
+ otherDenominator == denominator ifTrue:[
+ n := otherNumerator + numerator.
+ d := otherDenominator.
+ ] ifFalse:[
+ n := (otherNumerator * denominator) + (numerator * otherDenominator).
+ d := otherDenominator * denominator.
+ ].
+ ^ aFixedPoint class
+ numerator:n
+ denominator:d
+ scale:(aFixedPoint scale)
+
+ "
+ ((1/3) asFixedPoint:2) + (1/3)
+ ((1/3) asFixedPoint:2) + (2/3)
+ "
+!
+
sumFromFloat:aFloat
"sent when a float does not know how to add the receiver, a fraction"
^ (aFloat * denominator + numerator) / denominator
!
+sumFromFraction:aFraction
+ |n d otherDenominator otherNumerator|
+
+ otherDenominator := aFraction denominator.
+ otherNumerator := aFraction numerator.
+
+ "save a multiplication if possible"
+ otherDenominator == denominator ifTrue:[
+ n := otherNumerator + numerator.
+ d := otherDenominator.
+ ] ifFalse:[
+ n := (otherNumerator * denominator) + (numerator * otherDenominator).
+ d := otherDenominator * denominator.
+ ].
+ ^ aFraction class
+ numerator:n
+ denominator:d
+
+ "
+ (1/3) + (1/3)
+ (1/3) + (2/3)
+ "
+!
+
sumFromInteger:anInteger
"sent when an integer does not know how to add the receiver, a fraction"
- ^ (self class
+ ^ self class
numerator:(numerator + (anInteger * denominator))
- denominator:denominator)
+ denominator:denominator
"Modified: 28.7.1997 / 19:08:40 / cg"
! !
@@ -836,17 +960,24 @@
!Fraction methodsFor:'truncation & rounding'!
fractionPart
- "extract the after-decimal fraction part."
+ "extract the after-decimal fraction part,
+ such that (self truncated + self fractionPart) = self"
numerator abs < denominator abs ifTrue:[
^ self
].
- ^ super fractionPart
+ ^ (numerator rem: denominator) / denominator
+ "/ ^ super fractionPart
"
- (3/2) fractionPart
+ (3/2) fractionPart + (3/2) truncated
+ (-3/2) fractionPart + (-3/2) truncated
+
+ (3/2) fractionPart
(-3/2) fractionPart
- (2/3) fractionPart
+ (3/2) asFloat fractionPart
+ (-3/2) asFloat fractionPart
+ (2/3) fractionPart
((3/2)*(15/4)) fractionPart
((2/3)*(4/15)) fractionPart
"
@@ -917,7 +1048,7 @@
!Fraction class methodsFor:'documentation'!
version
- ^ '$Header: /cvs/stx/stx/libbasic/Fraction.st,v 1.62 2003-03-31 09:12:58 cg Exp $'
+ ^ '$Header: /cvs/stx/stx/libbasic/Fraction.st,v 1.63 2003-06-16 09:14:59 cg Exp $'
! !
Fraction initialize!