diff -r 8574ffbe45fb -r 658ff91cef9e LimitedPrecisionReal.st --- 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 $' ! !