softfloat.c
来自「基于组件方式开发操作系统的OSKIT源代码」· C语言 代码 · 共 1,910 行 · 第 1/5 页
C
1,910 行
z.high = ( zSign<<31 ) + ( zExp<<20 ) + zSig0; return z;}/*-------------------------------------------------------------------------------Takes an abstract floating-point value having sign `zSign', exponent `zExp',and extended significand formed by the concatenation of `zSig0', `zSig1',and `zSig2', and returns the proper double-precision floating-point valuecorresponding to the abstract input. Ordinarily, the abstract value issimply rounded and packed into the double-precision format, with the inexactexception raised if the abstract input cannot be represented exactly. Ifthe abstract value is too large, however, the overflow and inexactexceptions are raised and an infinity or maximal finite value is returned.If the abstract value is too small, the input value is rounded to asubnormal number, and the underflow and inexact exceptions are raised if theabstract input cannot be represented exactly as a subnormal double-precisionfloating-point number. The input significand must be normalized or smaller. If the inputsignificand is not normalized, `zExp' must be 0; in that case, the resultreturned is a subnormal number, and it must not require rounding. In theusual case that the input significand is normalized, `zExp' must be 1 lessthan the ``true'' floating-point exponent. The handling of underflow andoverflow follows the IEC/IEEE Standard for Binary Floating-point Arithmetic.-------------------------------------------------------------------------------*/static float64 roundAndPackFloat64( flag zSign, int16 zExp, bits32 zSig0, bits32 zSig1, bits32 zSig2 ){ uint8 roundingMode; flag roundNearestEven, increment; flag isTiny; roundingMode = float_rounding_mode; roundNearestEven = roundingMode == float_round_nearest_even; increment = ( (sbits32) zSig2 ) < 0; if ( ! roundNearestEven ) { if ( roundingMode == float_round_to_zero ) { increment = 0; } else { if ( zSign ) { increment = ( roundingMode == float_round_down ) && zSig2; } else { increment = ( roundingMode == float_round_up ) && zSig2; } } } if ( 0x7FE - 1 <= ( (bits16) zExp ) ) { if ( ( 0x7FE - 1 < zExp ) || ( ( zExp == 0x7FE - 1 ) && eq64( 0x001FFFFF, 0xFFFFFFFF, zSig0, zSig1 ) && increment ) ) { float_raise( float_flag_overflow | float_flag_inexact ); if ( ( roundingMode == float_round_to_zero ) || ( zSign && ( roundingMode == float_round_up ) ) || ( ! zSign && ( roundingMode == float_round_down ) ) ) { return packFloat64( zSign, 0x7FE, 0x000FFFFF, 0xFFFFFFFF ); } return packFloat64( zSign, 0x7FF, 0, 0 ); } if ( zExp < 0 ) { isTiny = ( float_detect_tininess == float_tininess_before_rounding ) || ( zExp < -1 ) || ! increment || lt64( zSig0, zSig1, 0x001FFFFF, 0xFFFFFFFF ); shiftDown64ExtraJamming( zSig0, zSig1, zSig2, - zExp, &zSig0, &zSig1, &zSig2 ); zExp = 0; if ( isTiny && zSig2 ) float_raise( float_flag_underflow ); if ( roundNearestEven ) { increment = ( (sbits32) zSig2 ) < 0; } else { if ( zSign ) { increment = ( roundingMode == float_round_down ) && zSig2; } else { increment = ( roundingMode == float_round_up ) && zSig2; } } } } if ( zSig2 ) float_exception_flags |= float_flag_inexact; if ( increment ) { add64( zSig0, zSig1, 0, 1, &zSig0, &zSig1 ); zSig1 &= ~ ( ( zSig2 + zSig2 == 0 ) & roundNearestEven ); } if ( ( zSig0 | zSig1 ) == 0 ) zExp = 0; return packFloat64( zSign, zExp, zSig0, zSig1 );}/*-------------------------------------------------------------------------------Takes an abstract floating-point value having sign `zSign', exponent `zExp',and significand formed by the concatenation of `zSig0' and `zSig1', andreturns the proper double-precision floating-point value corresponding tothe abstract input. This routine is just like `roundAndPackFloat64' exceptthat the input significand has fewer bits and does not have to be normalizedin any way. In all cases, `zExp' must be 1 less than the ``true'' floating-point exponent.-------------------------------------------------------------------------------*/static float64 normalizeRoundAndPackFloat64( flag zSign, int16 zExp, bits32 zSig0, bits32 zSig1 ){ int8 shiftCount; bits32 zSig2; if ( zSig0 == 0 ) { zSig0 = zSig1; zSig1 = 0; zExp -= 32; } shiftCount = countLeadingZeros( zSig0 ) - 11; if ( 0 <= shiftCount ) { zSig2 = 0; shortShiftUp64( zSig0, zSig1, shiftCount, &zSig0, &zSig1 ); } else { shiftDown64ExtraJamming( zSig0, zSig1, 0, - shiftCount, &zSig0, &zSig1, &zSig2 ); } zExp -= shiftCount; return roundAndPackFloat64( zSign, zExp, zSig0, zSig1, zSig2 );}/*-------------------------------------------------------------------------------Returns the result of converting the 32-bit two's complement integer `a' tothe single-precision floating-point format. The conversion is performedaccording to the IEC/IEEE Standard for Binary Floating-point Arithmetic.-------------------------------------------------------------------------------*/float32 int32_to_float32( int32 a ){ flag zSign; if ( a == 0 ) return 0; if ( a == -0x80000000 ) return packFloat32( 1, 0x9E, 0 ); zSign = ( a < 0 ); return normalizeRoundAndPackFloat32( zSign, 0x9C, zSign ? - a : a );}/*-------------------------------------------------------------------------------Returns the result of converting the 32-bit two's complement integer `a' tothe double-precision floating-point format. The conversion is performedaccording to the IEC/IEEE Standard for Binary Floating-point Arithmetic.-------------------------------------------------------------------------------*/float64 int32_to_float64( int32 a ){ flag zSign; bits32 absA; int8 shiftCount; bits32 zSig0, zSig1; if ( a == 0 ) return packFloat64( 0, 0, 0, 0 ); zSign = ( a < 0 ); absA = zSign ? - a : a; shiftCount = countLeadingZeros( absA ) - 11; if ( 0 <= shiftCount ) { zSig0 = absA<<shiftCount; zSig1 = 0; } else { shiftDown64( absA, 0, - shiftCount, &zSig0, &zSig1 ); } return packFloat64( zSign, 0x412 - shiftCount, zSig0, zSig1 );}/*-------------------------------------------------------------------------------Returns the result of converting the single-precision floating-point value`a' to the 32-bit two's complement integer format. The conversion isperformed according to the IEC/IEEE Standard for Binary Floating-pointArithmetic---which means in particular that the conversion is roundedaccording to the current rounding mode. If `a' is a NaN, the largestpositive integer is returned. If the conversion overflows, the largestinteger with the same sign as `a' is returned.-------------------------------------------------------------------------------*/int32 float32_to_int32( float32 a ){ flag aSign; int16 aExp, shiftCount; bits32 aSig; bits32 zExtra; int32 z; uint8 roundingMode; aSig = extractFloat32Frac( a ); aExp = extractFloat32Exp( a ); aSign = extractFloat32Sign( a ); shiftCount = aExp - 0x96; if ( 0 <= shiftCount ) { if ( 0x9E <= aExp ) { if ( a == 0xCF000000 ) return -0x80000000; float_raise( float_flag_invalid ); if ( ! aSign || ( ( aExp == 0xFF ) && aSig ) ) return 0x7FFFFFFF; return -0x80000000; } z = ( aSig | 0x800000 )<<shiftCount; if ( aSign ) z = - z; } else { if ( aExp < 0x7E ) { zExtra = aExp | aSig; z = 0; } else { aSig |= 0x800000; zExtra = aSig<<( shiftCount & 31 ); z = aSig>>( - shiftCount ); } if ( zExtra ) float_exception_flags |= float_flag_inexact; roundingMode = float_rounding_mode; if ( roundingMode == float_round_nearest_even ) { if ( ( (sbits32) zExtra ) < 0 ) { ++z; if ( ( zExtra + zExtra ) == 0 ) z &= ~1; } if ( aSign ) z = - z; } else { zExtra = zExtra != 0; if ( aSign ) { z += ( roundingMode == float_round_down ) & zExtra; z = - z; } else { z += ( roundingMode == float_round_up ) & zExtra; } } } return z;}/*-------------------------------------------------------------------------------Returns the result of converting the single-precision floating-point value`a' to the 32-bit two's complement integer format. The conversion isperformed according to the IEC/IEEE Standard for Binary Floating-pointArithmetic, except that the conversion is always rounded toward zero. If`a' is a NaN, the largest positive integer is returned. If the conversionoverflows, the largest integer with the same sign as `a' is returned.-------------------------------------------------------------------------------*/int32 float32_to_int32_round_to_zero( float32 a ){ flag aSign; int16 aExp, shiftCount; bits32 aSig; int32 z; aSig = extractFloat32Frac( a ); aExp = extractFloat32Exp( a ); aSign = extractFloat32Sign( a ); shiftCount = aExp - 0x9E; if ( 0 <= shiftCount ) { if ( a == 0xCF000000 ) return -0x80000000; float_raise( float_flag_invalid ); if ( ! aSign || ( ( aExp == 0xFF ) && aSig ) ) return 0x7FFFFFFF; return -0x80000000; } else if ( aExp <= 0x7E ) { if ( aExp | aSig ) float_exception_flags |= float_flag_inexact; return 0; } aSig = ( aSig | 0x800000 )<<8; z = aSig>>( - shiftCount ); if ( aSig<<( shiftCount & 31 ) ) { float_exception_flags |= float_flag_inexact; } if ( aSign ) z = - z; return z;}/*-------------------------------------------------------------------------------Returns the result of converting the single-precision floating-point value`a' to the double-precision floating-point format. The conversion isperformed according to the IEC/IEEE Standard for Binary Floating-pointArithmetic.-------------------------------------------------------------------------------*/float64 float32_to_float64( float32 a ){ flag aSign; int16 aExp; bits32 aSig; bits32 zSig0, zSig1; aSig = extractFloat32Frac( a ); aExp = extractFloat32Exp( a ); aSign = extractFloat32Sign( a ); if ( aExp == 0xFF ) { if ( aSig ) return float32ToFloat64NaN( a ); return packFloat64( aSign, 0x7FF, 0, 0 ); } if ( aExp == 0 ) { if ( aSig == 0 ) return packFloat64( aSign, 0, 0, 0 ); normalizeFloat32Subnormal( aSig, &aExp, &aSig ); --aExp; } shiftDown64( aSig, 0, 3, &zSig0, &zSig1 ); return packFloat64( aSign, aExp - 0x7F + 0x3FF, zSig0, zSig1 );}/*-------------------------------------------------------------------------------Returns the result of converting the double-precision floating-point value`a' to the 32-bit two's complement integer format. The conversion isperformed according to the IEC/IEEE Standard for Binary Floating-pointArithmetic---which means in particular that the conversion is roundedaccording to the current rounding mode. If `a' is a NaN, the largestpositive integer is returned. If the conversion overflows, the largestinteger with the same sign as `a' is returned.-------------------------------------------------------------------------------*/int32 float64_to_int32( float64 a ){ flag aSign; int16 aExp, shiftCount; bits32 aSig0, aSig1; bits32 absZ, zExtra; int32 z; uint8 roundingMode; aSig1 = extractFloat64Frac1( a ); aSig0 = extractFloat64Frac0( a ); aExp = extractFloat64Exp( a ); aSign = extractFloat64Sign( a ); shiftCount = aExp - 0x413; if ( 0 <= shiftCount ) { if ( 11 < shiftCount ) { if ( ( aExp == 0x7FF ) && ( aSig0 | aSig1 ) ) aSign = 0; absZ = 0xC0000000; } else { shortShiftUp64( aSig0 | 0x100000, aSig1, shiftCount, &absZ, &zExtra ); if ( 0xC0000000 < absZ ) absZ = 0xC0000000; } } else { aSig1 = aSig1 != 0; if ( aExp < 0x3FE ) { zExtra = aExp | aSig0 | aSig1; absZ = 0; } else { aSig0 |= 0x100000; zExtra = ( aSig0<<( shiftCount & 31 ) ) | aSig1; absZ = aSig0>>( - shiftCount ); } } roundingMode = float_rounding_mode; if ( roundingMode == float_round_nearest_even ) { if ( ( (sbits32) zExtra ) < 0 ) { ++absZ; if ( ( zExtra + zExtra ) == 0 ) absZ &= ~1; } z = aSign ? - absZ : absZ; } else {
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?