Nicolas Cellier uploaded a new version of Kernel to project The Trunk:
http://source.squeak.org/trunk/Kernel-nice.1168.mcz ==================== Summary ==================== Name: Kernel-nice.1168 Author: nice Time: 26 April 2018, 11:40:17.923908 am UUID: fa008d75-249a-b243-8b1e-068eeb72a45d Ancestors: Kernel-nice.1167 Change asApproximateFraction to allow prescribing a relative decimal precision Example: (FloatArray with: 1/3) first asApproximateFractionRelativeDecimalPlaces: 6. 0.6667 asApproximateFractionRelativeDecimalPlaces: 3. 0.6667 asApproximateFractionRelativeDecimalPlaces: 5. =============== Diff against Kernel-nice.1167 =============== Item was changed: ----- Method: Float>>asApproximateFraction (in category 'converting') ----- asApproximateFraction "Answer a Fraction approximating the receiver. This conversion uses the continued fraction method to approximate a floating point number." + ^ self asApproximateFractionRelativeDecimalPlaces: 10! - ^ self asApproximateFractionAtOrder: 0! 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 + precision: self ulp / 2! - | 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:precision: (in category 'converting') ----- + asApproximateFractionAtOrder: maxOrder precision: limit + "Answer a Rational number--Integer or Fraction--representing the receiver. + This conversion uses the continued fraction method to approximate a floating point number. + The iteration stops when precision has reached the prescribed limit, + or when the maximum number of iterations has been reached. + If maxOrder is zero, then the number of iterations is not limited." + + | num1 denom1 num2 denom2 int frac newD order | + newD := self asFraction. "use exact arithmetic to avoid both overflow and accumulation of rounding errors" + num1 := denom2 := 1. "Initialize alternating numerators" + num2 := denom1 := 0. "and denominators" + order := maxOrder = 0 ifTrue: [-1] ifFalse: [maxOrder]. + [int := newD integerPart. "get the integer part of this" + frac := newD fractionPart. "and save the fractional part for next time" + num1 := num2 + ((num2 := num1) * int). "Update numerators" + denom1 := denom2 + ((denom2 := denom1) * int). "and denominators" + frac = 0 + or: [order = 0 + or: [((Fraction numerator: num1 denominator: denom1) - self) abs <= limit]]] + whileFalse: + [newD := frac reciprocal "Take reciprocal of the fractional part". + order := order - 1]. + ^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>>asApproximateFractionRelativeDecimalPlaces: (in category 'converting') ----- + asApproximateFractionRelativeDecimalPlaces: decimalPlaces + "Answer a Fraction approximating the receiver. This conversion uses the + continued fraction method to approximate a floating point number. + Stop the recursion when precision has reached prescribed number of relative decimalPlaces." + + ^ self + asApproximateFractionAtOrder: 0 + precision: (1.0 timesTwoPower: self exponent - (decimalPlaces * Ln10 / Ln2) rounded)! |
Free forum by Nabble | Edit this page |