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

commits at source.squeak.org commits at source.squeak.org
Fri May 7 19:39:50 UTC 2021


Nicolas Cellier uploaded a new version of Kernel to project The Trunk:
http://source.squeak.org/trunk/Kernel-nice.1402.mcz

==================== Summary ====================

Name: Kernel-nice.1402
Author: nice
Time: 7 May 2021, 9:39:45.713143 pm
UUID: 21ee698b-9f75-40e3-9bd3-944e73cb9e20
Ancestors: Kernel-nice.1401

Fix sqrt bugs exposed by #testSqrtNearExactTie.

If we pretend to round to nearest, we must do it right, not just pretend...

How was the problem found? Accidentally...
I re-examined our implementation after musing in SO:
https://stackoverflow.com/questions/67361541/correctly-rounded-computation-of-sqrt-of-sum-of-two-floats-handling-overflow/67426790#67426790

Musing is more powerful than dumb static and coverage tests, I wish I got more time for musing :)
We deadly need evolutive testing (neural based).

=============== Diff against Kernel-nice.1401 ===============

Item was changed:
  ----- Method: LargePositiveInteger>>sqrt (in category 'mathematical functions') -----
  sqrt
  	"Answer the square root of the receiver.
  	If the square root is exact, answer an Integer, else answer a Float approximation.
  	Make sure the result is correctly rounded (i.e. the nearest Float to the exact square root)"
  	
+ 	| floatResult integerResult guardBit highBit sr maybeExact |
+ 	maybeExact := self mightBeASquare.
+ 	self isAnExactFloat
- 	| floatResult integerResult guardBit highBit sr |
- 	(highBit := self highBit) < (Float precision * 2)
  		ifTrue:
  			["the sqrt of self asFloat is correctly rounded, so use it"
  			floatResult := self asFloat sqrt.
+ 			maybeExact ifFalse: [^floatResult].
- 			self mightBeASquare ifFalse: [^floatResult].
  			"Answer integerResult in case of perfect square"
  			integerResult := floatResult truncated.
  			integerResult squared = self ifTrue: [^integerResult].
  			^floatResult].
  
+ 	"Eventually use guard bits for handling correct rounding direction"
+ 	highBit := self highBit.
- 	"Eventually use a guard bit for handling correct rounding direction"
  	guardBit := highBit <= (Float precision + 1 * 2)
  		ifTrue:
+ 			["Add guard bits for rounding correctly"
+ 			Float precision + 1 * 2 + 1 - highBit]
- 			["Add one guard bit for rounding correctly"
- 			1]
  		ifFalse:
+ 			[maybeExact
- 			[self mightBeASquare
  				ifTrue:
+ 					["Keep all the bits in case we were a perfect square"
- 					["Keep all the bits in case we are a perfect square"
  					0]
  				ifFalse:
+ 					["Remove superfluous bits that won't change the Float approximation"
- 					["Remove superfluous bit that won't change the Float approximation"
  					Float precision + 1 - (highBit // 2)]].
  	
  	"Get truncated sqrt and remainder for the same price"
  	sr := (self bitShift: guardBit * 2) sqrtRem.
  	
  	"Handle case of perfect square"
  	integerResult := sr first.
+ 	(maybeExact and: [sr last isZero]) ifTrue: [^integerResult bitShift: guardBit negated].
- 	sr last isZero ifTrue: [^integerResult bitShift: guardBit negated].
  	
  	"Answer the best we have which is the sqrt correctly rounded at Float precision."
  	^((integerResult bitShift: Float precision - integerResult highBit)
  		+ (integerResult bitAt: integerResult highBit - Float precision)) asFloat
  			timesTwoPower: integerResult highBit - Float precision - guardBit!



More information about the Squeak-dev mailing list