[squeak-dev] The Inbox: Kernel-nice.690.mcz

David T. Lewis lewis at mail.msen.com
Sun May 20 12:54:12 UTC 2012


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 <bert at freudenbergs.de>:
> > 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, commits at source.squeak.org 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!
> >>
> >>
> >
> >


More information about the Squeak-dev mailing list