[squeak-dev] The Trunk: Kernel-nice.627.mcz
commits at source.squeak.org
commits at source.squeak.org
Sun Sep 25 10:56:41 UTC 2011
Nicolas Cellier uploaded a new version of Kernel to project The Trunk:
http://source.squeak.org/trunk/Kernel-nice.627.mcz
==================== Summary ====================
Name: Kernel-nice.627
Author: nice
Time: 25 September 2011, 12:55:51.623 pm
UUID: c09ead19-3aa6-482b-b2cc-f6549bc67eb6
Ancestors: Kernel-ul.626
Improve Fraction and Integer asFloat by:
- removing unreachable branch
- removing un-needed arithmetic
- renaming temps
- using Float precision explicitly rather than hardcoded magical numbers
- clarifying comments
The resulting code shall be clearer and a bit faster than previously.
=============== Diff against Kernel-ul.626 ===============
Item was changed:
----- Method: Fraction>>asFloat (in category 'converting') -----
asFloat
"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 |
- This implementation will answer the closest floating point number to
- the receiver.
- It uses the IEEE 754 round to nearest even mode
- (can happen in case denominator is a power of two)"
-
- | a b q r exponent floatExponent n ha hb hq q1 |
a := numerator abs.
+ b := denominator. "denominator is always positive"
- b := denominator abs.
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
- then fastest thing to do is to use hardwired float division"
- (ha < 54 and: [hb < 54]) ifTrue: [^numerator asFloat / denominator asFloat].
-
- "Try and obtain a mantissa with 54 bits.
- First guess is rough, we might get one more bit or one less"
- exponent := ha - hb - 54.
- exponent > 0
ifTrue: [b := b bitShift: exponent]
ifFalse: [a := a bitShift: exponent negated].
+ mantissa := a quo: b.
+ hasTruncatedBits := a > (mantissa * b).
+ hm := mantissa highBit.
- q := a quo: b.
- r := a - (q * b).
- hq := q 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
+ ifTrue:
+ [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].
+
- "check for gradual underflow, in which case we should use less bits"
- floatExponent := exponent + hq - 1.
- n := floatExponent > -1023
- ifTrue: [54]
- ifFalse: [54 + floatExponent + 1022].
-
- hq > n
- ifTrue: [exponent := exponent + hq - n.
- r := (q bitAnd: (1 bitShift: hq - n) - 1) * b + r.
- q := q bitShift: n - hq].
- hq < n
- ifTrue: [exponent := exponent + hq - n.
- q1 := (r bitShift: n - hq) quo: b.
- q := (q bitShift: n - hq) bitAnd: q1.
- r := (r bitShift: n - hq) - (q1 * b)].
-
- "check if we should round upward.
- The case of exact half (q bitAnd: 1) isZero not & (r isZero)
- will be handled by Integer>>asFloat"
- ((q bitAnd: 1) isZero or: [r isZero])
- ifFalse: [q := q + 1].
-
^ (self positive
+ ifTrue: [mantissa asFloat]
+ ifFalse: [mantissa asFloat negated])
- ifTrue: [q asFloat]
- ifFalse: [q = 0
- ifTrue: [Float negativeZero]
- ifFalse: [q asFloat negated]])
timesTwoPower: exponent!
Item was changed:
----- Method: Integer>>asFloat (in category 'converting') -----
asFloat
+ "Answer a Float that best approximates the value of the receiver."
- "Answer a Float that represents the value of the receiver.
- Optimized to process only the significant digits of a LargeInteger.
- SqR: 11/30/1998 21:1
+ self subclassResponsibility!
- This algorithm does honour IEEE 754 round to nearest even mode.
- Numbers are first rounded on nearest integer on 53 bits.
- In case of exact half difference between two consecutive integers (2r0.1),
- there are two possible choices (two integers are as near, 0 and 1)
- In this case, the nearest even integer is chosen.
- examples (with less than 53bits for clarity)
- 2r0.00001 is rounded to 2r0
- 2r1.00001 is rounded to 2.1
- 2r0.1 is rounded to 2r0 (nearest event)
- 2r1.1 is rounded to 2.10 (neraest even)
- 2r0.10001 is rounded to 2r1
- 2r1.10001 is rounded to 2.10"
-
- | abs shift sum delta mask trailingBits carry |
- self isZero
- ifTrue: [^ 0.0].
- abs := self abs.
-
- "Assume Float is a double precision IEEE 754 number with 53bits mantissa.
- We should better use some Float class message for that (Float precision)..."
- delta := abs highBit - 53.
- delta > 0
- ifTrue: [mask := (1 bitShift: delta) - 1.
- trailingBits := abs bitAnd: mask.
- "inexact := trailingBits isZero not."
- carry := trailingBits bitShift: 1 - delta.
- abs := abs bitShift: delta negated.
- shift := delta.
- (carry isZero
- or: [(trailingBits bitAnd: (mask bitShift: -1)) isZero
- and: [abs even]])
- ifFalse: [abs := abs + 1]]
- ifFalse: [shift := 0].
-
- "now, abs has no more than 53 bits, we can do exact floating point arithmetic"
- sum := 0.0.
- 1 to: abs size do:
- [:byteIndex |
- sum := ((abs digitAt: byteIndex) asFloat timesTwoPower: shift) + sum.
- shift := shift + 8].
- ^ self positive
- ifTrue: [sum]
- ifFalse: [sum negated]!
Item was added:
+ ----- Method: LargeNegativeInteger>>asFloat (in category 'converting') -----
+ asFloat
+ ^self negated asFloat negated!
Item was added:
+ ----- Method: LargePositiveInteger>>asFloat (in category 'converting') -----
+ asFloat
+ "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."
+
+ "Algorihm details:
+ 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 sum excess |
+
+ "Check how many bits excess the maximum precision of a Float mantissa."
+ excess := self highBitOfMagnitude - Float precision.
+ excess > 1
+ ifTrue:
+ ["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]]
+ ifFalse:
+ [mantissa := self.
+ shift := 0].
+
+ "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!
More information about the Squeak-dev
mailing list
|