--- a/LimitedPrecisionReal.st Mon Jun 25 09:03:35 2001 +0200
+++ b/LimitedPrecisionReal.st Tue Jun 26 16:03:35 2001 +0200
@@ -184,46 +184,59 @@
!
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"
+ "Answer a rational number (Integer or Fraction) representing the receiver.
+ This conversion uses the continued fraction method to approximate
+ a floating point number."
+
+ |num1 denom1 num2 denom2 int frac newD temp limit|
- |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.
+ limit := (self class unity * 10) raisedTo:self defaultNumberOfDigits.
+ num1 := self truncated.
+ denom1 := 1. "The first of two alternating denominators"
+ num2 := 1. "The second numerator"
+ denom2 := 0. "The second denominator--will update"
+ int := num1. "The integer part of self"
+ frac := self fractionPart.
+ [frac = 0] whileFalse:[
+ newD := 1.0 / frac.
+ int := newD truncated.
+ frac := newD fractionPart. "save the fractional part for next time"
+ temp := num2. "old numerator and save it"
+ num2 := num1.
+ num1 := num1 * int + temp. "Update first numerator"
+ temp := denom2. "old denominator and save it"
+ denom2 := denom1.
+ denom1 := int * denom1 + temp. "Update first denominator"
+ limit < denom1 ifTrue:[
+ "Is ratio past float precision? If so, pick which of the two ratios to use"
+ num2 = 0.0 ifTrue:[
+ "Is second denominator 0?"
+ ^ Fraction numerator:num1 denominator:denom1
+ ].
+ ^ Fraction numerator:num2 denominator:denom2
+ ]
].
- "/ 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
+ "If fractional part is zero, return the first ratio"
+ denom1 = 1 ifTrue:[
+ "Am i really an Integer?"
+ ^ num1 "Yes, return Integer result"
].
-
- 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
+ "Otherwise return Fraction result"
+ ^ Fraction numerator:num1 denominator:denom1
"
- 0.3 asFraction
+ 1.1 asFraction
+ 1.2 asFraction
+ 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
+ (1/8) asFloat asFraction
+ (1/13) asFloat asFraction
+ 3.14159 asFraction
+ 3.14159 asFraction asFloat
+ 1.3 asFraction
+ 1.0 asFraction
"
"Modified: / 25.10.1997 / 16:41:19 / cg"
@@ -267,6 +280,27 @@
"Modified: 12.2.1997 / 16:45:07 / cg"
!
+asRational
+ "Answer a Rational number--Integer or Fraction--representing the receiver.
+ Same as asFraction fro st-80 compatibility."
+
+ ^ self asFraction
+
+ "
+ 1.1 asRational
+ 1.2 asRational
+ 0.3 asRational
+ 0.5 asRational
+ (1/5) asFloat asRational
+ (1/8) asFloat asRational
+ (1/13) asFloat asRational
+ 3.14159 asRational
+ 3.14159 asRational asFloat
+ 1.3 asRational
+ 1.0 asRational
+ "
+!
+
coerce:aNumber
"return aNumber converted into receivers type"
@@ -442,13 +476,16 @@
!LimitedPrecisionReal methodsFor:'queries'!
+defaultNumberOfDigits
+ self subclassResponsibility
+!
+
size
"redefined since reals are kludgy (ByteArry)"
^ 0
! !
-
!LimitedPrecisionReal methodsFor:'testing'!
isFinite
@@ -521,5 +558,5 @@
!LimitedPrecisionReal class methodsFor:'documentation'!
version
- ^ '$Header: /cvs/stx/stx/libbasic/LimitedPrecisionReal.st,v 1.37 2001-05-17 22:08:24 stefan Exp $'
+ ^ '$Header: /cvs/stx/stx/libbasic/LimitedPrecisionReal.st,v 1.38 2001-06-26 14:03:35 cg Exp $'
! !