[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
|