The Inbox: Kernel-dtl.1165.mcz

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

The Inbox: Kernel-dtl.1165.mcz

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