[squeak-dev] The Trunk: Kernel-nice.1168.mcz

commits at source.squeak.org commits at source.squeak.org
Thu Apr 26 09:40:45 UTC 2018


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



More information about the Squeak-dev mailing list