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

commits at source.squeak.org commits at source.squeak.org
Mon Sep 26 20:20:36 UTC 2011

```A new version of Kernel was added to project The Inbox:
http://source.squeak.org/inbox/Kernel-nice.630.mcz

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

Name: Kernel-nice.630
Author: nice
Time: 26 September 2011, 10:20:03.656 pm
UUID: 741a02d5-c9f3-4549-8013-a77ffe1305b1
Ancestors: Kernel-nice.629

With the help of Andres remarks, and a bit of magic (7 and 30), here is an ever faster LargeInteger>>asFloat. Non portable to other precision than double, but cute.

=============== Diff against Kernel-nice.629 ===============

Item was changed:
----- Method: LargePositiveInteger>>asFloat (in category 'converting') -----
asFloat
This algorithm is optimized to process only the significant digits of a LargeInteger.
And it does honour IEEE 754 round to nearest even mode in case of excess precision (see details below)."

"How numbers are rounded in IEEE 754 default rounding mode:
A shift is applied so that the highest 53 bits are placed before the floating point to form a mantissa.
The trailing bits form the fraction part placed after the floating point.
This fractional number must be rounded to the nearest integer.
If fraction part is 2r0.1, exactly between two consecutive integers, there is a tie.
The nearest even integer is chosen in this case.
Examples (First 52bits of mantissa are omitted for brevity):
2r0.00001 is rounded downward to 2r0
2r1.00001 is rounded downward to 2r1
2r0.1 is a tie and rounded to 2r0 (nearest even)
2r1.1 is a tie and rounded to 2r10 (nearest even)
2r0.10001 is rounded upward to 2r1
2r1.10001 is rounded upward to 2r10
Thus, if the next bit after floating point is 0, the mantissa is left unchanged.
If next bit after floating point is 1, an odd mantissa is always rounded upper.
An even mantissa is rounded upper only if the fraction part is not a tie."

"Algorihm details:
+ 	Floating point hardware will correctly handle the rounding by itself if there is a single inexact operation.
- 	Floating point hardware will correctly handle the rounding by itself with a single inexact operation if mantissa has one excess bit of precision.
Except in the last case when extra bits are present after an even mantissa, we must round upper by ourselves.
Note 1: the inexact flag in floating point hardware must not be trusted because it won't take into account the bits we truncated by ourselves.
Note 2: the floating point hardware is presumed configured in default rounding mode."

+ 	| mantissa shift excess |
- 	| mantissa shift sum excess |

"Check how many bits excess the maximum precision of a Float mantissa."
excess := self highBitOfMagnitude - Float precision.
+ 	excess > 7
- 	excess > 1
ifTrue:
+ 			["Remove the excess bits but seven.
+ 			Float precision + 7 = 60 bits = 2 * length of positive small integer"
+ 			mantissa := self bitShiftMagnitude: 7 - excess.
+ 			shift := excess - 7.
- 			["Remove the excess bits but one."
- 			mantissa := self bitShift: 1 - excess.
- 			shift := excess - 1.
"Handle the case of extra bits truncated after an even mantissa."
+ 			((mantissa digitAt: 1) = 2r01000000 and: [self anyBitOfMagnitudeFrom: 1 to: shift])
- 			((mantissa bitAnd: 2r11) = 2r01 and: [self anyBitOfMagnitudeFrom: 1 to: shift])
ifTrue: [mantissa := mantissa + 1]]
ifFalse:
[mantissa := self.
shift := 0].

+ 	"Combine two small integers (SmallInteger maxVale highBit = 30 bits) asFloat with a single inexact round off"
+ 	^(((mantissa bitShiftMagnitude: -30) asFloat timesTwoPower: 30)
+ 		+ (mantissa bitAnd: 16r3FFFFFFF "SmallInteger maxVal"))
+ 			timesTwoPower: shift!
- 	"Now that mantissa has at most 1 excess bit of precision, let floating point operations perform the final rounding."
- 	sum := 0.0.
- 	1 to: mantissa digitLength do:
- 		[:byteIndex |
- 		sum := sum + ((mantissa digitAt: byteIndex) asFloat timesTwoPower: shift).
- 		shift := shift + 8].
- 	^sum!

```