Nicolas Cellier uploaded a new version of Kernel to project The Trunk:
http://source.squeak.org/trunk/Kernel-nice.1262.mcz ==================== Summary ==================== Name: Kernel-nice.1262 Author: nice Time: 29 August 2019, 12:28:31.665288 pm UUID: 3e167d35-e96e-7649-8324-28d9cb255a65 Ancestors: Kernel-nice.1261 Accelerate LargeInteger asFloat in 64bits images. =============== Diff against Kernel-nice.1261 =============== Item was added: + ----- Method: Integer>>digitsAsFloat (in category 'private') ----- + digitsAsFloat + "private - naive conversion method. + This method should be used if and only if + Float precision + 8 >= self highBit. + This way, all floating point operations will be exact, but eventually the + last one, giving a guaranty that result will be the nearest Float." + | result n | + result := (self digitAt: (n := self digitLength)) asFloat. + [(n := n - 1) > 0] + whileTrue: [result := 256.0 * result + (self digitAt: n) asFloat]. + ^ result! Item was changed: ----- 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: 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. Note 2: the floating point hardware is presumed configured in default rounding mode." + | mantissa shift excess | - | mantissa shift excess result n | "Check how many bits excess the maximum precision of a Float mantissa." excess := self highBitOfMagnitude - Float precision. excess > 7 ifTrue: ["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]) ifTrue: [mantissa := mantissa + 1]] ifFalse: [mantissa := self. shift := 0]. + "We can use naive digit by digit conversion because there will be a single inexact round off at last iteration. + But the nice thing is that Float precision + 7 excess bits = 60 which fit in a SmallInteger in Spur64. + So the best to do is to delegate this final operation" + ^mantissa digitsAsFloat timesTwoPower: shift.! - "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.! Item was added: + ----- Method: SmallInteger>>digitsAsFloat (in category 'private') ----- + digitsAsFloat + "private - let the primitive take care to answer the nearest float" + <primitive: 40> + ^super digitsAsFloat! |
Le jeu. 29 août 2019 à 12:28, <[hidden email]> a écrit : Nicolas Cellier uploaded a new version of Kernel to project The Trunk: Some additional notes: I've also tried a simple split of the 53 (Float precision) + 7 (excess bits) significand into two 30 bits SmallInteger: digitsAsFloat2 ^(self bitShift: -30) asFloat * 1073741824.0 + (self bitAnd: 16r3FFFFFFF) asFloat Unfortunately, this is slower than looping on the byte-digits like proposed above: self assert: 923456789012345678 highBit = 60. [923456789012345678 digitsAsFloat] bench. '7,290,000 per second. 137 nanoseconds per run.' [923456789012345678 digitsAsFloat2] bench. '3,430,000 per second. 291 nanoseconds per run.' I did not use latest VM when trying this (Macos-metal pb https://github.com/OpenSmalltalk/opensmalltalk-vm/issues/397) Item was changed: |
Free forum by Nabble | Edit this page |