[squeak-dev] The Inbox: Kernel-nice.650.mcz
commits at source.squeak.org
commits at source.squeak.org
Thu Nov 3 20:17:45 UTC 2011
A new version of Kernel was added to project The Inbox:
http://source.squeak.org/inbox/Kernel-nice.650.mcz
==================== Summary ====================
Name: Kernel-nice.650
Author: nice
Time: 3 November 2011, 9:17:16.187 pm
UUID: e8775ee0-9502-469d-81b5-e7c39f9947a0
Ancestors: Kernel-eem.648
Provide a Float>>asMinimalDecimalFraction
which answers the shortest decimal Fraction that will equal the receiver when converted back asFloat.
A decimal Fraction has only powers of 2 and 5 as denominator, so it can be printed in decimal with a finite number of digits.
For example,
0.1 asMinimalDecimalFraction = (1/10).
Note that this does not reflect what is exactly stored in memory. For this we should use asTrueFraction.
(0.1 asTrueFraction storeStringBase: 2) = '(2r1100110011001100110011001100110011001100110011001101/2r10000000000000000000000000000000000000000000000000000000)'.
Note that asApproximateFraction might give shorter Fractions, but
- asApproximateFraction does not exclusively has power of 2 and 5 in denominator
- asApproximateFraction does not necessarily convert back exactly to the receiver
An example is:
0.11111111111 asApproximateFraction = (1/9).
0.11111111111 asMinimalDecimalFraction = (11111111111/100000000000).
But:
(1/9) asFloat storeString -> '0.1111111111111111' "has five more digits..."
A good application for such message would be:
0.111111111 asMinimalDecimalFraction asScaledDecimal = 0.111111111s9.
versus:
0.111111111 asTrueFraction asScaledDecimal = 0.11111111099999999851650755999799002893269062042236328125s56.
The later reflects the exact representation of the Float though.
=============== Diff against Kernel-eem.648 ===============
Item was added:
+ ----- Method: Float>>asMinimalDecimalFraction (in category 'printing') -----
+ asMinimalDecimalFraction
+ "Answer the shortest decimal Fraction that will equal self when converted back asFloat.
+ A decimal Fraction has only powers of 2 and 5 as denominator.
+ For example, 0.1 asMinimalDecimalFraction = (1/10)."
+
+ | significand exp baseExpEstimate r s mPlus mMinus scale roundingIncludesLimits d tc1 tc2 fixedFormat decPointCount slowbit shead denominator numerator |
+ self isFinite ifFalse: [self error: 'Only finite Float can be converted to a Fraction'].
+ self = 0.0 ifTrue: [^0].
+ self < 0.0 ifTrue: [^self negated asMinimalDecimalFraction negated].
+ numerator := 0.
+ denominator := 0.
+ significand := self significandAsInteger.
+ roundingIncludesLimits := significand even.
+ exp := (self exponent - 52) max: MinValLogBase2.
+ baseExpEstimate := (self exponent * 10 asFloat reciprocalLogBase2 - 1.0e-10) ceiling.
+ exp >= 0
+ ifTrue:
+ [significand ~= 16r10000000000000
+ ifTrue:
+ [r := significand bitShift: 1 + exp.
+ s := 2.
+ mPlus := mMinus := 1 bitShift: exp]
+ ifFalse:
+ [r := significand bitShift: 2 + exp.
+ s := 4.
+ mPlus := 2 * (mMinus := 1 bitShift: exp)]]
+ ifFalse:
+ [(exp = MinValLogBase2 or: [significand ~= 16r10000000000000])
+ ifTrue:
+ [r := significand bitShift: 1.
+ s := 1 bitShift: 1 - exp.
+ mPlus := mMinus := 1]
+ ifFalse:
+ [r := significand bitShift: 2.
+ s := 1 bitShift: 2 - exp.
+ mPlus := 2.
+ mMinus := 1]].
+ baseExpEstimate >= 0
+ ifTrue: [s := s * (10 raisedToInteger: baseExpEstimate)]
+ ifFalse:
+ [scale := 10 raisedToInteger: baseExpEstimate negated.
+ r := r * scale.
+ mPlus := mPlus * scale.
+ mMinus := mMinus * scale].
+ ((r + mPlus < s) not and: [roundingIncludesLimits or: [r + mPlus > s]])
+ ifTrue: [baseExpEstimate := baseExpEstimate + 1]
+ ifFalse:
+ [r := r * 10.
+ mPlus := mPlus * 10.
+ mMinus := mMinus * 10].
+ (fixedFormat := baseExpEstimate between: -3 and: 6)
+ ifTrue:
+ [decPointCount := baseExpEstimate.
+ baseExpEstimate <= 0
+ ifTrue: [denominator := 10 raisedTo: baseExpEstimate negated]]
+ ifFalse:
+ [decPointCount := 1].
+ slowbit := 1 - s lowBit .
+ shead := s bitShift: slowbit.
+ [d := (r bitShift: slowbit) // shead.
+ r := r - (d * s).
+ (tc1 := (r > mMinus) not and: [roundingIncludesLimits or: [r < mMinus]]) |
+ (tc2 := (r + mPlus < s) not and: [roundingIncludesLimits or: [r + mPlus > s]])] whileFalse:
+ [numerator := 10 * numerator + d.
+ denominator := 10 * denominator.
+ r := r * 10.
+ mPlus := mPlus * 10.
+ mMinus := mMinus * 10.
+ decPointCount := decPointCount - 1.
+ decPointCount = 0 ifTrue: [denominator := 1]].
+ tc2 ifTrue:
+ [(tc1 not or: [r * 2 >= s]) ifTrue: [d := d + 1]].
+ numerator := 10 * numerator + d.
+ denominator := 10 * denominator.
+ decPointCount > 0
+ ifTrue:
+ [numerator := (10 raisedTo: decPointCount - 1) * numerator].
+ fixedFormat ifFalse:
+ [(baseExpEstimate - 1) > 0
+ ifTrue: [numerator := (10 raisedTo: baseExpEstimate - 1) * numerator]
+ ifFalse: [denominator := (10 raisedTo: 1 - baseExpEstimate) * (denominator max: 1)]].
+ denominator < 2 ifTrue: [^numerator].
+ ^numerator / denominator!
More information about the Squeak-dev
mailing list
|