A new version of Kernel was added to project The Inbox:
http://source.squeak.org/inbox/Kernel-nice.690.mcz ==================== Summary ==================== Name: Kernel-nice.690 Author: nice Time: 20 May 2012, 10:05:07.444 am UUID: 2c2aba8b-d8bd-4ec3-8b88-a873de9c68c4 Ancestors: Kernel-nice.689 1) Correct the very new #printOn:maxDecimalPlaces: which often rounds inexactly for large Float or large number of digits. Rationale: the printed representation shall be rounded exactly 2) Don't print arbitrary digits beyond Float precision, just print zeros (0.1 printShowingDecimalPlaces: 20) now prints '0.10000000000000000000' instead of '0.10000000000000000555', Rationale: those digits, while reflecting internal representation exactly, are totally insignificant and could be replaced with any other digits, while still representing the same Float. 3) Print the negative sign, even if the number vanishes to zero at prescribed decimal places (-0.001 printShowingDecimalPlaces: 2) now prints '-0.00' instead of '0.00', Rationale: this behaves like classical lib printf, and is in the spirit of Float negativeZero printString: when the precision vanishes, the Float keeps its sign. Note: I find the scheme feature which prints # for insignificant digits is very nice, but we should find a re-interpretable format... Implementation details: Of course, algorithms are taken from: Robert G. Burger and R. Kent Dybvig Printing Floating Point Numbers Quickly and Accurately ACM SIGPLAN 1996 Conference on Programming Language Design and Implementation June 1996. Note that there is lot of duplicated code between free format and fixed format Float printing. And we should also fix the case of fixed number of digits #absPrintOn:base:digitCount: ... =============== Diff against Kernel-nice.689 =============== Item was added: + ----- Method: Float>>absPrintExactlyOn:base:decimalPlaces:showTrailingFractionalZeros: (in category 'printing') ----- + absPrintExactlyOn: aStream base: base decimalPlaces: placesDesired showTrailingFractionalZeros: showtrailingZeros + "Print my value on a stream in the given base with fixed number of digits after floating point. + When placesDesired are beyond Float precision, zeroes are appended. + When showtrailingZeros is false, the trailing zeroes after decimal point will be omitted. + If all fractional digits are zeros, the decimal point is omitted too. + Assumes that my value is strictly positive; negative numbers, zero, and NaNs have already been handled elsewhere. + Based upon the algorithm outlined in: + Robert G. Burger and R. Kent Dybvig + Printing Floating Point Numbers Quickly and Accurately + ACM SIGPLAN 1996 Conference on Programming Language Design and Implementation + June 1996.." + + | significand exp baseExpEstimate r s mPlus mMinus scale roundingLowIncludesLimits roundingHighIncludesLimits d tc1 tc2 decPointCount slowbit shead delta | + self isInfinite ifTrue: [aStream nextPutAll: 'Infinity'. ^ self]. + significand := self significandAsInteger. + exp := (self exponent - 52) max: MinValLogBase2. + 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]]. + delta := s / 2 / (base raisedTo: placesDesired). + roundingLowIncludesLimits := (mMinus < delta and: [mMinus := delta. true]) or: [significand even]. + roundingHighIncludesLimits := (mPlus < delta and: [mPlus := delta. true]) or: [significand even]. + baseExpEstimate := (self exponent * base asFloat reciprocalLogBase2 - 1.0e-10) ceiling. + baseExpEstimate >= 0 + ifTrue: [s := s * (base raisedToInteger: baseExpEstimate)] + ifFalse: + [scale := base raisedToInteger: baseExpEstimate negated. + r := r * scale. + mPlus := mPlus * scale. + mMinus := mMinus * scale]. + ((r + mPlus >= s) and: [roundingHighIncludesLimits or: [r + mPlus > s]]) + ifTrue: [baseExpEstimate := baseExpEstimate + 1] + ifFalse: + [r := r * base. + mPlus := mPlus * base. + mMinus := mMinus * base]. + decPointCount := baseExpEstimate. + baseExpEstimate <= 0 + ifTrue: + [placesDesired + baseExpEstimate <= 0 + ifTrue: + [aStream nextPut: $0. + (showtrailingZeros and: [placesDesired > 0]) ifTrue: [aStream nextPut: $.; nextPutAll: (String new: placesDesired withAll: $0)]. + ^self]. + aStream nextPutAll: '0.'; nextPutAll: (String new: 0 - baseExpEstimate withAll: $0)]. + slowbit := 1 - s lowBit . + shead := s bitShift: slowbit. + [d := (r bitShift: slowbit) // shead. + r := r - (d * s). + (tc1 := (r <= mMinus) and: [roundingLowIncludesLimits or: [r < mMinus]]) | + (tc2 := (r + mPlus >= s) and: [roundingHighIncludesLimits or: [r + mPlus > s]])] whileFalse: + [aStream nextPut: (Character digitValue: d). + r := r * base. + mPlus := mPlus * base. + mMinus := mMinus * base. + (decPointCount := decPointCount - 1) = 0 ifTrue: [aStream nextPut: $.]]. + tc2 ifTrue: + [(tc1 not or: [r * 2 >= s]) ifTrue: [d := d + 1]]. + aStream nextPut: (Character digitValue: d). + decPointCount > 0 + ifTrue: + [decPointCount - 1 to: 1 by: -1 do: [:i | aStream nextPut: $0]. + (showtrailingZeros and: [placesDesired > 0]) ifTrue: [aStream nextPut: $.; nextPutAll: (String new: placesDesired withAll: $0)]] + ifFalse: + [(showtrailingZeros and: [placesDesired + decPointCount > 1]) ifTrue: [aStream nextPutAll: (String new: placesDesired + decPointCount - 1 withAll: $0)]].! Item was changed: + ----- Method: Float>>absPrintOn:base:digitCount: (in category 'printing') ----- - ----- Method: Float>>absPrintOn:base:digitCount: (in category 'private') ----- absPrintOn: aStream base: base digitCount: digitCount "Print me in the given base, using digitCount significant figures." | fuzz x exp q fBase scale logScale xi | self isInfinite ifTrue: [^ aStream nextPutAll: 'Inf']. fBase := base asFloat. "x is myself normalized to [1.0, fBase), exp is my exponent" exp := self < 1.0 ifTrue: [self reciprocalFloorLog: fBase] ifFalse: [self floorLog: fBase]. scale := 1.0. logScale := 0. [(x := fBase raisedTo: (exp + logScale)) = 0] whileTrue: [scale := scale * fBase. logScale := logScale + 1]. x := self * scale / x. fuzz := fBase raisedTo: 1 - digitCount. "round the last digit to be printed" x := 0.5 * fuzz + x. x >= fBase ifTrue: ["check if rounding has unnormalized x" x := x / fBase. exp := exp + 1]. (exp < 6 and: [exp > -4]) ifTrue: ["decimal notation" q := 0. exp < 0 ifTrue: [1 to: 1 - exp do: [:i | aStream nextPut: ('0.0000' at: i)]]] ifFalse: ["scientific notation" q := exp. exp := 0]. [x >= fuzz] whileTrue: ["use fuzz to track significance" xi := x asInteger. aStream nextPut: (Character digitValue: xi). x := x - xi asFloat * fBase. fuzz := fuzz * fBase. exp := exp - 1. exp = -1 ifTrue: [aStream nextPut: $.]]. [exp >= -1] whileTrue: [aStream nextPut: $0. exp := exp - 1. exp = -1 ifTrue: [aStream nextPut: $.]]. q ~= 0 ifTrue: [aStream nextPut: $e. q printOn: aStream]! Item was added: + ----- Method: Float>>printOn:maxDecimalPlaces: (in category 'printing') ----- + printOn: aStream maxDecimalPlaces: placesDesired + "Refine super implementation in order to avoid any rounding error caused by rounded or roundTo:" + + self isFinite ifFalse: [^self printOn: aStream]. + self > 0.0 + ifTrue: [self absPrintExactlyOn: aStream base: 10 decimalPlaces: placesDesired showTrailingFractionalZeros: false] + ifFalse: + [self sign = -1 + ifTrue: [aStream nextPutAll: '-']. + self = 0.0 + ifTrue: [aStream nextPutAll: '0.0'] + ifFalse: [self absPrintExactlyOn: aStream base: 10 decimalPlaces: placesDesired showTrailingFractionalZeros: false]]! Item was added: + ----- Method: Float>>printOn:showingDecimalPlaces: (in category 'printing') ----- + printOn: aStream showingDecimalPlaces: placesDesired + "Refine super implementation in order to avoid any rounding error caused by rounded or roundTo:" + + self isFinite ifFalse: [^self printOn: aStream]. + self > 0.0 + ifTrue: [self absPrintExactlyOn: aStream base: 10 decimalPlaces: placesDesired showTrailingFractionalZeros: true] + ifFalse: + [self sign = -1 + ifTrue: [aStream nextPutAll: '-']. + self = 0.0 + ifTrue: [aStream nextPutAll: '0.0'] + ifFalse: [self absPrintExactlyOn: aStream base: 10 decimalPlaces: placesDesired showTrailingFractionalZeros: true]]! Item was removed: - ----- Method: Float>>printShowingDecimalPlaces: (in category 'printing') ----- - printShowingDecimalPlaces: placesDesired - "This implementation avoids any rounding error caused by rounded or roundTo:" - - self isFinite ifFalse: [^self printString]. - ^self asTrueFraction printShowingDecimalPlaces: placesDesired! |
Looks good to me - but I doubt you will get any testing unless you actually commit to trunk :)
- Bert - On 20.05.2012, at 08:05, [hidden email] wrote: > A new version of Kernel was added to project The Inbox: > http://source.squeak.org/inbox/Kernel-nice.690.mcz > > ==================== Summary ==================== > > Name: Kernel-nice.690 > Author: nice > Time: 20 May 2012, 10:05:07.444 am > UUID: 2c2aba8b-d8bd-4ec3-8b88-a873de9c68c4 > Ancestors: Kernel-nice.689 > > 1) Correct the very new #printOn:maxDecimalPlaces: which often rounds inexactly for large Float or large number of digits. > Rationale: the printed representation shall be rounded exactly > > 2) Don't print arbitrary digits beyond Float precision, just print zeros > (0.1 printShowingDecimalPlaces: 20) now prints '0.10000000000000000000' instead of '0.10000000000000000555', > Rationale: those digits, while reflecting internal representation exactly, are totally insignificant and could be replaced with any other digits, while still representing the same Float. > > 3) Print the negative sign, even if the number vanishes to zero at prescribed decimal places > (-0.001 printShowingDecimalPlaces: 2) now prints '-0.00' instead of '0.00', > Rationale: this behaves like classical lib printf, and is in the spirit of Float negativeZero printString: when the precision vanishes, the Float keeps its sign. > > Note: I find the scheme feature which prints # for insignificant digits is very nice, but we should find a re-interpretable format... > > Implementation details: > > Of course, algorithms are taken from: > Robert G. Burger and R. Kent Dybvig > Printing Floating Point Numbers Quickly and Accurately > ACM SIGPLAN 1996 Conference on Programming Language Design and Implementation > June 1996. > > Note that there is lot of duplicated code between free format and fixed format Float printing. > And we should also fix the case of fixed number of digits #absPrintOn:base:digitCount: ... > > =============== Diff against Kernel-nice.689 =============== > > Item was added: > + ----- Method: Float>>absPrintExactlyOn:base:decimalPlaces:showTrailingFractionalZeros: (in category 'printing') ----- > + absPrintExactlyOn: aStream base: base decimalPlaces: placesDesired showTrailingFractionalZeros: showtrailingZeros > + "Print my value on a stream in the given base with fixed number of digits after floating point. > + When placesDesired are beyond Float precision, zeroes are appended. > + When showtrailingZeros is false, the trailing zeroes after decimal point will be omitted. > + If all fractional digits are zeros, the decimal point is omitted too. > + Assumes that my value is strictly positive; negative numbers, zero, and NaNs have already been handled elsewhere. > + Based upon the algorithm outlined in: > + Robert G. Burger and R. Kent Dybvig > + Printing Floating Point Numbers Quickly and Accurately > + ACM SIGPLAN 1996 Conference on Programming Language Design and Implementation > + June 1996.." > + > + | significand exp baseExpEstimate r s mPlus mMinus scale roundingLowIncludesLimits roundingHighIncludesLimits d tc1 tc2 decPointCount slowbit shead delta | > + self isInfinite ifTrue: [aStream nextPutAll: 'Infinity'. ^ self]. > + significand := self significandAsInteger. > + exp := (self exponent - 52) max: MinValLogBase2. > + 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]]. > + delta := s / 2 / (base raisedTo: placesDesired). > + roundingLowIncludesLimits := (mMinus < delta and: [mMinus := delta. true]) or: [significand even]. > + roundingHighIncludesLimits := (mPlus < delta and: [mPlus := delta. true]) or: [significand even]. > + baseExpEstimate := (self exponent * base asFloat reciprocalLogBase2 - 1.0e-10) ceiling. > + baseExpEstimate >= 0 > + ifTrue: [s := s * (base raisedToInteger: baseExpEstimate)] > + ifFalse: > + [scale := base raisedToInteger: baseExpEstimate negated. > + r := r * scale. > + mPlus := mPlus * scale. > + mMinus := mMinus * scale]. > + ((r + mPlus >= s) and: [roundingHighIncludesLimits or: [r + mPlus > s]]) > + ifTrue: [baseExpEstimate := baseExpEstimate + 1] > + ifFalse: > + [r := r * base. > + mPlus := mPlus * base. > + mMinus := mMinus * base]. > + decPointCount := baseExpEstimate. > + baseExpEstimate <= 0 > + ifTrue: > + [placesDesired + baseExpEstimate <= 0 > + ifTrue: > + [aStream nextPut: $0. > + (showtrailingZeros and: [placesDesired > 0]) ifTrue: [aStream nextPut: $.; nextPutAll: (String new: placesDesired withAll: $0)]. > + ^self]. > + aStream nextPutAll: '0.'; nextPutAll: (String new: 0 - baseExpEstimate withAll: $0)]. > + slowbit := 1 - s lowBit . > + shead := s bitShift: slowbit. > + [d := (r bitShift: slowbit) // shead. > + r := r - (d * s). > + (tc1 := (r <= mMinus) and: [roundingLowIncludesLimits or: [r < mMinus]]) | > + (tc2 := (r + mPlus >= s) and: [roundingHighIncludesLimits or: [r + mPlus > s]])] whileFalse: > + [aStream nextPut: (Character digitValue: d). > + r := r * base. > + mPlus := mPlus * base. > + mMinus := mMinus * base. > + (decPointCount := decPointCount - 1) = 0 ifTrue: [aStream nextPut: $.]]. > + tc2 ifTrue: > + [(tc1 not or: [r * 2 >= s]) ifTrue: [d := d + 1]]. > + aStream nextPut: (Character digitValue: d). > + decPointCount > 0 > + ifTrue: > + [decPointCount - 1 to: 1 by: -1 do: [:i | aStream nextPut: $0]. > + (showtrailingZeros and: [placesDesired > 0]) ifTrue: [aStream nextPut: $.; nextPutAll: (String new: placesDesired withAll: $0)]] > + ifFalse: > + [(showtrailingZeros and: [placesDesired + decPointCount > 1]) ifTrue: [aStream nextPutAll: (String new: placesDesired + decPointCount - 1 withAll: $0)]].! > > Item was changed: > + ----- Method: Float>>absPrintOn:base:digitCount: (in category 'printing') ----- > - ----- Method: Float>>absPrintOn:base:digitCount: (in category 'private') ----- > absPrintOn: aStream base: base digitCount: digitCount > "Print me in the given base, using digitCount significant figures." > > | fuzz x exp q fBase scale logScale xi | > self isInfinite ifTrue: [^ aStream nextPutAll: 'Inf']. > fBase := base asFloat. > "x is myself normalized to [1.0, fBase), exp is my exponent" > exp := > self < 1.0 > ifTrue: [self reciprocalFloorLog: fBase] > ifFalse: [self floorLog: fBase]. > scale := 1.0. > logScale := 0. > [(x := fBase raisedTo: (exp + logScale)) = 0] > whileTrue: > [scale := scale * fBase. > logScale := logScale + 1]. > x := self * scale / x. > fuzz := fBase raisedTo: 1 - digitCount. > "round the last digit to be printed" > x := 0.5 * fuzz + x. > x >= fBase > ifTrue: > ["check if rounding has unnormalized x" > x := x / fBase. > exp := exp + 1]. > (exp < 6 and: [exp > -4]) > ifTrue: > ["decimal notation" > q := 0. > exp < 0 ifTrue: [1 to: 1 - exp do: [:i | aStream nextPut: ('0.0000' > at: i)]]] > ifFalse: > ["scientific notation" > q := exp. > exp := 0]. > [x >= fuzz] > whileTrue: > ["use fuzz to track significance" > xi := x asInteger. > aStream nextPut: (Character digitValue: xi). > x := x - xi asFloat * fBase. > fuzz := fuzz * fBase. > exp := exp - 1. > exp = -1 ifTrue: [aStream nextPut: $.]]. > [exp >= -1] > whileTrue: > [aStream nextPut: $0. > exp := exp - 1. > exp = -1 ifTrue: [aStream nextPut: $.]]. > q ~= 0 > ifTrue: > [aStream nextPut: $e. > q printOn: aStream]! > > Item was added: > + ----- Method: Float>>printOn:maxDecimalPlaces: (in category 'printing') ----- > + printOn: aStream maxDecimalPlaces: placesDesired > + "Refine super implementation in order to avoid any rounding error caused by rounded or roundTo:" > + > + self isFinite ifFalse: [^self printOn: aStream]. > + self > 0.0 > + ifTrue: [self absPrintExactlyOn: aStream base: 10 decimalPlaces: placesDesired showTrailingFractionalZeros: false] > + ifFalse: > + [self sign = -1 > + ifTrue: [aStream nextPutAll: '-']. > + self = 0.0 > + ifTrue: [aStream nextPutAll: '0.0'] > + ifFalse: [self absPrintExactlyOn: aStream base: 10 decimalPlaces: placesDesired showTrailingFractionalZeros: false]]! > > Item was added: > + ----- Method: Float>>printOn:showingDecimalPlaces: (in category 'printing') ----- > + printOn: aStream showingDecimalPlaces: placesDesired > + "Refine super implementation in order to avoid any rounding error caused by rounded or roundTo:" > + > + self isFinite ifFalse: [^self printOn: aStream]. > + self > 0.0 > + ifTrue: [self absPrintExactlyOn: aStream base: 10 decimalPlaces: placesDesired showTrailingFractionalZeros: true] > + ifFalse: > + [self sign = -1 > + ifTrue: [aStream nextPutAll: '-']. > + self = 0.0 > + ifTrue: [aStream nextPutAll: '0.0'] > + ifFalse: [self absPrintExactlyOn: aStream base: 10 decimalPlaces: placesDesired showTrailingFractionalZeros: true]]! > > Item was removed: > - ----- Method: Float>>printShowingDecimalPlaces: (in category 'printing') ----- > - printShowingDecimalPlaces: placesDesired > - "This implementation avoids any rounding error caused by rounded or roundTo:" > - > - self isFinite ifFalse: [^self printString]. > - ^self asTrueFraction printShowingDecimalPlaces: placesDesired! > > |
I posted in inbox in order to obtain an agreement on features, rather
than begging for beta-testers. For testing, Burger & Dybvig papers report that a set of 250 680 float was used and compared to various libc printf (the linux and solaris one were rounding correctly, the SGI, HP, RS6000 and Dec Alpha all suffered from some incorrect rounding at time of writing). We should really have such intensive tests, but maybe make them optional... With our rational arithmetic, we can also test correct rounding without a reference to external library : 1) we produce a printed representation 2) we re-interpret the printed representation in rational arithmetic 3) we test (original asTrueFraction - reconstructed) abs <= (original ulp / 2) for free format 4) we test (original asTrueFraction - reconstructed) abs <= (((base raisedTo: placesDesired) reciprocal max: original ulp) / 2) for fixed format But 2 bugs in printing and scanning could eventually compensate... Testing that printed representation is the shortest form having this property is a bit more involved... Nicolas 2012/5/20 Bert Freudenberg <[hidden email]>: > Looks good to me - but I doubt you will get any testing unless you actually commit to trunk :) > > - Bert - > > On 20.05.2012, at 08:05, [hidden email] wrote: > >> A new version of Kernel was added to project The Inbox: >> http://source.squeak.org/inbox/Kernel-nice.690.mcz >> >> ==================== Summary ==================== >> >> Name: Kernel-nice.690 >> Author: nice >> Time: 20 May 2012, 10:05:07.444 am >> UUID: 2c2aba8b-d8bd-4ec3-8b88-a873de9c68c4 >> Ancestors: Kernel-nice.689 >> >> 1) Correct the very new #printOn:maxDecimalPlaces: which often rounds inexactly for large Float or large number of digits. >> Rationale: the printed representation shall be rounded exactly >> >> 2) Don't print arbitrary digits beyond Float precision, just print zeros >> (0.1 printShowingDecimalPlaces: 20) now prints '0.10000000000000000000' instead of '0.10000000000000000555', >> Rationale: those digits, while reflecting internal representation exactly, are totally insignificant and could be replaced with any other digits, while still representing the same Float. >> >> 3) Print the negative sign, even if the number vanishes to zero at prescribed decimal places >> (-0.001 printShowingDecimalPlaces: 2) now prints '-0.00' instead of '0.00', >> Rationale: this behaves like classical lib printf, and is in the spirit of Float negativeZero printString: when the precision vanishes, the Float keeps its sign. >> >> Note: I find the scheme feature which prints # for insignificant digits is very nice, but we should find a re-interpretable format... >> >> Implementation details: >> >> Of course, algorithms are taken from: >> Robert G. Burger and R. Kent Dybvig >> Printing Floating Point Numbers Quickly and Accurately >> ACM SIGPLAN 1996 Conference on Programming Language Design and Implementation >> June 1996. >> >> Note that there is lot of duplicated code between free format and fixed format Float printing. >> And we should also fix the case of fixed number of digits #absPrintOn:base:digitCount: ... >> >> =============== Diff against Kernel-nice.689 =============== >> >> Item was added: >> + ----- Method: Float>>absPrintExactlyOn:base:decimalPlaces:showTrailingFractionalZeros: (in category 'printing') ----- >> + absPrintExactlyOn: aStream base: base decimalPlaces: placesDesired showTrailingFractionalZeros: showtrailingZeros >> + "Print my value on a stream in the given base with fixed number of digits after floating point. >> + When placesDesired are beyond Float precision, zeroes are appended. >> + When showtrailingZeros is false, the trailing zeroes after decimal point will be omitted. >> + If all fractional digits are zeros, the decimal point is omitted too. >> + Assumes that my value is strictly positive; negative numbers, zero, and NaNs have already been handled elsewhere. >> + Based upon the algorithm outlined in: >> + Robert G. Burger and R. Kent Dybvig >> + Printing Floating Point Numbers Quickly and Accurately >> + ACM SIGPLAN 1996 Conference on Programming Language Design and Implementation >> + June 1996.." >> + >> + | significand exp baseExpEstimate r s mPlus mMinus scale roundingLowIncludesLimits roundingHighIncludesLimits d tc1 tc2 decPointCount slowbit shead delta | >> + self isInfinite ifTrue: [aStream nextPutAll: 'Infinity'. ^ self]. >> + significand := self significandAsInteger. >> + exp := (self exponent - 52) max: MinValLogBase2. >> + 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]]. >> + delta := s / 2 / (base raisedTo: placesDesired). >> + roundingLowIncludesLimits := (mMinus < delta and: [mMinus := delta. true]) or: [significand even]. >> + roundingHighIncludesLimits := (mPlus < delta and: [mPlus := delta. true]) or: [significand even]. >> + baseExpEstimate := (self exponent * base asFloat reciprocalLogBase2 - 1.0e-10) ceiling. >> + baseExpEstimate >= 0 >> + ifTrue: [s := s * (base raisedToInteger: baseExpEstimate)] >> + ifFalse: >> + [scale := base raisedToInteger: baseExpEstimate negated. >> + r := r * scale. >> + mPlus := mPlus * scale. >> + mMinus := mMinus * scale]. >> + ((r + mPlus >= s) and: [roundingHighIncludesLimits or: [r + mPlus > s]]) >> + ifTrue: [baseExpEstimate := baseExpEstimate + 1] >> + ifFalse: >> + [r := r * base. >> + mPlus := mPlus * base. >> + mMinus := mMinus * base]. >> + decPointCount := baseExpEstimate. >> + baseExpEstimate <= 0 >> + ifTrue: >> + [placesDesired + baseExpEstimate <= 0 >> + ifTrue: >> + [aStream nextPut: $0. >> + (showtrailingZeros and: [placesDesired > 0]) ifTrue: [aStream nextPut: $.; nextPutAll: (String new: placesDesired withAll: $0)]. >> + ^self]. >> + aStream nextPutAll: '0.'; nextPutAll: (String new: 0 - baseExpEstimate withAll: $0)]. >> + slowbit := 1 - s lowBit . >> + shead := s bitShift: slowbit. >> + [d := (r bitShift: slowbit) // shead. >> + r := r - (d * s). >> + (tc1 := (r <= mMinus) and: [roundingLowIncludesLimits or: [r < mMinus]]) | >> + (tc2 := (r + mPlus >= s) and: [roundingHighIncludesLimits or: [r + mPlus > s]])] whileFalse: >> + [aStream nextPut: (Character digitValue: d). >> + r := r * base. >> + mPlus := mPlus * base. >> + mMinus := mMinus * base. >> + (decPointCount := decPointCount - 1) = 0 ifTrue: [aStream nextPut: $.]]. >> + tc2 ifTrue: >> + [(tc1 not or: [r * 2 >= s]) ifTrue: [d := d + 1]]. >> + aStream nextPut: (Character digitValue: d). >> + decPointCount > 0 >> + ifTrue: >> + [decPointCount - 1 to: 1 by: -1 do: [:i | aStream nextPut: $0]. >> + (showtrailingZeros and: [placesDesired > 0]) ifTrue: [aStream nextPut: $.; nextPutAll: (String new: placesDesired withAll: $0)]] >> + ifFalse: >> + [(showtrailingZeros and: [placesDesired + decPointCount > 1]) ifTrue: [aStream nextPutAll: (String new: placesDesired + decPointCount - 1 withAll: $0)]].! >> >> Item was changed: >> + ----- Method: Float>>absPrintOn:base:digitCount: (in category 'printing') ----- >> - ----- Method: Float>>absPrintOn:base:digitCount: (in category 'private') ----- >> absPrintOn: aStream base: base digitCount: digitCount >> "Print me in the given base, using digitCount significant figures." >> >> | fuzz x exp q fBase scale logScale xi | >> self isInfinite ifTrue: [^ aStream nextPutAll: 'Inf']. >> fBase := base asFloat. >> "x is myself normalized to [1.0, fBase), exp is my exponent" >> exp := >> self < 1.0 >> ifTrue: [self reciprocalFloorLog: fBase] >> ifFalse: [self floorLog: fBase]. >> scale := 1.0. >> logScale := 0. >> [(x := fBase raisedTo: (exp + logScale)) = 0] >> whileTrue: >> [scale := scale * fBase. >> logScale := logScale + 1]. >> x := self * scale / x. >> fuzz := fBase raisedTo: 1 - digitCount. >> "round the last digit to be printed" >> x := 0.5 * fuzz + x. >> x >= fBase >> ifTrue: >> ["check if rounding has unnormalized x" >> x := x / fBase. >> exp := exp + 1]. >> (exp < 6 and: [exp > -4]) >> ifTrue: >> ["decimal notation" >> q := 0. >> exp < 0 ifTrue: [1 to: 1 - exp do: [:i | aStream nextPut: ('0.0000' >> at: i)]]] >> ifFalse: >> ["scientific notation" >> q := exp. >> exp := 0]. >> [x >= fuzz] >> whileTrue: >> ["use fuzz to track significance" >> xi := x asInteger. >> aStream nextPut: (Character digitValue: xi). >> x := x - xi asFloat * fBase. >> fuzz := fuzz * fBase. >> exp := exp - 1. >> exp = -1 ifTrue: [aStream nextPut: $.]]. >> [exp >= -1] >> whileTrue: >> [aStream nextPut: $0. >> exp := exp - 1. >> exp = -1 ifTrue: [aStream nextPut: $.]]. >> q ~= 0 >> ifTrue: >> [aStream nextPut: $e. >> q printOn: aStream]! >> >> Item was added: >> + ----- Method: Float>>printOn:maxDecimalPlaces: (in category 'printing') ----- >> + printOn: aStream maxDecimalPlaces: placesDesired >> + "Refine super implementation in order to avoid any rounding error caused by rounded or roundTo:" >> + >> + self isFinite ifFalse: [^self printOn: aStream]. >> + self > 0.0 >> + ifTrue: [self absPrintExactlyOn: aStream base: 10 decimalPlaces: placesDesired showTrailingFractionalZeros: false] >> + ifFalse: >> + [self sign = -1 >> + ifTrue: [aStream nextPutAll: '-']. >> + self = 0.0 >> + ifTrue: [aStream nextPutAll: '0.0'] >> + ifFalse: [self absPrintExactlyOn: aStream base: 10 decimalPlaces: placesDesired showTrailingFractionalZeros: false]]! >> >> Item was added: >> + ----- Method: Float>>printOn:showingDecimalPlaces: (in category 'printing') ----- >> + printOn: aStream showingDecimalPlaces: placesDesired >> + "Refine super implementation in order to avoid any rounding error caused by rounded or roundTo:" >> + >> + self isFinite ifFalse: [^self printOn: aStream]. >> + self > 0.0 >> + ifTrue: [self absPrintExactlyOn: aStream base: 10 decimalPlaces: placesDesired showTrailingFractionalZeros: true] >> + ifFalse: >> + [self sign = -1 >> + ifTrue: [aStream nextPutAll: '-']. >> + self = 0.0 >> + ifTrue: [aStream nextPutAll: '0.0'] >> + ifFalse: [self absPrintExactlyOn: aStream base: 10 decimalPlaces: placesDesired showTrailingFractionalZeros: true]]! >> >> Item was removed: >> - ----- Method: Float>>printShowingDecimalPlaces: (in category 'printing') ----- >> - printShowingDecimalPlaces: placesDesired >> - "This implementation avoids any rounding error caused by rounded or roundTo:" >> - >> - self isFinite ifFalse: [^self printString]. >> - ^self asTrueFraction printShowingDecimalPlaces: placesDesired! >> >> > > |
On 20.05.2012, at 13:54, Nicolas Cellier wrote:
> I posted in inbox in order to obtain an agreement on features, rather > than begging for beta-testers. Ah. Well, my needs are modest: I want to be able to print floats precisely, and up to a given precision. Storing should match reading so a repeated store/read does not change the value. I leave the details to people more knowledgable in that area, such as you :) - Bert - > For testing, Burger & Dybvig papers report that a set of 250 680 float > was used and compared to various libc printf (the linux and solaris > one were rounding correctly, the SGI, HP, RS6000 and Dec Alpha all > suffered from some incorrect rounding at time of writing). > We should really have such intensive tests, but maybe make them optional... > > With our rational arithmetic, we can also test correct rounding > without a reference to external library : > 1) we produce a printed representation > 2) we re-interpret the printed representation in rational arithmetic > 3) we test (original asTrueFraction - reconstructed) abs <= (original > ulp / 2) for free format > 4) we test (original asTrueFraction - reconstructed) abs <= (((base > raisedTo: placesDesired) reciprocal max: original ulp) / 2) for fixed > format > > But 2 bugs in printing and scanning could eventually compensate... > Testing that printed representation is the shortest form having this > property is a bit more involved... > > Nicolas > > 2012/5/20 Bert Freudenberg <[hidden email]>: >> Looks good to me - but I doubt you will get any testing unless you actually commit to trunk :) >> >> - Bert - |
In reply to this post by Nicolas Cellier
Regarding this change:
>> 2) Don't print arbitrary digits beyond Float precision, just print zeros >> (0.1 printShowingDecimalPlaces: 20) now prints '0.10000000000000000000' >> instead of '0.10000000000000000555', >> Rationale: those digits, while reflecting internal representation exactly, >> are totally insignificant and could be replaced with any other digits, while still representing the same Float. The rationale is correct, although a contrary argument might be that the trailing '555' digits provide a visual cue as to floating point precision. The visual reminder may be useful when mixing single and double precision floats. (FloatArray with: 0.1) first printShowingDecimalPlaces: 20 ==> '0.10000000149011611938' 0.1 asFloat printShowingDecimalPlaces: 20 ==> '0.10000000000000000555' Dave On Sun, May 20, 2012 at 01:54:23PM +0200, Nicolas Cellier wrote: > I posted in inbox in order to obtain an agreement on features, rather > than begging for beta-testers. > > For testing, Burger & Dybvig papers report that a set of 250 680 float > was used and compared to various libc printf (the linux and solaris > one were rounding correctly, the SGI, HP, RS6000 and Dec Alpha all > suffered from some incorrect rounding at time of writing). > We should really have such intensive tests, but maybe make them optional... > > With our rational arithmetic, we can also test correct rounding > without a reference to external library : > 1) we produce a printed representation > 2) we re-interpret the printed representation in rational arithmetic > 3) we test (original asTrueFraction - reconstructed) abs <= (original > ulp / 2) for free format > 4) we test (original asTrueFraction - reconstructed) abs <= (((base > raisedTo: placesDesired) reciprocal max: original ulp) / 2) for fixed > format > > But 2 bugs in printing and scanning could eventually compensate... > Testing that printed representation is the shortest form having this > property is a bit more involved... > > Nicolas > > 2012/5/20 Bert Freudenberg <[hidden email]>: > > Looks good to me - but I doubt you will get any testing unless you actually commit to trunk :) > > > > - Bert - > > > > On 20.05.2012, at 08:05, [hidden email] wrote: > > > >> A new version of Kernel was added to project The Inbox: > >> http://source.squeak.org/inbox/Kernel-nice.690.mcz > >> > >> ==================== Summary ==================== > >> > >> Name: Kernel-nice.690 > >> Author: nice > >> Time: 20 May 2012, 10:05:07.444 am > >> UUID: 2c2aba8b-d8bd-4ec3-8b88-a873de9c68c4 > >> Ancestors: Kernel-nice.689 > >> > >> 1) Correct the very new #printOn:maxDecimalPlaces: which often rounds inexactly for large Float or large number of digits. > >> Rationale: the printed representation shall be rounded exactly > >> > >> 2) Don't print arbitrary digits beyond Float precision, just print zeros > >> (0.1 printShowingDecimalPlaces: 20) now prints '0.10000000000000000000' instead of '0.10000000000000000555', > >> Rationale: those digits, while reflecting internal representation exactly, are totally insignificant and could be replaced with any other digits, while still representing the same Float. > >> > >> 3) Print the negative sign, even if the number vanishes to zero at prescribed decimal places > >> (-0.001 printShowingDecimalPlaces: 2) now prints '-0.00' instead of '0.00', > >> Rationale: this behaves like classical lib printf, and is in the spirit of Float negativeZero printString: when the precision vanishes, the Float keeps its sign. > >> > >> Note: I find the scheme feature which prints # for insignificant digits is very nice, but we should find a re-interpretable format... > >> > >> Implementation details: > >> > >> Of course, algorithms are taken from: > >> Robert G. Burger and R. Kent Dybvig > >> ? ? ? Printing Floating Point Numbers Quickly and Accurately > >> ? ? ? ACM SIGPLAN 1996 Conference on Programming Language Design and Implementation > >> ? ? ? June 1996. > >> > >> Note that there is lot of duplicated code between free format and fixed format Float printing. > >> And we should also fix the case of fixed number of digits #absPrintOn:base:digitCount: ... > >> > >> =============== Diff against Kernel-nice.689 =============== > >> > >> Item was added: > >> + ----- Method: Float>>absPrintExactlyOn:base:decimalPlaces:showTrailingFractionalZeros: (in category 'printing') ----- > >> + absPrintExactlyOn: aStream base: base decimalPlaces: placesDesired showTrailingFractionalZeros: showtrailingZeros > >> + ? ? "Print my value on a stream in the given base with fixed number of digits after floating point. > >> + ? ? When placesDesired are beyond Float precision, zeroes are appended. > >> + ? ? When showtrailingZeros is false, the trailing zeroes after decimal point will be omitted. > >> + ? ? If all fractional digits are zeros, the decimal point is omitted too. > >> + ? ? Assumes that my value is strictly positive; negative numbers, zero, and NaNs have already been handled elsewhere. > >> + ? ? Based upon the algorithm outlined in: > >> + ? ? Robert G. Burger and R. Kent Dybvig > >> + ? ? Printing Floating Point Numbers Quickly and Accurately > >> + ? ? ACM SIGPLAN 1996 Conference on Programming Language Design and Implementation > >> + ? ? June 1996.." > >> + > >> + ? ? | significand exp baseExpEstimate r s mPlus mMinus scale roundingLowIncludesLimits roundingHighIncludesLimits d tc1 tc2 decPointCount slowbit shead delta | > >> + ? ? self isInfinite ifTrue: [aStream nextPutAll: 'Infinity'. ^ self]. > >> + ? ? significand := self significandAsInteger. > >> + ? ? exp := (self exponent - 52) max: MinValLogBase2. > >> + ? ? 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]]. > >> + ? ? delta := s / 2 / (base raisedTo: placesDesired). > >> + ? ? roundingLowIncludesLimits := ?(mMinus < delta and: [mMinus := delta. true]) or: [significand even]. > >> + ? ? roundingHighIncludesLimits := (mPlus < delta and: [mPlus := delta. true]) or: [significand even]. > >> + ? ? baseExpEstimate := (self exponent * base asFloat reciprocalLogBase2 - 1.0e-10) ceiling. > >> + ? ? baseExpEstimate >= 0 > >> + ? ? ? ? ? ? ifTrue: [s := s * (base raisedToInteger: baseExpEstimate)] > >> + ? ? ? ? ? ? ifFalse: > >> + ? ? ? ? ? ? ? ? ? ? [scale := base raisedToInteger: baseExpEstimate negated. > >> + ? ? ? ? ? ? ? ? ? ? r := r * scale. > >> + ? ? ? ? ? ? ? ? ? ? mPlus := mPlus * scale. > >> + ? ? ? ? ? ? ? ? ? ? mMinus := mMinus * scale]. > >> + ? ? ((r + mPlus >= s) and: [roundingHighIncludesLimits or: [r + mPlus > s]]) > >> + ? ? ? ? ? ? ifTrue: [baseExpEstimate := baseExpEstimate + 1] > >> + ? ? ? ? ? ? ifFalse: > >> + ? ? ? ? ? ? ? ? ? ? [r := r * base. > >> + ? ? ? ? ? ? ? ? ? ? mPlus := mPlus * base. > >> + ? ? ? ? ? ? ? ? ? ? mMinus := mMinus * base]. > >> + ? ? decPointCount := baseExpEstimate. > >> + ? ? baseExpEstimate <= 0 > >> + ? ? ? ? ? ? ifTrue: > >> + ? ? ? ? ? ? ? ? ? ? [placesDesired + baseExpEstimate <= 0 > >> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ifTrue: > >> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? [aStream nextPut: $0. > >> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? (showtrailingZeros and: [placesDesired > 0]) ifTrue: [aStream nextPut: $.; nextPutAll: (String new: placesDesired withAll: $0)]. > >> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ^self]. > >> + ? ? ? ? ? ? ? ? ? ? aStream nextPutAll: '0.'; nextPutAll: (String new: 0 - baseExpEstimate withAll: $0)]. > >> + ? ? slowbit := 1 - s lowBit . > >> + ? ? shead := s bitShift: slowbit. > >> + ? ? [d := (r bitShift: slowbit) // shead. > >> + ? ? r := r - (d * s). > >> + ? ? (tc1 := (r <= mMinus) and: [roundingLowIncludesLimits or: [r < mMinus]]) | > >> + ? ? (tc2 := (r + mPlus >= s) and: [roundingHighIncludesLimits or: [r + mPlus > s]])] whileFalse: > >> + ? ? ? ? ? ? [aStream nextPut: (Character digitValue: d). > >> + ? ? ? ? ? ? r := r * base. > >> + ? ? ? ? ? ? mPlus := mPlus * base. > >> + ? ? ? ? ? ? mMinus := mMinus * base. > >> + ? ? ? ? ? ? (decPointCount := decPointCount - 1) = 0 ifTrue: [aStream nextPut: $.]]. > >> + ? ? tc2 ifTrue: > >> + ? ? ? ? ? ? [(tc1 not or: [r * 2 >= s]) ifTrue: [d := d + 1]]. > >> + ? ? aStream nextPut: (Character digitValue: d). > >> + ? ? decPointCount > 0 > >> + ? ? ? ? ? ? ifTrue: > >> + ? ? ? ? ? ? ? ? ? ? [decPointCount - 1 to: 1 by: -1 do: [:i | aStream nextPut: $0]. > >> + ? ? ? ? ? ? ? ? ? ? (showtrailingZeros and: [placesDesired > 0]) ifTrue: [aStream nextPut: $.; nextPutAll: (String new: placesDesired withAll: $0)]] > >> + ? ? ? ? ? ? ifFalse: > >> + ? ? ? ? ? ? ? ? ? ? [(showtrailingZeros and: [placesDesired + decPointCount > 1]) ifTrue: [aStream nextPutAll: (String new: placesDesired + decPointCount - 1 withAll: $0)]].! > >> > >> Item was changed: > >> + ----- Method: Float>>absPrintOn:base:digitCount: (in category 'printing') ----- > >> - ----- Method: Float>>absPrintOn:base:digitCount: (in category 'private') ----- > >> ?absPrintOn: aStream base: base digitCount: digitCount > >> ? ? ? "Print me in the given base, using digitCount significant figures." > >> > >> ? ? ? | fuzz x exp q fBase scale logScale xi | > >> ? ? ? self isInfinite ifTrue: [^ aStream nextPutAll: 'Inf']. > >> ? ? ? fBase := base asFloat. > >> ? ? ? "x is myself normalized to [1.0, fBase), exp is my exponent" > >> ? ? ? exp := > >> ? ? ? ? ? ? ? self < 1.0 > >> ? ? ? ? ? ? ? ? ? ? ? ifTrue: [self reciprocalFloorLog: fBase] > >> ? ? ? ? ? ? ? ? ? ? ? ifFalse: [self floorLog: fBase]. > >> ? ? ? scale := 1.0. > >> ? ? ? logScale := 0. > >> ? ? ? [(x := fBase raisedTo: (exp + logScale)) = 0] > >> ? ? ? ? ? ? ? whileTrue: > >> ? ? ? ? ? ? ? ? ? ? ? [scale := scale * fBase. > >> ? ? ? ? ? ? ? ? ? ? ? logScale := logScale + 1]. > >> ? ? ? x := self * scale / x. > >> ? ? ? fuzz := fBase raisedTo: 1 - digitCount. > >> ? ? ? "round the last digit to be printed" > >> ? ? ? x := 0.5 * fuzz + x. > >> ? ? ? x >= fBase > >> ? ? ? ? ? ? ? ifTrue: > >> ? ? ? ? ? ? ? ? ? ? ? ["check if rounding has unnormalized x" > >> ? ? ? ? ? ? ? ? ? ? ? x := x / fBase. > >> ? ? ? ? ? ? ? ? ? ? ? exp := exp + 1]. > >> ? ? ? (exp < 6 and: [exp > -4]) > >> ? ? ? ? ? ? ? ifTrue: > >> ? ? ? ? ? ? ? ? ? ? ? ["decimal notation" > >> ? ? ? ? ? ? ? ? ? ? ? q := 0. > >> ? ? ? ? ? ? ? ? ? ? ? exp < 0 ifTrue: [1 to: 1 - exp do: [:i | aStream nextPut: ('0.0000' > >> ?at: i)]]] > >> ? ? ? ? ? ? ? ifFalse: > >> ? ? ? ? ? ? ? ? ? ? ? ["scientific notation" > >> ? ? ? ? ? ? ? ? ? ? ? q := exp. > >> ? ? ? ? ? ? ? ? ? ? ? exp := 0]. > >> ? ? ? [x >= fuzz] > >> ? ? ? ? ? ? ? whileTrue: > >> ? ? ? ? ? ? ? ? ? ? ? ["use fuzz to track significance" > >> ? ? ? ? ? ? ? ? ? ? ? xi := x asInteger. > >> ? ? ? ? ? ? ? ? ? ? ? aStream nextPut: (Character digitValue: xi). > >> ? ? ? ? ? ? ? ? ? ? ? x := x - xi asFloat * fBase. > >> ? ? ? ? ? ? ? ? ? ? ? fuzz := fuzz * fBase. > >> ? ? ? ? ? ? ? ? ? ? ? exp := exp - 1. > >> ? ? ? ? ? ? ? ? ? ? ? exp = -1 ifTrue: [aStream nextPut: $.]]. > >> ? ? ? [exp >= -1] > >> ? ? ? ? ? ? ? whileTrue: > >> ? ? ? ? ? ? ? ? ? ? ? [aStream nextPut: $0. > >> ? ? ? ? ? ? ? ? ? ? ? exp := exp - 1. > >> ? ? ? ? ? ? ? ? ? ? ? exp = -1 ifTrue: [aStream nextPut: $.]]. > >> ? ? ? q ~= 0 > >> ? ? ? ? ? ? ? ifTrue: > >> ? ? ? ? ? ? ? ? ? ? ? [aStream nextPut: $e. > >> ? ? ? ? ? ? ? ? ? ? ? q printOn: aStream]! > >> > >> Item was added: > >> + ----- Method: Float>>printOn:maxDecimalPlaces: (in category 'printing') ----- > >> + printOn: aStream maxDecimalPlaces: placesDesired > >> + ? ? "Refine super implementation in order to avoid any rounding error caused by rounded or roundTo:" > >> + > >> + ? ? self isFinite ifFalse: [^self printOn: aStream]. > >> + ? ? self > 0.0 > >> + ? ? ? ? ? ? ifTrue: [self absPrintExactlyOn: aStream base: 10 decimalPlaces: placesDesired showTrailingFractionalZeros: false] > >> + ? ? ? ? ? ? ifFalse: > >> + ? ? ? ? ? ? ? ? ? ? [self sign = -1 > >> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ifTrue: [aStream nextPutAll: '-']. > >> + ? ? ? ? ? ? ? ? ? ? self = 0.0 > >> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ifTrue: [aStream nextPutAll: '0.0'] > >> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ifFalse: [self absPrintExactlyOn: aStream base: 10 decimalPlaces: placesDesired showTrailingFractionalZeros: false]]! > >> > >> Item was added: > >> + ----- Method: Float>>printOn:showingDecimalPlaces: (in category 'printing') ----- > >> + printOn: aStream showingDecimalPlaces: placesDesired > >> + ? ? "Refine super implementation in order to avoid any rounding error caused by rounded or roundTo:" > >> + > >> + ? ? self isFinite ifFalse: [^self printOn: aStream]. > >> + ? ? self > 0.0 > >> + ? ? ? ? ? ? ifTrue: [self absPrintExactlyOn: aStream base: 10 decimalPlaces: placesDesired showTrailingFractionalZeros: true] > >> + ? ? ? ? ? ? ifFalse: > >> + ? ? ? ? ? ? ? ? ? ? [self sign = -1 > >> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ifTrue: [aStream nextPutAll: '-']. > >> + ? ? ? ? ? ? ? ? ? ? self = 0.0 > >> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ifTrue: [aStream nextPutAll: '0.0'] > >> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ifFalse: [self absPrintExactlyOn: aStream base: 10 decimalPlaces: placesDesired showTrailingFractionalZeros: true]]! > >> > >> Item was removed: > >> - ----- Method: Float>>printShowingDecimalPlaces: (in category 'printing') ----- > >> - printShowingDecimalPlaces: placesDesired > >> - ? ? "This implementation avoids any rounding error caused by rounded or roundTo:" > >> - > >> - ? ? self isFinite ifFalse: [^self printString]. > >> - ? ? ^self asTrueFraction printShowingDecimalPlaces: placesDesired! > >> > >> > > > > |
On 20.05.2012, at 14:54, David T. Lewis wrote: > Regarding this change: > >>> 2) Don't print arbitrary digits beyond Float precision, just print zeros >>> (0.1 printShowingDecimalPlaces: 20) now prints '0.10000000000000000000' >>> instead of '0.10000000000000000555', >>> Rationale: those digits, while reflecting internal representation exactly, >>> are totally insignificant and could be replaced with any other digits, while still representing the same Float. > > The rationale is correct, although a contrary argument might be that > the trailing '555' digits provide a visual cue as to floating point > precision. The visual reminder may be useful when mixing single and > double precision floats. > > (FloatArray with: 0.1) first printShowingDecimalPlaces: 20 > ==> '0.10000000149011611938' > > 0.1 asFloat printShowingDecimalPlaces: 20 > ==> '0.10000000000000000555' > > Dave But 0.10000000000000000555 = 0.10000000000000000000 What do you gain by showing the byproducts of the printing algorithm, which have nothing to do with the actual number? - Bert - |
2012/5/20 Bert Freudenberg <[hidden email]>:
> > On 20.05.2012, at 14:54, David T. Lewis wrote: > >> Regarding this change: >> >>>> 2) Don't print arbitrary digits beyond Float precision, just print zeros >>>> (0.1 printShowingDecimalPlaces: 20) now prints '0.10000000000000000000' >>>> instead of '0.10000000000000000555', >>>> Rationale: those digits, while reflecting internal representation exactly, >>>> are totally insignificant and could be replaced with any other digits, while still representing the same Float. >> >> The rationale is correct, although a contrary argument might be that >> the trailing '555' digits provide a visual cue as to floating point >> precision. The visual reminder may be useful when mixing single and >> double precision floats. >> >> (FloatArray with: 0.1) first printShowingDecimalPlaces: 20 >> ==> '0.10000000149011611938' >> >> 0.1 asFloat printShowingDecimalPlaces: 20 >> ==> '0.10000000000000000555' >> >> Dave > > > But > > 0.10000000000000000555 = 0.10000000000000000000 > > What do you gain by showing the byproducts of the printing algorithm, which have nothing to do with the actual number? > > - Bert - > That's why I prefer scheme 0.10000000000000000###, but since this is not a valid literal syntax, I didn't dare... Nicolas > > |
On 20.05.2012, at 15:56, Nicolas Cellier wrote: > 2012/5/20 Bert Freudenberg <[hidden email]>: >> >> On 20.05.2012, at 14:54, David T. Lewis wrote: >> >>> Regarding this change: >>> >>>>> 2) Don't print arbitrary digits beyond Float precision, just print zeros >>>>> (0.1 printShowingDecimalPlaces: 20) now prints '0.10000000000000000000' >>>>> instead of '0.10000000000000000555', >>>>> Rationale: those digits, while reflecting internal representation exactly, >>>>> are totally insignificant and could be replaced with any other digits, while still representing the same Float. >>> >>> The rationale is correct, although a contrary argument might be that >>> the trailing '555' digits provide a visual cue as to floating point >>> precision. The visual reminder may be useful when mixing single and >>> double precision floats. >>> >>> (FloatArray with: 0.1) first printShowingDecimalPlaces: 20 >>> ==> '0.10000000149011611938' >>> >>> 0.1 asFloat printShowingDecimalPlaces: 20 >>> ==> '0.10000000000000000555' >>> >>> Dave >> >> >> But >> >> 0.10000000000000000555 = 0.10000000000000000000 >> >> What do you gain by showing the byproducts of the printing algorithm, which have nothing to do with the actual number? >> >> - Bert - >> > > That's why I prefer scheme 0.10000000000000000###, but since this is > not a valid literal syntax, I didn't dare... > > Nicolas David: Float pi printShowingDecimalPlaces: 30 ==> '3.141592653589793115997963468544' (before) ==> '3.141592653589793000000000000000' (after) The latter seems way better to me. - Bert - |
On Sun, May 20, 2012 at 05:42:04PM +0200, Bert Freudenberg wrote:
> > On 20.05.2012, at 15:56, Nicolas Cellier wrote: > > > 2012/5/20 Bert Freudenberg <[hidden email]>: > >> > >> On 20.05.2012, at 14:54, David T. Lewis wrote: > >> > >>> Regarding this change: > >>> > >>>>> 2) Don't print arbitrary digits beyond Float precision, just print zeros > >>>>> (0.1 printShowingDecimalPlaces: 20) now prints '0.10000000000000000000' > >>>>> instead of '0.10000000000000000555', > >>>>> Rationale: those digits, while reflecting internal representation exactly, > >>>>> are totally insignificant and could be replaced with any other digits, while still representing the same Float. > >>> > >>> The rationale is correct, although a contrary argument might be that > >>> the trailing '555' digits provide a visual cue as to floating point > >>> precision. The visual reminder may be useful when mixing single and > >>> double precision floats. > >>> > >>> (FloatArray with: 0.1) first printShowingDecimalPlaces: 20 > >>> ==> '0.10000000149011611938' > >>> > >>> 0.1 asFloat printShowingDecimalPlaces: 20 > >>> ==> '0.10000000000000000555' > >>> > >>> Dave > >> > >> > >> But > >> > >> 0.10000000000000000555 = 0.10000000000000000000 > >> > >> What do you gain by showing the byproducts of the printing algorithm, which have nothing to do with the actual number? > >> > >> - Bert - > >> > > > > That's why I prefer scheme 0.10000000000000000###, but since this is > > not a valid literal syntax, I didn't dare... > > > > Nicolas > > > David: > > Float pi printShowingDecimalPlaces: 30 > ==> '3.141592653589793115997963468544' (before) > ==> '3.141592653589793000000000000000' (after) > > The latter seems way better to me. > +1 I'm fine with the change, I was just trying to think of some possible objection so we could say we discussed it ;) Dave |
Free forum by Nabble | Edit this page |