[squeak-dev] The Inbox: Kernel-dtl.1165.mcz

commits at source.squeak.org commits at source.squeak.org
Tue Apr 24 02:43:21 UTC 2018


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!



More information about the Squeak-dev mailing list