📄 softfloat.c
字号:
return a>>63;}/*----------------------------------------------------------------------------| Normalizes the subnormal double-precision floating-point value represented| by the denormalized significand `aSig'. The normalized exponent and| significand are stored at the locations pointed to by `zExpPtr' and| `zSigPtr', respectively.*----------------------------------------------------------------------------*/static void normalizeFloat64Subnormal( bits64 aSig, int16 *zExpPtr, bits64 *zSigPtr ){ int8 shiftCount; shiftCount = countLeadingZeros64( aSig ) - 11; *zSigPtr = aSig<<shiftCount; *zExpPtr = 1 - shiftCount;}/*----------------------------------------------------------------------------| Packs the sign `zSign', exponent `zExp', and significand `zSig' into a| double-precision floating-point value, returning the result. After being| shifted into the proper positions, the three fields are simply added| together to form the result. This means that any integer portion of `zSig'| will be added into the exponent. Since a properly normalized significand| will have an integer portion equal to 1, the `zExp' input should be 1 less| than the desired result exponent whenever `zSig' is a complete, normalized| significand.*----------------------------------------------------------------------------*/INLINE float64 packFloat64( flag zSign, int16 zExp, bits64 zSig ){ return ( ( (bits64) zSign )<<63 ) + ( ( (bits64) zExp )<<52 ) + zSig;}/*----------------------------------------------------------------------------| Takes an abstract floating-point value having sign `zSign', exponent `zExp',| and significand `zSig', and returns the proper double-precision floating-| point value corresponding to the abstract input. Ordinarily, the abstract| value is simply rounded and packed into the double-precision format, with| the inexact exception raised if the abstract input cannot be represented| exactly. However, if the abstract value is too large, the overflow and| inexact exceptions are raised and an infinity or maximal finite value is| returned. If the abstract value is too small, the input value is rounded| to a subnormal number, and the underflow and inexact exceptions are raised| if the abstract input cannot be represented exactly as a subnormal double-| precision floating-point number.| The input significand `zSig' has its binary point between bits 62| and 61, which is 10 bits to the left of the usual location. This shifted| significand must be normalized or smaller. If `zSig' is not normalized,| `zExp' must be 0; in that case, the result returned is a subnormal number,| and it must not require rounding. In the usual case that `zSig' is| normalized, `zExp' must be 1 less than the ``true'' floating-point exponent.| The handling of underflow and overflow follows the IEC/IEEE Standard for| Binary Floating-Point Arithmetic.*----------------------------------------------------------------------------*/static float64 roundAndPackFloat64( flag zSign, int16 zExp, bits64 zSig STATUS_PARAM){ int8 roundingMode; flag roundNearestEven; int16 roundIncrement, roundBits; flag isTiny; roundingMode = STATUS(float_rounding_mode); roundNearestEven = ( roundingMode == float_round_nearest_even ); roundIncrement = 0x200; if ( ! roundNearestEven ) { if ( roundingMode == float_round_to_zero ) { roundIncrement = 0; } else { roundIncrement = 0x3FF; if ( zSign ) { if ( roundingMode == float_round_up ) roundIncrement = 0; } else { if ( roundingMode == float_round_down ) roundIncrement = 0; } } } roundBits = zSig & 0x3FF; if ( 0x7FD <= (bits16) zExp ) { if ( ( 0x7FD < zExp ) || ( ( zExp == 0x7FD ) && ( (sbits64) ( zSig + roundIncrement ) < 0 ) ) ) { float_raise( float_flag_overflow | float_flag_inexact STATUS_VAR); return packFloat64( zSign, 0x7FF, 0 ) - ( roundIncrement == 0 ); } if ( zExp < 0 ) { isTiny = ( STATUS(float_detect_tininess) == float_tininess_before_rounding ) || ( zExp < -1 ) || ( zSig + roundIncrement < LIT64( 0x8000000000000000 ) ); shift64RightJamming( zSig, - zExp, &zSig ); zExp = 0; roundBits = zSig & 0x3FF; if ( isTiny && roundBits ) float_raise( float_flag_underflow STATUS_VAR); } } if ( roundBits ) STATUS(float_exception_flags) |= float_flag_inexact; zSig = ( zSig + roundIncrement )>>10; zSig &= ~ ( ( ( roundBits ^ 0x200 ) == 0 ) & roundNearestEven ); if ( zSig == 0 ) zExp = 0; return packFloat64( zSign, zExp, zSig );}/*----------------------------------------------------------------------------| Takes an abstract floating-point value having sign `zSign', exponent `zExp',| and significand `zSig', and returns the proper double-precision floating-| point value corresponding to the abstract input. This routine is just like| `roundAndPackFloat64' except that `zSig' does not have to be normalized.| Bit 63 of `zSig' must be zero, and `zExp' must be 1 less than the ``true''| floating-point exponent.*----------------------------------------------------------------------------*/static float64 normalizeRoundAndPackFloat64( flag zSign, int16 zExp, bits64 zSig STATUS_PARAM){ int8 shiftCount; shiftCount = countLeadingZeros64( zSig ) - 1; return roundAndPackFloat64( zSign, zExp - shiftCount, zSig<<shiftCount STATUS_VAR);}#ifdef FLOATX80/*----------------------------------------------------------------------------| Returns the fraction bits of the extended double-precision floating-point| value `a'.*----------------------------------------------------------------------------*/INLINE bits64 extractFloatx80Frac( floatx80 a ){ return a.low;}/*----------------------------------------------------------------------------| Returns the exponent bits of the extended double-precision floating-point| value `a'.*----------------------------------------------------------------------------*/INLINE int32 extractFloatx80Exp( floatx80 a ){ return a.high & 0x7FFF;}/*----------------------------------------------------------------------------| Returns the sign bit of the extended double-precision floating-point value| `a'.*----------------------------------------------------------------------------*/INLINE flag extractFloatx80Sign( floatx80 a ){ return a.high>>15;}/*----------------------------------------------------------------------------| Normalizes the subnormal extended double-precision floating-point value| represented by the denormalized significand `aSig'. The normalized exponent| and significand are stored at the locations pointed to by `zExpPtr' and| `zSigPtr', respectively.*----------------------------------------------------------------------------*/static void normalizeFloatx80Subnormal( bits64 aSig, int32 *zExpPtr, bits64 *zSigPtr ){ int8 shiftCount; shiftCount = countLeadingZeros64( aSig ); *zSigPtr = aSig<<shiftCount; *zExpPtr = 1 - shiftCount;}/*----------------------------------------------------------------------------| Packs the sign `zSign', exponent `zExp', and significand `zSig' into an| extended double-precision floating-point value, returning the result.*----------------------------------------------------------------------------*/INLINE floatx80 packFloatx80( flag zSign, int32 zExp, bits64 zSig ){ floatx80 z; z.low = zSig; z.high = ( ( (bits16) zSign )<<15 ) + zExp; return z;}/*----------------------------------------------------------------------------| Takes an abstract floating-point value having sign `zSign', exponent `zExp',| and extended significand formed by the concatenation of `zSig0' and `zSig1',| and returns the proper extended double-precision floating-point value| corresponding to the abstract input. Ordinarily, the abstract value is| rounded and packed into the extended double-precision format, with the| inexact exception raised if the abstract input cannot be represented| exactly. However, if the abstract value is too large, the overflow and| inexact exceptions are raised and an infinity or maximal finite value is| returned. If the abstract value is too small, the input value is rounded to| a subnormal number, and the underflow and inexact exceptions are raised if| the abstract input cannot be represented exactly as a subnormal extended| double-precision floating-point number.| If `roundingPrecision' is 32 or 64, the result is rounded to the same| number of bits as single or double precision, respectively. Otherwise, the| result is rounded to the full precision of the extended double-precision| format.| The input significand must be normalized or smaller. If the input| significand is not normalized, `zExp' must be 0; in that case, the result| returned is a subnormal number, and it must not require rounding. The| handling of underflow and overflow follows the IEC/IEEE Standard for Binary| Floating-Point Arithmetic.*----------------------------------------------------------------------------*/static floatx80 roundAndPackFloatx80( int8 roundingPrecision, flag zSign, int32 zExp, bits64 zSig0, bits64 zSig1 STATUS_PARAM){ int8 roundingMode; flag roundNearestEven, increment, isTiny; int64 roundIncrement, roundMask, roundBits; roundingMode = STATUS(float_rounding_mode); roundNearestEven = ( roundingMode == float_round_nearest_even ); if ( roundingPrecision == 80 ) goto precision80; if ( roundingPrecision == 64 ) { roundIncrement = LIT64( 0x0000000000000400 ); roundMask = LIT64( 0x00000000000007FF ); } else if ( roundingPrecision == 32 ) { roundIncrement = LIT64( 0x0000008000000000 ); roundMask = LIT64( 0x000000FFFFFFFFFF ); } else { goto precision80; } zSig0 |= ( zSig1 != 0 ); if ( ! roundNearestEven ) { if ( roundingMode == float_round_to_zero ) { roundIncrement = 0; } else { roundIncrement = roundMask; if ( zSign ) { if ( roundingMode == float_round_up ) roundIncrement = 0; } else { if ( roundingMode == float_round_down ) roundIncrement = 0; } } } roundBits = zSig0 & roundMask; if ( 0x7FFD <= (bits32) ( zExp - 1 ) ) { if ( ( 0x7FFE < zExp ) || ( ( zExp == 0x7FFE ) && ( zSig0 + roundIncrement < zSig0 ) ) ) { goto overflow; } if ( zExp <= 0 ) { isTiny = ( STATUS(float_detect_tininess) == float_tininess_before_rounding ) || ( zExp < 0 ) || ( zSig0 <= zSig0 + roundIncrement ); shift64RightJamming( zSig0, 1 - zExp, &zSig0 ); zExp = 0; roundBits = zSig0 & roundMask; if ( isTiny && roundBits ) float_raise( float_flag_underflow STATUS_VAR); if ( roundBits ) STATUS(float_exception_flags) |= float_flag_inexact; zSig0 += roundIncrement; if ( (sbits64) zSig0 < 0 ) zExp = 1; roundIncrement = roundMask + 1; if ( roundNearestEven && ( roundBits<<1 == roundIncrement ) ) { roundMask |= roundIncrement; } zSig0 &= ~ roundMask; return packFloatx80( zSign, zExp, zSig0 ); } } if ( roundBits ) STATUS(float_exception_flags) |= float_flag_inexact; zSig0 += roundIncrement; if ( zSig0 < roundIncrement ) { ++zExp; zSig0 = LIT64( 0x8000000000000000 ); } roundIncrement = roundMask + 1; if ( roundNearestEven && ( roundBits<<1 == roundIncrement ) ) { roundMask |= roundIncrement; } zSig0 &= ~ roundMask; if ( zSig0 == 0 ) zExp = 0; return packFloatx80( zSign, zExp, zSig0 ); precision80: increment = ( (sbits64) zSig1 < 0 ); if ( ! roundNearestEven ) { if ( roundingMode == float_round_to_zero ) { increment = 0; } else { if ( zSign ) { increment = ( roundingMode == float_round_down ) && zSig1; } else { increment = ( roundingMode == float_round_up ) && zSig1; } } } if ( 0x7FFD <= (bits32) ( zExp - 1 ) ) { if ( ( 0x7FFE < zExp ) || ( ( zExp == 0x7FFE ) && ( zSig0 == LIT64( 0xFFFFFFFFFFFFFFFF ) ) && increment ) ) { roundMask = 0; overflow: float_raise( float_flag_overflow | float_flag_inexact STATUS_VAR); if ( ( roundingMode == float_round_to_zero ) || ( zSign && ( roundingMode == float_round_up ) ) || ( ! zSign && ( roundingMode == float_round_down ) ) ) { return packFloatx80( zSign, 0x7FFE, ~ roundMask ); } return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) ); } if ( zExp <= 0 ) { isTiny = ( STATUS(float_detect_tininess) == float_tininess_before_rounding ) || ( zExp < 0 ) || ! increment || ( zSig0 < LIT64( 0xFFFFFFFFFFFFFFFF ) ); shift64ExtraRightJamming( zSig0, zSig1, 1 - zExp, &zSig0, &zSig1 ); zExp = 0; if ( isTiny && zSig1 ) float_raise( float_flag_underflow STATUS_VAR); if ( zSig1 ) STATUS(float_exception_flags) |= float_flag_inexact; if ( roundNearestEven ) { increment = ( (sbits64) zSig1 < 0 ); } else { if ( zSign ) { increment = ( roundingMode == float_round_down ) && zSig1; } else { increment = ( roundingMode == float_round_up ) && zSig1; } } if ( increment ) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -