[Pkg] The Trunk: Kernel-nice.723.mcz
commits at source.squeak.org
commits at source.squeak.org
Tue Jan 1 14:57:39 UTC 2013
Nicolas Cellier uploaded a new version of Kernel to project The Trunk:
==================== Summary ====================
Time: 1 January 2013, 3:56:14.701 pm
Speed-up LargeInteger asFloat when highBit > Float precision.
=============== Diff against Kernel-nice.720 ===============
Item was changed:
----- Method: Fraction>>asFloat (in category 'converting') -----
"Answer a Float that closely approximates the value of the receiver.
This implementation will answer the closest floating point number to the receiver.
In case of a tie, it will use the IEEE 754 round to nearest even mode.
In case of overflow, it will answer +/- Float infinity."
| a b mantissa exponent hasTruncatedBits lostBit n ha hb hm |
a := numerator abs.
b := denominator. "denominator is always positive"
+ ha := a highBitOfMagnitude.
+ hb := b highBitOfMagnitude.
- ha := a highBit.
- hb := b highBit.
"Number of bits to keep in mantissa plus one to handle rounding."
n := 1 + Float precision.
"If both numerator and denominator are represented exactly in floating point number,
then fastest thing to do is to use hardwired float division."
(ha < n and: [hb < n]) ifTrue: [^numerator asFloat / denominator asFloat].
"Shift the fraction by a power of two exponent so as to obtain a mantissa with n bits.
First guess is rough, the mantissa might have n+1 bits."
exponent := ha - hb - n.
exponent >= 0
ifTrue: [b := b bitShift: exponent]
ifFalse: [a := a bitShift: exponent negated].
mantissa := a quo: b.
hasTruncatedBits := a > (mantissa * b).
hm := mantissa highBit.
"Check for gradual underflow, in which case the mantissa will loose bits.
Keep at least one bit to let underflow preserve the sign of zero."
lostBit := Float emin - (exponent + hm - 1).
lostBit > 0 ifTrue: [n := n - lostBit max: 1].
"Remove excess bits in the mantissa."
hm > n
[exponent := exponent + hm - n.
hasTruncatedBits := hasTruncatedBits or: [mantissa anyBitOfMagnitudeFrom: 1 to: hm - n].
mantissa := mantissa bitShift: n - hm].
"Check if mantissa must be rounded upward.
The case of tie (mantissa odd & hasTruncatedBits not)
will be handled by Integer>>asFloat."
(hasTruncatedBits and: [mantissa odd])
ifTrue: [mantissa := mantissa + 1].
^ (self positive
ifTrue: [mantissa asFloat]
ifFalse: [mantissa asFloat negated])
Item was changed:
----- Method: LargeNegativeInteger>>asFloat (in category 'converting') -----
+ ^super asFloat negated!
- ^self negated asFloat negated!
Item was changed:
----- Method: LargePositiveInteger>>asFloat (in category 'converting') -----
"Answer a Float that best approximates the value of the receiver.
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."
+ The floating point hardware can perform the rounding correctly with several excess bits as long as there is a single inexact operation.
+ This can be obtained by splitting the mantissa plus excess bits in two part with less bits than Float precision.
+ Note 1: the inexact flag in floating point hardware must not be trusted because in some cases the operations would be exact but would not take into account some bits that were truncated before the Floating point operations.
- 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 result n |
- | 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
+ ["Remove the excess bits but seven."
+ mantissa := self bitShiftMagnitude: 7 - excess.
+ shift := excess - 7.
+ "An even mantissa with a single excess bit immediately following would be truncated.
+ But this would not be correct if above shift has truncated some extra bits.
+ Check this case, and round excess bits upper manually."
+ ((mantissa digitAt: 1) = 2r01000000 and: [self anyBitOfMagnitudeFrom: 1 to: shift])
- ["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 bitAnd: 2r11) = 2r01 and: [self anyBitOfMagnitudeFrom: 1 to: shift])
ifTrue: [mantissa := mantissa + 1]]
[mantissa := self.
shift := 0].
+ "There will be a single inexact round off at last iteration"
+ result := (mantissa digitAt: (n := mantissa digitLength)) asFloat.
+ [(n := n - 1) > 0] whileTrue: [
+ result := 256.0 * result + (mantissa digitAt: n) asFloat].
+ ^result 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].
More information about the Packages