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!
squeak-dev@lists.squeakfoundation.org