The Inbox: Kernel-nice.690.mcz

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
9 messages Options
Reply | Threaded
Open this post in threaded view
|

The Inbox: Kernel-nice.690.mcz

commits-2
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!


Reply | Threaded
Open this post in threaded view
|

Re: The Inbox: Kernel-nice.690.mcz

Bert Freudenberg
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!
>
>


Reply | Threaded
Open this post in threaded view
|

Re: The Inbox: Kernel-nice.690.mcz

Nicolas Cellier
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!
>>
>>
>
>

Reply | Threaded
Open this post in threaded view
|

Re: The Inbox: Kernel-nice.690.mcz

Bert Freudenberg
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 -





Reply | Threaded
Open this post in threaded view
|

Re: The Inbox: Kernel-nice.690.mcz

David T. Lewis
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!
> >>
> >>
> >
> >

Reply | Threaded
Open this post in threaded view
|

Re: The Inbox: Kernel-nice.690.mcz

Bert Freudenberg

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 -



Reply | Threaded
Open this post in threaded view
|

Re: The Inbox: Kernel-nice.690.mcz

Nicolas Cellier
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

>
>

Reply | Threaded
Open this post in threaded view
|

Re: The Inbox: Kernel-nice.690.mcz

Bert Freudenberg

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 -



Reply | Threaded
Open this post in threaded view
|

Re: The Inbox: Kernel-nice.690.mcz

David T. Lewis
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