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

commits at source.squeak.org commits at source.squeak.org
Tue May 22 20:12:18 UTC 2012


Nicolas Cellier uploaded a new version of Kernel to project The Trunk:
http://source.squeak.org/trunk/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