[squeakdev] The Trunk: Kernelnice.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/Kernelnice.1402.mcz
==================== Summary ====================
Name: Kernelnice.1402
Author: nice
Time: 7 May 2021, 9:39:45.713143 pm
UUID: 21ee698b9f7540e39bd3944e73cb9e20
Ancestors: Kernelnice.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 reexamined our implementation after musing in SO:
https://stackoverflow.com/questions/67361541/correctlyroundedcomputationofsqrtofsumoftwofloatshandlingoverflow/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 Kernelnice.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 Squeakdev
mailing list
