softfloat.c
来自「基于组件方式开发操作系统的OSKIT源代码」· C语言 代码 · 共 1,910 行 · 第 1/5 页
C
1,910 行
/* $NetBSD: softfloat.c,v 1.3 1998/01/06 00:06:12 perry Exp $ *//*===============================================================================This C source file is part of the SoftFloat IEC/IEEE Floating-pointArithmetic Package, Release 1a.Written by John R. Hauser. This work was made possible by the InternationalComputer Science Institute, located at Suite 600, 1947 Center Street,Berkeley, California 94704. Funding was provided in part by the NationalScience Foundation under grant MIP-9311980. The original version ofthis code was written as part of a project to build a fixed-point vectorprocessor in collaboration with the University of California at Berkeley,overseen by Profs. Nelson Morgan and John Wawrzynek. More informationis available through the web page `http://www.cs.berkeley.edu/~jhauser/softfloat.html'.THIS PACKAGE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort hasbeen made to avoid it, THIS PACKAGE MAY CONTAIN FAULTS THAT WILL AT TIMESRESULT IN INCORRECT BEHAVIOR. USE OF THIS PACKAGE IS RESTRICTED TO PERSONSAND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY AND ALLLOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE.Derivative works are acceptable, even for commercial purposes, so long as(1) they include prominent notice that the work is derivative, and (2) theyinclude prominent notice akin to these three paragraphs for those parts ofthis code that are retained.===============================================================================*/#include "environment.h"#include "softfloat.h"/*-------------------------------------------------------------------------------Floating-point rounding mode and exception flags.-------------------------------------------------------------------------------*/uint8 float_exception_flags = 0;uint8 float_rounding_mode = float_round_nearest_even;/*-------------------------------------------------------------------------------Functions and definitions to determine: (1) what (if anything) happens whenexceptions are raised, (2) how signaling NaNs are distinguished from quietNaNs, (3) the default generated quiet NaNs, and (4) how NaNs are propagatedfrom function inputs to output. These details are target-specific.-------------------------------------------------------------------------------*/#include "softfloat-specialize.h"/*-------------------------------------------------------------------------------Primitive arithmetic functions, including multi-word arithmetic, anddivision and square root approximations. (Can be specialized to target ifdesired.)-------------------------------------------------------------------------------*/#include "softfloat-macros.h"/* Local prototypes */INLINE bits32 extractFloat32Frac( float32 a );INLINE int16 extractFloat32Exp( float32 a );INLINE flag extractFloat32Sign( float32 a );INLINE flag bothZeroFloat32( float32 a, float32 b );INLINE float32 packFloat32( flag zSign, int16 zExp, bits32 zSig );INLINE bits32 extractFloat64Frac1( float64 a );INLINE bits32 extractFloat64Frac0( float64 a );INLINE int16 extractFloat64Exp( float64 a );INLINE flag extractFloat64Sign( float64 a );INLINE flag bothZeroFloat64( float64 a, float64 b );INLINE float64 packFloat64( flag zSign, int16 zExp, bits32 zSig0, bits32 zSig1 );/*-------------------------------------------------------------------------------Returns the fraction bits of the single-precision floating-point value `a'.-------------------------------------------------------------------------------*/INLINE bits32 extractFloat32Frac( float32 a ){ return a & 0x007FFFFF;}/*-------------------------------------------------------------------------------Returns the exponent bits of the single-precision floating-point value `a'.-------------------------------------------------------------------------------*/INLINE int16 extractFloat32Exp( float32 a ){ return ( a>>23 ) & 0xFF;}/*-------------------------------------------------------------------------------Returns the sign bit of the single-precision floating-point value `a'.-------------------------------------------------------------------------------*/INLINE flag extractFloat32Sign( float32 a ){ return a>>31;}/*-------------------------------------------------------------------------------Returns true if the single-precision floating-point values `a' and `b' areboth zero. Otherwise, returns false.-------------------------------------------------------------------------------*/INLINE flag bothZeroFloat32( float32 a, float32 b ){ return ( ( ( a | b )<<1 ) == 0 );}/*-------------------------------------------------------------------------------Normalizes the subnormal single-precision floating-point value representedby the denormalized significand `aSig'. The normalized exponent andsignificand are stored at the locations pointed to by `zExpPtr' and`zSigPtr', respectively.-------------------------------------------------------------------------------*/static void normalizeFloat32Subnormal( bits32 aSig, int16 *zExpPtr, bits32 *zSigPtr ){ int8 shiftCount; shiftCount = countLeadingZeros( aSig ) - 8; *zSigPtr = aSig<<shiftCount; *zExpPtr = 1 - shiftCount;}/*-------------------------------------------------------------------------------Packs the sign `zSign', exponent `zExp', and significand `zSig' into asingle-precision floating-point value, returning the result. After beingshifted into the proper positions, the three fields are simply addedtogether to form the result. This means that any integer portion of `zSig'will be added into the exponent. Since a properly normalized significandwill have an integer portion equal to 1, the `zExp' input should be 1 lessthan the desired result exponent whenever `zSig' is a complete, normalizedsignificand.-------------------------------------------------------------------------------*/INLINE float32 packFloat32( flag zSign, int16 zExp, bits32 zSig ){ return ( zSign<<31 ) + ( zExp<<23 ) + zSig;}/*-------------------------------------------------------------------------------Takes an abstract floating-point value having sign `zSign', exponent `zExp',and significand `zSig', and returns the proper single-precision floating-point value corresponding to the abstract input. Ordinarily, the abstractvalue is simply rounded and packed into the single-precision format, withthe inexact exception raised if the abstract input cannot be representedexactly. If the abstract value is too large, however, the overflow andinexact exceptions are raised and an infinity or maximal finite value isreturned. If the abstract value is too small, the input value is rounded toa subnormal number, and the underflow and inexact exceptions are raised ifthe abstract input cannot be represented exactly as a subnormal single-precision floating-point number. The input significand `zSig' has its binary point between bits 30and 29, which is 7 bits to the left of the usual location. This shiftedsignificand 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' isnormalized, `zExp' must be 1 less than the ``true'' floating-point exponent.The handling of underflow and overflow follows the IEC/IEEE Standard forBinary Floating-point Arithmetic.-------------------------------------------------------------------------------*/static float32 roundAndPackFloat32( flag zSign, int16 zExp, bits32 zSig ){ uint8 roundingMode; flag roundNearestEven; int8 roundIncrement, roundBits; flag isTiny; roundingMode = float_rounding_mode; roundNearestEven = roundingMode == float_round_nearest_even; roundIncrement = 0x40; if ( ! roundNearestEven ) { if ( roundingMode == float_round_to_zero ) { roundIncrement = 0; } else { roundIncrement = 0x7F; if ( zSign ) { if ( roundingMode == float_round_up ) roundIncrement = 0; } else { if ( roundingMode == float_round_down ) roundIncrement = 0; } } } roundBits = zSig & 0x7F; if ( 0xFE - 1 <= ( (bits16) zExp ) ) { if ( ( 0xFE - 1 < zExp ) || ( ( zExp == 0xFE - 1 ) && ( ( (sbits32) ( zSig + roundIncrement ) ) < 0 ) ) ) { float_raise( float_flag_overflow | float_flag_inexact ); return packFloat32( zSign, 0xFF, 0 ) - ( roundIncrement == 0 ); } if ( zExp < 0 ) { isTiny = ( float_detect_tininess == float_tininess_before_rounding ) || ( zExp < -1 ) || ( zSig + roundIncrement < 0x80000000 ); shiftDown32Jamming( zSig, - zExp, &zSig ); zExp = 0; roundBits = zSig & 0x7F; if ( isTiny && roundBits ) float_raise( float_flag_underflow ); } } if ( roundBits ) float_exception_flags |= float_flag_inexact; zSig = ( zSig + roundIncrement )>>7; zSig &= ~ ( ( ( roundBits ^ 0x40 ) == 0 ) & roundNearestEven ); if ( zSig == 0 ) zExp = 0; return packFloat32( zSign, zExp, zSig );}/*-------------------------------------------------------------------------------Takes an abstract floating-point value having sign `zSign', exponent `zExp',and significand `zSig', and returns the proper single-precision floating-point value corresponding to the abstract input. This routine is just like`roundAndPackFloat32' except that `zSig' does not have to be normalized inany way. In all cases, `zExp' must be 1 less than the ``true'' floating-point exponent.-------------------------------------------------------------------------------*/static float32 normalizeRoundAndPackFloat32( flag zSign, int16 zExp, bits32 zSig ){ int8 shiftCount; shiftCount = countLeadingZeros( zSig ) - 1; return roundAndPackFloat32( zSign, zExp - shiftCount, zSig<<shiftCount );}/*-------------------------------------------------------------------------------Returns the least-significant 32 fraction bits of the double-precisionfloating-point value `a'.-------------------------------------------------------------------------------*/INLINE bits32 extractFloat64Frac1( float64 a ){ return a.low;}/*-------------------------------------------------------------------------------Returns the most-significant 20 fraction bits of the double-precisionfloating-point value `a'.-------------------------------------------------------------------------------*/INLINE bits32 extractFloat64Frac0( float64 a ){ return a.high & 0x000FFFFF;}/*-------------------------------------------------------------------------------Returns the exponent bits of the double-precision floating-point value `a'.-------------------------------------------------------------------------------*/INLINE int16 extractFloat64Exp( float64 a ){ return ( a.high>>20 ) & 0x7FF;}/*-------------------------------------------------------------------------------Returns the sign bit of the double-precision floating-point value `a'.-------------------------------------------------------------------------------*/INLINE flag extractFloat64Sign( float64 a ){ return a.high>>31;}/*-------------------------------------------------------------------------------Returns true if the double-precision floating-point values `a' and `b' areboth zero. Otherwise, returns false.-------------------------------------------------------------------------------*/INLINE flag bothZeroFloat64( float64 a, float64 b ){ return ( ( ( a.high | b.high )<<1 ) | a.low | b.low ) == 0;}/*-------------------------------------------------------------------------------Normalizes the subnormal double-precision floating-point value representedby the denormalized significand formed by the concatenation of `aSig0' and`aSig1'. The normalized exponent is stored at the location pointed to by`zExpPtr'. The most significant 21 bits of the normalized significand arestored at the location pointed to by `zSig0Ptr', and the least significant32 bits of the normalized significand are stored at the location pointed toby `zSig1Ptr'.-------------------------------------------------------------------------------*/static void normalizeFloat64Subnormal( bits32 aSig0, bits32 aSig1, int16 *zExpPtr, bits32 *zSig0Ptr, bits32 *zSig1Ptr ){ int8 shiftCount; if ( aSig0 == 0 ) { shiftCount = countLeadingZeros( aSig1 ) - 11; if ( shiftCount < 0 ) { *zSig0Ptr = aSig1>>( - shiftCount ); *zSig1Ptr = aSig1<<( shiftCount & 31 ); } else { *zSig0Ptr = aSig1<<shiftCount; *zSig1Ptr = 0; } *zExpPtr = - shiftCount - 31; } else { shiftCount = countLeadingZeros( aSig0 ) - 11; shortShiftUp64( aSig0, aSig1, shiftCount, zSig0Ptr, zSig1Ptr ); *zExpPtr = 1 - shiftCount; }}/*-------------------------------------------------------------------------------Packs the sign `zSign', the exponent `zExp', and the significand formed bythe concatenation of `zSig0' and `zSig1' into a double-precision floating-point value, returning the result. After being shifted into the properpositions, the three fields `zSign', `zExp', and `zSig0' are simply addedtogether to form the most significant 32 bits of the result. This meansthat any integer portion of `zSig0' will be added into the exponent. Sincea properly normalized significand will have an integer portion equal to 1,the `zExp' input should be 1 less than the desired result exponent whenever`zSig0' and `zSig1' concatenated form a complete, normalized significand.-------------------------------------------------------------------------------*/INLINE float64 packFloat64( flag zSign, int16 zExp, bits32 zSig0, bits32 zSig1 ){ float64 z; z.low = zSig1;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?