The Trunk: Kernel-nice.1168.mcz

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

The Trunk: Kernel-nice.1168.mcz

commits-2
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)!