David T. Lewis uploaded a new version of Kernel to project The Inbox:
http://source.squeak.org/inbox/Kernel-dtl.1165.mcz ==================== Summary ==================== Name: Kernel-dtl.1165 Author: dtl Time: 23 April 2018, 10:43:08.381368 pm UUID: a7581950-44f0-4b4c-ac85-5f34672bc4a4 Ancestors: Kernel-eem.1164 Let Float>>asApproximateFraction give unsurprising results when the value of the float was derived from a single precision float in a Squeak FloatArray. Float>>asApproximateFraction is implemented for Squeak Float, which assumes double precision float. FloatArray is single precision, which can lead to confusion when converted back to double Float in Squeak. Implement asApproximateFractionFloatPrecision: to allow lesser float precision to be specified. =============== Diff against Kernel-eem.1164 =============== Item was changed: ----- Method: Float>>asApproximateFractionAtOrder: (in category 'converting') ----- asApproximateFractionAtOrder: maxOrder "Answer a Fraction approximating the receiver. This conversion uses the continued fraction method to approximate a floating point number. If maxOrder is zero, use maximum order" + ^self asApproximateFractionAtOrder: maxOrder floatPrecision: 10. + ! - | num1 denom1 num2 denom2 int frac newD temp order | - num1 := self asInteger. "The first of two alternating numerators" - 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. "The fractional part of self" - order := maxOrder = 0 ifTrue: [-1] ifFalse: [maxOrder]. - [frac = 0 or: [order = 0] ] - whileFalse: - ["repeat while the fractional part is not zero and max order is not reached" - order := order - 1. - newD := 1.0 / frac. "Take reciprocal of the fractional part" - int := newD asInteger. "get the integer part of this" - frac := newD fractionPart. "and save the fractional part for next time" - temp := num2. "Get old numerator and save it" - num2 := num1. "Set second numerator to first" - num1 := num1 * int + temp. "Update first numerator" - temp := denom2. "Get old denominator and save it" - denom2 := denom1. "Set second denominator to first" - denom1 := int * denom1 + temp. "Update first denominator" - 10000000000.0 < 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]]. - "If fractional part is zero, return the first ratio" - denom1 = 1 - ifTrue: ["Am I really an Integer?" - ^ num1 "Yes, return Integer result"] - ifFalse: ["Otherwise return Fraction result" - ^ Fraction numerator: num1 denominator: denom1]! Item was added: + ----- Method: Float>>asApproximateFractionAtOrder:floatPrecision: (in category 'converting') ----- + asApproximateFractionAtOrder: maxOrder floatPrecision: decimalPlaces + "Answer a Fraction approximating the receiver. This conversion uses the + continued fraction method to approximate a floating point number. If maxOrder + is zero, use maximum order. Assume that I am a float with decimalPlaces of + meaningful accuracy, regardless of the precision of my internal representation." + + | num1 denom1 num2 denom2 int frac newD temp order floatPrecision | + num1 := self asInteger. "The first of two alternating numerators" + 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. "The fractional part of self" + order := maxOrder = 0 ifTrue: [-1] ifFalse: [maxOrder]. + floatPrecision := (10 raisedTo: decimalPlaces) asFloat. + [frac = 0 or: [order = 0] ] + whileFalse: + ["repeat while the fractional part is not zero and max order is not reached" + order := order - 1. + newD := 1.0 / frac. "Take reciprocal of the fractional part" + int := newD asInteger. "get the integer part of this" + frac := newD fractionPart. "and save the fractional part for next time" + temp := num2. "Get old numerator and save it" + num2 := num1. "Set second numerator to first" + num1 := num1 * int + temp. "Update first numerator" + temp := denom2. "Get old denominator and save it" + denom2 := denom1. "Set second denominator to first" + denom1 := int * denom1 + temp. "Update first denominator" + floatPrecision < 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]]. + "If fractional part is zero, return the first ratio" + denom1 = 1 + ifTrue: ["Am I really an Integer?" + ^ num1 "Yes, return Integer result"] + ifFalse: ["Otherwise return Fraction result" + ^ Fraction numerator: num1 denominator: denom1]! Item was added: + ----- Method: Float>>asApproximateFractionFloatPrecision: (in category 'converting') ----- + asApproximateFractionFloatPrecision: decimalPlaces + "Answer a Fraction approximating the receiver. This conversion uses the + continued fraction method to approximate a floating point number. If maxOrder + is zero, use maximum order. Assume that I am a float with with decimalPlaces + places of precision. For 64 bit double precision floating point, a value of 10 is + appropriate. For 32 bit single precision floating point, a decimalPlaces of 5 will + give good results." + + ^self asApproximateFractionAtOrder: 0 floatPrecision: decimalPlaces! |
Free forum by Nabble | Edit this page |