115144b0fSOlivier Houchard /* $NetBSD: softfloat.c,v 1.1 2002/05/21 23:51:07 bjh21 Exp $ */
215144b0fSOlivier Houchard
315144b0fSOlivier Houchard /*
415144b0fSOlivier Houchard * This version hacked for use with gcc -msoft-float by bjh21.
515144b0fSOlivier Houchard * (Mostly a case of #ifdefing out things GCC doesn't need or provides
615144b0fSOlivier Houchard * itself).
715144b0fSOlivier Houchard */
815144b0fSOlivier Houchard
915144b0fSOlivier Houchard /*
1015144b0fSOlivier Houchard * Things you may want to define:
1115144b0fSOlivier Houchard *
1215144b0fSOlivier Houchard * SOFTFLOAT_FOR_GCC - build only those functions necessary for GCC (with
1315144b0fSOlivier Houchard * -msoft-float) to work. Include "softfloat-for-gcc.h" to get them
1415144b0fSOlivier Houchard * properly renamed.
1515144b0fSOlivier Houchard */
1615144b0fSOlivier Houchard
1715144b0fSOlivier Houchard /*
1815144b0fSOlivier Houchard * This differs from the standard bits32/softfloat.c in that float64
1915144b0fSOlivier Houchard * is defined to be a 64-bit integer rather than a structure. The
2015144b0fSOlivier Houchard * structure is float64s, with translation between the two going via
2115144b0fSOlivier Houchard * float64u.
2215144b0fSOlivier Houchard */
2315144b0fSOlivier Houchard
2415144b0fSOlivier Houchard /*
2515144b0fSOlivier Houchard ===============================================================================
2615144b0fSOlivier Houchard
2715144b0fSOlivier Houchard This C source file is part of the SoftFloat IEC/IEEE Floating-Point
2815144b0fSOlivier Houchard Arithmetic Package, Release 2a.
2915144b0fSOlivier Houchard
3015144b0fSOlivier Houchard Written by John R. Hauser. This work was made possible in part by the
3115144b0fSOlivier Houchard International Computer Science Institute, located at Suite 600, 1947 Center
3215144b0fSOlivier Houchard Street, Berkeley, California 94704. Funding was partially provided by the
3315144b0fSOlivier Houchard National Science Foundation under grant MIP-9311980. The original version
3415144b0fSOlivier Houchard of this code was written as part of a project to build a fixed-point vector
3515144b0fSOlivier Houchard processor in collaboration with the University of California at Berkeley,
3615144b0fSOlivier Houchard overseen by Profs. Nelson Morgan and John Wawrzynek. More information
3715144b0fSOlivier Houchard is available through the Web page `http://HTTP.CS.Berkeley.EDU/~jhauser/
3815144b0fSOlivier Houchard arithmetic/SoftFloat.html'.
3915144b0fSOlivier Houchard
4015144b0fSOlivier Houchard THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort
4115144b0fSOlivier Houchard has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT
4215144b0fSOlivier Houchard TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO
4315144b0fSOlivier Houchard PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY
4415144b0fSOlivier Houchard AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE.
4515144b0fSOlivier Houchard
4615144b0fSOlivier Houchard Derivative works are acceptable, even for commercial purposes, so long as
4715144b0fSOlivier Houchard (1) they include prominent notice that the work is derivative, and (2) they
4815144b0fSOlivier Houchard include prominent notice akin to these four paragraphs for those parts of
4915144b0fSOlivier Houchard this code that are retained.
5015144b0fSOlivier Houchard
5115144b0fSOlivier Houchard ===============================================================================
5215144b0fSOlivier Houchard */
5315144b0fSOlivier Houchard
5415144b0fSOlivier Houchard #ifdef SOFTFLOAT_FOR_GCC
5515144b0fSOlivier Houchard #include "softfloat-for-gcc.h"
5615144b0fSOlivier Houchard #endif
5715144b0fSOlivier Houchard
5815144b0fSOlivier Houchard #include "milieu.h"
5915144b0fSOlivier Houchard #include "softfloat.h"
6015144b0fSOlivier Houchard
6115144b0fSOlivier Houchard /*
6215144b0fSOlivier Houchard * Conversions between floats as stored in memory and floats as
6315144b0fSOlivier Houchard * SoftFloat uses them
6415144b0fSOlivier Houchard */
6515144b0fSOlivier Houchard #ifndef FLOAT64_DEMANGLE
6615144b0fSOlivier Houchard #define FLOAT64_DEMANGLE(a) (a)
6715144b0fSOlivier Houchard #endif
6815144b0fSOlivier Houchard #ifndef FLOAT64_MANGLE
6915144b0fSOlivier Houchard #define FLOAT64_MANGLE(a) (a)
7015144b0fSOlivier Houchard #endif
7115144b0fSOlivier Houchard
7215144b0fSOlivier Houchard /*
7315144b0fSOlivier Houchard -------------------------------------------------------------------------------
7415144b0fSOlivier Houchard Floating-point rounding mode and exception flags.
7515144b0fSOlivier Houchard -------------------------------------------------------------------------------
7615144b0fSOlivier Houchard */
77*b1d04644SDavid Schultz int float_rounding_mode = float_round_nearest_even;
78*b1d04644SDavid Schultz int float_exception_flags = 0;
7915144b0fSOlivier Houchard
8015144b0fSOlivier Houchard /*
8115144b0fSOlivier Houchard -------------------------------------------------------------------------------
8215144b0fSOlivier Houchard Primitive arithmetic functions, including multi-word arithmetic, and
8315144b0fSOlivier Houchard division and square root approximations. (Can be specialized to target if
8415144b0fSOlivier Houchard desired.)
8515144b0fSOlivier Houchard -------------------------------------------------------------------------------
8615144b0fSOlivier Houchard */
8715144b0fSOlivier Houchard #include "softfloat-macros"
8815144b0fSOlivier Houchard
8915144b0fSOlivier Houchard /*
9015144b0fSOlivier Houchard -------------------------------------------------------------------------------
9115144b0fSOlivier Houchard Functions and definitions to determine: (1) whether tininess for underflow
9215144b0fSOlivier Houchard is detected before or after rounding by default, (2) what (if anything)
9315144b0fSOlivier Houchard happens when exceptions are raised, (3) how signaling NaNs are distinguished
9415144b0fSOlivier Houchard from quiet NaNs, (4) the default generated quiet NaNs, and (4) how NaNs
9515144b0fSOlivier Houchard are propagated from function inputs to output. These details are target-
9615144b0fSOlivier Houchard specific.
9715144b0fSOlivier Houchard -------------------------------------------------------------------------------
9815144b0fSOlivier Houchard */
9915144b0fSOlivier Houchard #include "softfloat-specialize"
10015144b0fSOlivier Houchard
10115144b0fSOlivier Houchard /*
10215144b0fSOlivier Houchard -------------------------------------------------------------------------------
10315144b0fSOlivier Houchard Returns the fraction bits of the single-precision floating-point value `a'.
10415144b0fSOlivier Houchard -------------------------------------------------------------------------------
10515144b0fSOlivier Houchard */
extractFloat32Frac(float32 a)10615144b0fSOlivier Houchard INLINE bits32 extractFloat32Frac( float32 a )
10715144b0fSOlivier Houchard {
10815144b0fSOlivier Houchard
10915144b0fSOlivier Houchard return a & 0x007FFFFF;
11015144b0fSOlivier Houchard
11115144b0fSOlivier Houchard }
11215144b0fSOlivier Houchard
11315144b0fSOlivier Houchard /*
11415144b0fSOlivier Houchard -------------------------------------------------------------------------------
11515144b0fSOlivier Houchard Returns the exponent bits of the single-precision floating-point value `a'.
11615144b0fSOlivier Houchard -------------------------------------------------------------------------------
11715144b0fSOlivier Houchard */
extractFloat32Exp(float32 a)11815144b0fSOlivier Houchard INLINE int16 extractFloat32Exp( float32 a )
11915144b0fSOlivier Houchard {
12015144b0fSOlivier Houchard
12115144b0fSOlivier Houchard return ( a>>23 ) & 0xFF;
12215144b0fSOlivier Houchard
12315144b0fSOlivier Houchard }
12415144b0fSOlivier Houchard
12515144b0fSOlivier Houchard /*
12615144b0fSOlivier Houchard -------------------------------------------------------------------------------
12715144b0fSOlivier Houchard Returns the sign bit of the single-precision floating-point value `a'.
12815144b0fSOlivier Houchard -------------------------------------------------------------------------------
12915144b0fSOlivier Houchard */
extractFloat32Sign(float32 a)13015144b0fSOlivier Houchard INLINE flag extractFloat32Sign( float32 a )
13115144b0fSOlivier Houchard {
13215144b0fSOlivier Houchard
13315144b0fSOlivier Houchard return a>>31;
13415144b0fSOlivier Houchard
13515144b0fSOlivier Houchard }
13615144b0fSOlivier Houchard
13715144b0fSOlivier Houchard /*
13815144b0fSOlivier Houchard -------------------------------------------------------------------------------
13915144b0fSOlivier Houchard Normalizes the subnormal single-precision floating-point value represented
14015144b0fSOlivier Houchard by the denormalized significand `aSig'. The normalized exponent and
14115144b0fSOlivier Houchard significand are stored at the locations pointed to by `zExpPtr' and
14215144b0fSOlivier Houchard `zSigPtr', respectively.
14315144b0fSOlivier Houchard -------------------------------------------------------------------------------
14415144b0fSOlivier Houchard */
14515144b0fSOlivier Houchard static void
normalizeFloat32Subnormal(bits32 aSig,int16 * zExpPtr,bits32 * zSigPtr)14615144b0fSOlivier Houchard normalizeFloat32Subnormal( bits32 aSig, int16 *zExpPtr, bits32 *zSigPtr )
14715144b0fSOlivier Houchard {
14815144b0fSOlivier Houchard int8 shiftCount;
14915144b0fSOlivier Houchard
15015144b0fSOlivier Houchard shiftCount = countLeadingZeros32( aSig ) - 8;
15115144b0fSOlivier Houchard *zSigPtr = aSig<<shiftCount;
15215144b0fSOlivier Houchard *zExpPtr = 1 - shiftCount;
15315144b0fSOlivier Houchard
15415144b0fSOlivier Houchard }
15515144b0fSOlivier Houchard
15615144b0fSOlivier Houchard /*
15715144b0fSOlivier Houchard -------------------------------------------------------------------------------
15815144b0fSOlivier Houchard Packs the sign `zSign', exponent `zExp', and significand `zSig' into a
15915144b0fSOlivier Houchard single-precision floating-point value, returning the result. After being
16015144b0fSOlivier Houchard shifted into the proper positions, the three fields are simply added
16115144b0fSOlivier Houchard together to form the result. This means that any integer portion of `zSig'
16215144b0fSOlivier Houchard will be added into the exponent. Since a properly normalized significand
16315144b0fSOlivier Houchard will have an integer portion equal to 1, the `zExp' input should be 1 less
16415144b0fSOlivier Houchard than the desired result exponent whenever `zSig' is a complete, normalized
16515144b0fSOlivier Houchard significand.
16615144b0fSOlivier Houchard -------------------------------------------------------------------------------
16715144b0fSOlivier Houchard */
packFloat32(flag zSign,int16 zExp,bits32 zSig)16815144b0fSOlivier Houchard INLINE float32 packFloat32( flag zSign, int16 zExp, bits32 zSig )
16915144b0fSOlivier Houchard {
17015144b0fSOlivier Houchard
17115144b0fSOlivier Houchard return ( ( (bits32) zSign )<<31 ) + ( ( (bits32) zExp )<<23 ) + zSig;
17215144b0fSOlivier Houchard
17315144b0fSOlivier Houchard }
17415144b0fSOlivier Houchard
17515144b0fSOlivier Houchard /*
17615144b0fSOlivier Houchard -------------------------------------------------------------------------------
17715144b0fSOlivier Houchard Takes an abstract floating-point value having sign `zSign', exponent `zExp',
17815144b0fSOlivier Houchard and significand `zSig', and returns the proper single-precision floating-
17915144b0fSOlivier Houchard point value corresponding to the abstract input. Ordinarily, the abstract
18015144b0fSOlivier Houchard value is simply rounded and packed into the single-precision format, with
18115144b0fSOlivier Houchard the inexact exception raised if the abstract input cannot be represented
18215144b0fSOlivier Houchard exactly. However, if the abstract value is too large, the overflow and
18315144b0fSOlivier Houchard inexact exceptions are raised and an infinity or maximal finite value is
18415144b0fSOlivier Houchard returned. If the abstract value is too small, the input value is rounded to
18515144b0fSOlivier Houchard a subnormal number, and the underflow and inexact exceptions are raised if
18615144b0fSOlivier Houchard the abstract input cannot be represented exactly as a subnormal single-
18715144b0fSOlivier Houchard precision floating-point number.
18815144b0fSOlivier Houchard The input significand `zSig' has its binary point between bits 30
18915144b0fSOlivier Houchard and 29, which is 7 bits to the left of the usual location. This shifted
19015144b0fSOlivier Houchard significand must be normalized or smaller. If `zSig' is not normalized,
19115144b0fSOlivier Houchard `zExp' must be 0; in that case, the result returned is a subnormal number,
19215144b0fSOlivier Houchard and it must not require rounding. In the usual case that `zSig' is
19315144b0fSOlivier Houchard normalized, `zExp' must be 1 less than the ``true'' floating-point exponent.
19415144b0fSOlivier Houchard The handling of underflow and overflow follows the IEC/IEEE Standard for
19515144b0fSOlivier Houchard Binary Floating-Point Arithmetic.
19615144b0fSOlivier Houchard -------------------------------------------------------------------------------
19715144b0fSOlivier Houchard */
roundAndPackFloat32(flag zSign,int16 zExp,bits32 zSig)19815144b0fSOlivier Houchard static float32 roundAndPackFloat32( flag zSign, int16 zExp, bits32 zSig )
19915144b0fSOlivier Houchard {
20015144b0fSOlivier Houchard int8 roundingMode;
20115144b0fSOlivier Houchard flag roundNearestEven;
20215144b0fSOlivier Houchard int8 roundIncrement, roundBits;
20315144b0fSOlivier Houchard flag isTiny;
20415144b0fSOlivier Houchard
20515144b0fSOlivier Houchard roundingMode = float_rounding_mode;
20615144b0fSOlivier Houchard roundNearestEven = roundingMode == float_round_nearest_even;
20715144b0fSOlivier Houchard roundIncrement = 0x40;
20815144b0fSOlivier Houchard if ( ! roundNearestEven ) {
20915144b0fSOlivier Houchard if ( roundingMode == float_round_to_zero ) {
21015144b0fSOlivier Houchard roundIncrement = 0;
21115144b0fSOlivier Houchard }
21215144b0fSOlivier Houchard else {
21315144b0fSOlivier Houchard roundIncrement = 0x7F;
21415144b0fSOlivier Houchard if ( zSign ) {
21515144b0fSOlivier Houchard if ( roundingMode == float_round_up ) roundIncrement = 0;
21615144b0fSOlivier Houchard }
21715144b0fSOlivier Houchard else {
21815144b0fSOlivier Houchard if ( roundingMode == float_round_down ) roundIncrement = 0;
21915144b0fSOlivier Houchard }
22015144b0fSOlivier Houchard }
22115144b0fSOlivier Houchard }
22215144b0fSOlivier Houchard roundBits = zSig & 0x7F;
22315144b0fSOlivier Houchard if ( 0xFD <= (bits16) zExp ) {
22415144b0fSOlivier Houchard if ( ( 0xFD < zExp )
22515144b0fSOlivier Houchard || ( ( zExp == 0xFD )
22615144b0fSOlivier Houchard && ( (sbits32) ( zSig + roundIncrement ) < 0 ) )
22715144b0fSOlivier Houchard ) {
22815144b0fSOlivier Houchard float_raise( float_flag_overflow | float_flag_inexact );
22915144b0fSOlivier Houchard return packFloat32( zSign, 0xFF, 0 ) - ( roundIncrement == 0 );
23015144b0fSOlivier Houchard }
23115144b0fSOlivier Houchard if ( zExp < 0 ) {
23215144b0fSOlivier Houchard isTiny =
23315144b0fSOlivier Houchard ( float_detect_tininess == float_tininess_before_rounding )
23415144b0fSOlivier Houchard || ( zExp < -1 )
23515144b0fSOlivier Houchard || ( zSig + roundIncrement < 0x80000000 );
23615144b0fSOlivier Houchard shift32RightJamming( zSig, - zExp, &zSig );
23715144b0fSOlivier Houchard zExp = 0;
23815144b0fSOlivier Houchard roundBits = zSig & 0x7F;
23915144b0fSOlivier Houchard if ( isTiny && roundBits ) float_raise( float_flag_underflow );
24015144b0fSOlivier Houchard }
24115144b0fSOlivier Houchard }
24215144b0fSOlivier Houchard if ( roundBits ) float_exception_flags |= float_flag_inexact;
24315144b0fSOlivier Houchard zSig = ( zSig + roundIncrement )>>7;
24415144b0fSOlivier Houchard zSig &= ~ ( ( ( roundBits ^ 0x40 ) == 0 ) & roundNearestEven );
24515144b0fSOlivier Houchard if ( zSig == 0 ) zExp = 0;
24615144b0fSOlivier Houchard return packFloat32( zSign, zExp, zSig );
24715144b0fSOlivier Houchard
24815144b0fSOlivier Houchard }
24915144b0fSOlivier Houchard
25015144b0fSOlivier Houchard /*
25115144b0fSOlivier Houchard -------------------------------------------------------------------------------
25215144b0fSOlivier Houchard Takes an abstract floating-point value having sign `zSign', exponent `zExp',
25315144b0fSOlivier Houchard and significand `zSig', and returns the proper single-precision floating-
25415144b0fSOlivier Houchard point value corresponding to the abstract input. This routine is just like
25515144b0fSOlivier Houchard `roundAndPackFloat32' except that `zSig' does not have to be normalized.
25615144b0fSOlivier Houchard Bit 31 of `zSig' must be zero, and `zExp' must be 1 less than the ``true''
25715144b0fSOlivier Houchard floating-point exponent.
25815144b0fSOlivier Houchard -------------------------------------------------------------------------------
25915144b0fSOlivier Houchard */
26015144b0fSOlivier Houchard static float32
normalizeRoundAndPackFloat32(flag zSign,int16 zExp,bits32 zSig)26115144b0fSOlivier Houchard normalizeRoundAndPackFloat32( flag zSign, int16 zExp, bits32 zSig )
26215144b0fSOlivier Houchard {
26315144b0fSOlivier Houchard int8 shiftCount;
26415144b0fSOlivier Houchard
26515144b0fSOlivier Houchard shiftCount = countLeadingZeros32( zSig ) - 1;
26615144b0fSOlivier Houchard return roundAndPackFloat32( zSign, zExp - shiftCount, zSig<<shiftCount );
26715144b0fSOlivier Houchard
26815144b0fSOlivier Houchard }
26915144b0fSOlivier Houchard
27015144b0fSOlivier Houchard /*
27115144b0fSOlivier Houchard -------------------------------------------------------------------------------
27215144b0fSOlivier Houchard Returns the least-significant 32 fraction bits of the double-precision
27315144b0fSOlivier Houchard floating-point value `a'.
27415144b0fSOlivier Houchard -------------------------------------------------------------------------------
27515144b0fSOlivier Houchard */
extractFloat64Frac1(float64 a)27615144b0fSOlivier Houchard INLINE bits32 extractFloat64Frac1( float64 a )
27715144b0fSOlivier Houchard {
27815144b0fSOlivier Houchard
27915144b0fSOlivier Houchard return FLOAT64_DEMANGLE(a) & LIT64( 0x00000000FFFFFFFF );
28015144b0fSOlivier Houchard
28115144b0fSOlivier Houchard }
28215144b0fSOlivier Houchard
28315144b0fSOlivier Houchard /*
28415144b0fSOlivier Houchard -------------------------------------------------------------------------------
28515144b0fSOlivier Houchard Returns the most-significant 20 fraction bits of the double-precision
28615144b0fSOlivier Houchard floating-point value `a'.
28715144b0fSOlivier Houchard -------------------------------------------------------------------------------
28815144b0fSOlivier Houchard */
extractFloat64Frac0(float64 a)28915144b0fSOlivier Houchard INLINE bits32 extractFloat64Frac0( float64 a )
29015144b0fSOlivier Houchard {
29115144b0fSOlivier Houchard
29215144b0fSOlivier Houchard return ( FLOAT64_DEMANGLE(a)>>32 ) & 0x000FFFFF;
29315144b0fSOlivier Houchard
29415144b0fSOlivier Houchard }
29515144b0fSOlivier Houchard
29615144b0fSOlivier Houchard /*
29715144b0fSOlivier Houchard -------------------------------------------------------------------------------
29815144b0fSOlivier Houchard Returns the exponent bits of the double-precision floating-point value `a'.
29915144b0fSOlivier Houchard -------------------------------------------------------------------------------
30015144b0fSOlivier Houchard */
extractFloat64Exp(float64 a)30115144b0fSOlivier Houchard INLINE int16 extractFloat64Exp( float64 a )
30215144b0fSOlivier Houchard {
30315144b0fSOlivier Houchard
30415144b0fSOlivier Houchard return ( FLOAT64_DEMANGLE(a)>>52 ) & 0x7FF;
30515144b0fSOlivier Houchard
30615144b0fSOlivier Houchard }
30715144b0fSOlivier Houchard
30815144b0fSOlivier Houchard /*
30915144b0fSOlivier Houchard -------------------------------------------------------------------------------
31015144b0fSOlivier Houchard Returns the sign bit of the double-precision floating-point value `a'.
31115144b0fSOlivier Houchard -------------------------------------------------------------------------------
31215144b0fSOlivier Houchard */
extractFloat64Sign(float64 a)31315144b0fSOlivier Houchard INLINE flag extractFloat64Sign( float64 a )
31415144b0fSOlivier Houchard {
31515144b0fSOlivier Houchard
31615144b0fSOlivier Houchard return FLOAT64_DEMANGLE(a)>>63;
31715144b0fSOlivier Houchard
31815144b0fSOlivier Houchard }
31915144b0fSOlivier Houchard
32015144b0fSOlivier Houchard /*
32115144b0fSOlivier Houchard -------------------------------------------------------------------------------
32215144b0fSOlivier Houchard Normalizes the subnormal double-precision floating-point value represented
32315144b0fSOlivier Houchard by the denormalized significand formed by the concatenation of `aSig0' and
32415144b0fSOlivier Houchard `aSig1'. The normalized exponent is stored at the location pointed to by
32515144b0fSOlivier Houchard `zExpPtr'. The most significant 21 bits of the normalized significand are
32615144b0fSOlivier Houchard stored at the location pointed to by `zSig0Ptr', and the least significant
32715144b0fSOlivier Houchard 32 bits of the normalized significand are stored at the location pointed to
32815144b0fSOlivier Houchard by `zSig1Ptr'.
32915144b0fSOlivier Houchard -------------------------------------------------------------------------------
33015144b0fSOlivier Houchard */
33115144b0fSOlivier Houchard static void
normalizeFloat64Subnormal(bits32 aSig0,bits32 aSig1,int16 * zExpPtr,bits32 * zSig0Ptr,bits32 * zSig1Ptr)33215144b0fSOlivier Houchard normalizeFloat64Subnormal(
33315144b0fSOlivier Houchard bits32 aSig0,
33415144b0fSOlivier Houchard bits32 aSig1,
33515144b0fSOlivier Houchard int16 *zExpPtr,
33615144b0fSOlivier Houchard bits32 *zSig0Ptr,
33715144b0fSOlivier Houchard bits32 *zSig1Ptr
33815144b0fSOlivier Houchard )
33915144b0fSOlivier Houchard {
34015144b0fSOlivier Houchard int8 shiftCount;
34115144b0fSOlivier Houchard
34215144b0fSOlivier Houchard if ( aSig0 == 0 ) {
34315144b0fSOlivier Houchard shiftCount = countLeadingZeros32( aSig1 ) - 11;
34415144b0fSOlivier Houchard if ( shiftCount < 0 ) {
34515144b0fSOlivier Houchard *zSig0Ptr = aSig1>>( - shiftCount );
34615144b0fSOlivier Houchard *zSig1Ptr = aSig1<<( shiftCount & 31 );
34715144b0fSOlivier Houchard }
34815144b0fSOlivier Houchard else {
34915144b0fSOlivier Houchard *zSig0Ptr = aSig1<<shiftCount;
35015144b0fSOlivier Houchard *zSig1Ptr = 0;
35115144b0fSOlivier Houchard }
35215144b0fSOlivier Houchard *zExpPtr = - shiftCount - 31;
35315144b0fSOlivier Houchard }
35415144b0fSOlivier Houchard else {
35515144b0fSOlivier Houchard shiftCount = countLeadingZeros32( aSig0 ) - 11;
35615144b0fSOlivier Houchard shortShift64Left( aSig0, aSig1, shiftCount, zSig0Ptr, zSig1Ptr );
35715144b0fSOlivier Houchard *zExpPtr = 1 - shiftCount;
35815144b0fSOlivier Houchard }
35915144b0fSOlivier Houchard
36015144b0fSOlivier Houchard }
36115144b0fSOlivier Houchard
36215144b0fSOlivier Houchard /*
36315144b0fSOlivier Houchard -------------------------------------------------------------------------------
36415144b0fSOlivier Houchard Packs the sign `zSign', the exponent `zExp', and the significand formed by
36515144b0fSOlivier Houchard the concatenation of `zSig0' and `zSig1' into a double-precision floating-
36615144b0fSOlivier Houchard point value, returning the result. After being shifted into the proper
36715144b0fSOlivier Houchard positions, the three fields `zSign', `zExp', and `zSig0' are simply added
36815144b0fSOlivier Houchard together to form the most significant 32 bits of the result. This means
36915144b0fSOlivier Houchard that any integer portion of `zSig0' will be added into the exponent. Since
37015144b0fSOlivier Houchard a properly normalized significand will have an integer portion equal to 1,
37115144b0fSOlivier Houchard the `zExp' input should be 1 less than the desired result exponent whenever
37215144b0fSOlivier Houchard `zSig0' and `zSig1' concatenated form a complete, normalized significand.
37315144b0fSOlivier Houchard -------------------------------------------------------------------------------
37415144b0fSOlivier Houchard */
37515144b0fSOlivier Houchard INLINE float64
packFloat64(flag zSign,int16 zExp,bits32 zSig0,bits32 zSig1)37615144b0fSOlivier Houchard packFloat64( flag zSign, int16 zExp, bits32 zSig0, bits32 zSig1 )
37715144b0fSOlivier Houchard {
37815144b0fSOlivier Houchard
37915144b0fSOlivier Houchard return FLOAT64_MANGLE( ( ( (bits64) zSign )<<63 ) +
38015144b0fSOlivier Houchard ( ( (bits64) zExp )<<52 ) +
38115144b0fSOlivier Houchard ( ( (bits64) zSig0 )<<32 ) + zSig1 );
38215144b0fSOlivier Houchard
38315144b0fSOlivier Houchard
38415144b0fSOlivier Houchard }
38515144b0fSOlivier Houchard
38615144b0fSOlivier Houchard /*
38715144b0fSOlivier Houchard -------------------------------------------------------------------------------
38815144b0fSOlivier Houchard Takes an abstract floating-point value having sign `zSign', exponent `zExp',
38915144b0fSOlivier Houchard and extended significand formed by the concatenation of `zSig0', `zSig1',
39015144b0fSOlivier Houchard and `zSig2', and returns the proper double-precision floating-point value
39115144b0fSOlivier Houchard corresponding to the abstract input. Ordinarily, the abstract value is
39215144b0fSOlivier Houchard simply rounded and packed into the double-precision format, with the inexact
39315144b0fSOlivier Houchard exception raised if the abstract input cannot be represented exactly.
39415144b0fSOlivier Houchard However, if the abstract value is too large, the overflow and inexact
39515144b0fSOlivier Houchard exceptions are raised and an infinity or maximal finite value is returned.
39615144b0fSOlivier Houchard If the abstract value is too small, the input value is rounded to a
39715144b0fSOlivier Houchard subnormal number, and the underflow and inexact exceptions are raised if the
39815144b0fSOlivier Houchard abstract input cannot be represented exactly as a subnormal double-precision
39915144b0fSOlivier Houchard floating-point number.
40015144b0fSOlivier Houchard The input significand must be normalized or smaller. If the input
40115144b0fSOlivier Houchard significand is not normalized, `zExp' must be 0; in that case, the result
40215144b0fSOlivier Houchard returned is a subnormal number, and it must not require rounding. In the
40315144b0fSOlivier Houchard usual case that the input significand is normalized, `zExp' must be 1 less
40415144b0fSOlivier Houchard than the ``true'' floating-point exponent. The handling of underflow and
40515144b0fSOlivier Houchard overflow follows the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
40615144b0fSOlivier Houchard -------------------------------------------------------------------------------
40715144b0fSOlivier Houchard */
40815144b0fSOlivier Houchard static float64
roundAndPackFloat64(flag zSign,int16 zExp,bits32 zSig0,bits32 zSig1,bits32 zSig2)40915144b0fSOlivier Houchard roundAndPackFloat64(
41015144b0fSOlivier Houchard flag zSign, int16 zExp, bits32 zSig0, bits32 zSig1, bits32 zSig2 )
41115144b0fSOlivier Houchard {
41215144b0fSOlivier Houchard int8 roundingMode;
41315144b0fSOlivier Houchard flag roundNearestEven, increment, isTiny;
41415144b0fSOlivier Houchard
41515144b0fSOlivier Houchard roundingMode = float_rounding_mode;
41615144b0fSOlivier Houchard roundNearestEven = ( roundingMode == float_round_nearest_even );
41715144b0fSOlivier Houchard increment = ( (sbits32) zSig2 < 0 );
41815144b0fSOlivier Houchard if ( ! roundNearestEven ) {
41915144b0fSOlivier Houchard if ( roundingMode == float_round_to_zero ) {
42015144b0fSOlivier Houchard increment = 0;
42115144b0fSOlivier Houchard }
42215144b0fSOlivier Houchard else {
42315144b0fSOlivier Houchard if ( zSign ) {
42415144b0fSOlivier Houchard increment = ( roundingMode == float_round_down ) && zSig2;
42515144b0fSOlivier Houchard }
42615144b0fSOlivier Houchard else {
42715144b0fSOlivier Houchard increment = ( roundingMode == float_round_up ) && zSig2;
42815144b0fSOlivier Houchard }
42915144b0fSOlivier Houchard }
43015144b0fSOlivier Houchard }
43115144b0fSOlivier Houchard if ( 0x7FD <= (bits16) zExp ) {
43215144b0fSOlivier Houchard if ( ( 0x7FD < zExp )
43315144b0fSOlivier Houchard || ( ( zExp == 0x7FD )
43415144b0fSOlivier Houchard && eq64( 0x001FFFFF, 0xFFFFFFFF, zSig0, zSig1 )
43515144b0fSOlivier Houchard && increment
43615144b0fSOlivier Houchard )
43715144b0fSOlivier Houchard ) {
43815144b0fSOlivier Houchard float_raise( float_flag_overflow | float_flag_inexact );
43915144b0fSOlivier Houchard if ( ( roundingMode == float_round_to_zero )
44015144b0fSOlivier Houchard || ( zSign && ( roundingMode == float_round_up ) )
44115144b0fSOlivier Houchard || ( ! zSign && ( roundingMode == float_round_down ) )
44215144b0fSOlivier Houchard ) {
44315144b0fSOlivier Houchard return packFloat64( zSign, 0x7FE, 0x000FFFFF, 0xFFFFFFFF );
44415144b0fSOlivier Houchard }
44515144b0fSOlivier Houchard return packFloat64( zSign, 0x7FF, 0, 0 );
44615144b0fSOlivier Houchard }
44715144b0fSOlivier Houchard if ( zExp < 0 ) {
44815144b0fSOlivier Houchard isTiny =
44915144b0fSOlivier Houchard ( float_detect_tininess == float_tininess_before_rounding )
45015144b0fSOlivier Houchard || ( zExp < -1 )
45115144b0fSOlivier Houchard || ! increment
45215144b0fSOlivier Houchard || lt64( zSig0, zSig1, 0x001FFFFF, 0xFFFFFFFF );
45315144b0fSOlivier Houchard shift64ExtraRightJamming(
45415144b0fSOlivier Houchard zSig0, zSig1, zSig2, - zExp, &zSig0, &zSig1, &zSig2 );
45515144b0fSOlivier Houchard zExp = 0;
45615144b0fSOlivier Houchard if ( isTiny && zSig2 ) float_raise( float_flag_underflow );
45715144b0fSOlivier Houchard if ( roundNearestEven ) {
45815144b0fSOlivier Houchard increment = ( (sbits32) zSig2 < 0 );
45915144b0fSOlivier Houchard }
46015144b0fSOlivier Houchard else {
46115144b0fSOlivier Houchard if ( zSign ) {
46215144b0fSOlivier Houchard increment = ( roundingMode == float_round_down ) && zSig2;
46315144b0fSOlivier Houchard }
46415144b0fSOlivier Houchard else {
46515144b0fSOlivier Houchard increment = ( roundingMode == float_round_up ) && zSig2;
46615144b0fSOlivier Houchard }
46715144b0fSOlivier Houchard }
46815144b0fSOlivier Houchard }
46915144b0fSOlivier Houchard }
47015144b0fSOlivier Houchard if ( zSig2 ) float_exception_flags |= float_flag_inexact;
47115144b0fSOlivier Houchard if ( increment ) {
47215144b0fSOlivier Houchard add64( zSig0, zSig1, 0, 1, &zSig0, &zSig1 );
47315144b0fSOlivier Houchard zSig1 &= ~ ( ( zSig2 + zSig2 == 0 ) & roundNearestEven );
47415144b0fSOlivier Houchard }
47515144b0fSOlivier Houchard else {
47615144b0fSOlivier Houchard if ( ( zSig0 | zSig1 ) == 0 ) zExp = 0;
47715144b0fSOlivier Houchard }
47815144b0fSOlivier Houchard return packFloat64( zSign, zExp, zSig0, zSig1 );
47915144b0fSOlivier Houchard
48015144b0fSOlivier Houchard }
48115144b0fSOlivier Houchard
48215144b0fSOlivier Houchard /*
48315144b0fSOlivier Houchard -------------------------------------------------------------------------------
48415144b0fSOlivier Houchard Takes an abstract floating-point value having sign `zSign', exponent `zExp',
48515144b0fSOlivier Houchard and significand formed by the concatenation of `zSig0' and `zSig1', and
48615144b0fSOlivier Houchard returns the proper double-precision floating-point value corresponding
48715144b0fSOlivier Houchard to the abstract input. This routine is just like `roundAndPackFloat64'
48815144b0fSOlivier Houchard except that the input significand has fewer bits and does not have to be
48915144b0fSOlivier Houchard normalized. In all cases, `zExp' must be 1 less than the ``true'' floating-
49015144b0fSOlivier Houchard point exponent.
49115144b0fSOlivier Houchard -------------------------------------------------------------------------------
49215144b0fSOlivier Houchard */
49315144b0fSOlivier Houchard static float64
normalizeRoundAndPackFloat64(flag zSign,int16 zExp,bits32 zSig0,bits32 zSig1)49415144b0fSOlivier Houchard normalizeRoundAndPackFloat64(
49515144b0fSOlivier Houchard flag zSign, int16 zExp, bits32 zSig0, bits32 zSig1 )
49615144b0fSOlivier Houchard {
49715144b0fSOlivier Houchard int8 shiftCount;
49815144b0fSOlivier Houchard bits32 zSig2;
49915144b0fSOlivier Houchard
50015144b0fSOlivier Houchard if ( zSig0 == 0 ) {
50115144b0fSOlivier Houchard zSig0 = zSig1;
50215144b0fSOlivier Houchard zSig1 = 0;
50315144b0fSOlivier Houchard zExp -= 32;
50415144b0fSOlivier Houchard }
50515144b0fSOlivier Houchard shiftCount = countLeadingZeros32( zSig0 ) - 11;
50615144b0fSOlivier Houchard if ( 0 <= shiftCount ) {
50715144b0fSOlivier Houchard zSig2 = 0;
50815144b0fSOlivier Houchard shortShift64Left( zSig0, zSig1, shiftCount, &zSig0, &zSig1 );
50915144b0fSOlivier Houchard }
51015144b0fSOlivier Houchard else {
51115144b0fSOlivier Houchard shift64ExtraRightJamming(
51215144b0fSOlivier Houchard zSig0, zSig1, 0, - shiftCount, &zSig0, &zSig1, &zSig2 );
51315144b0fSOlivier Houchard }
51415144b0fSOlivier Houchard zExp -= shiftCount;
51515144b0fSOlivier Houchard return roundAndPackFloat64( zSign, zExp, zSig0, zSig1, zSig2 );
51615144b0fSOlivier Houchard
51715144b0fSOlivier Houchard }
51815144b0fSOlivier Houchard
51915144b0fSOlivier Houchard /*
52015144b0fSOlivier Houchard -------------------------------------------------------------------------------
52115144b0fSOlivier Houchard Returns the result of converting the 32-bit two's complement integer `a' to
52215144b0fSOlivier Houchard the single-precision floating-point format. The conversion is performed
52315144b0fSOlivier Houchard according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
52415144b0fSOlivier Houchard -------------------------------------------------------------------------------
52515144b0fSOlivier Houchard */
int32_to_float32(int32 a)52615144b0fSOlivier Houchard float32 int32_to_float32( int32 a )
52715144b0fSOlivier Houchard {
52815144b0fSOlivier Houchard flag zSign;
52915144b0fSOlivier Houchard
53015144b0fSOlivier Houchard if ( a == 0 ) return 0;
53115144b0fSOlivier Houchard if ( a == (sbits32) 0x80000000 ) return packFloat32( 1, 0x9E, 0 );
53215144b0fSOlivier Houchard zSign = ( a < 0 );
53315144b0fSOlivier Houchard return normalizeRoundAndPackFloat32( zSign, 0x9C, zSign ? - a : a );
53415144b0fSOlivier Houchard
53515144b0fSOlivier Houchard }
53615144b0fSOlivier Houchard
53715144b0fSOlivier Houchard /*
53815144b0fSOlivier Houchard -------------------------------------------------------------------------------
53915144b0fSOlivier Houchard Returns the result of converting the 32-bit two's complement integer `a' to
54015144b0fSOlivier Houchard the double-precision floating-point format. The conversion is performed
54115144b0fSOlivier Houchard according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
54215144b0fSOlivier Houchard -------------------------------------------------------------------------------
54315144b0fSOlivier Houchard */
int32_to_float64(int32 a)54415144b0fSOlivier Houchard float64 int32_to_float64( int32 a )
54515144b0fSOlivier Houchard {
54615144b0fSOlivier Houchard flag zSign;
54715144b0fSOlivier Houchard bits32 absA;
54815144b0fSOlivier Houchard int8 shiftCount;
54915144b0fSOlivier Houchard bits32 zSig0, zSig1;
55015144b0fSOlivier Houchard
55115144b0fSOlivier Houchard if ( a == 0 ) return packFloat64( 0, 0, 0, 0 );
55215144b0fSOlivier Houchard zSign = ( a < 0 );
55315144b0fSOlivier Houchard absA = zSign ? - a : a;
55415144b0fSOlivier Houchard shiftCount = countLeadingZeros32( absA ) - 11;
55515144b0fSOlivier Houchard if ( 0 <= shiftCount ) {
55615144b0fSOlivier Houchard zSig0 = absA<<shiftCount;
55715144b0fSOlivier Houchard zSig1 = 0;
55815144b0fSOlivier Houchard }
55915144b0fSOlivier Houchard else {
56015144b0fSOlivier Houchard shift64Right( absA, 0, - shiftCount, &zSig0, &zSig1 );
56115144b0fSOlivier Houchard }
56215144b0fSOlivier Houchard return packFloat64( zSign, 0x412 - shiftCount, zSig0, zSig1 );
56315144b0fSOlivier Houchard
56415144b0fSOlivier Houchard }
56515144b0fSOlivier Houchard
56615144b0fSOlivier Houchard #ifndef SOFTFLOAT_FOR_GCC
56715144b0fSOlivier Houchard /*
56815144b0fSOlivier Houchard -------------------------------------------------------------------------------
56915144b0fSOlivier Houchard Returns the result of converting the single-precision floating-point value
57015144b0fSOlivier Houchard `a' to the 32-bit two's complement integer format. The conversion is
57115144b0fSOlivier Houchard performed according to the IEC/IEEE Standard for Binary Floating-Point
57215144b0fSOlivier Houchard Arithmetic---which means in particular that the conversion is rounded
57315144b0fSOlivier Houchard according to the current rounding mode. If `a' is a NaN, the largest
57415144b0fSOlivier Houchard positive integer is returned. Otherwise, if the conversion overflows, the
57515144b0fSOlivier Houchard largest integer with the same sign as `a' is returned.
57615144b0fSOlivier Houchard -------------------------------------------------------------------------------
57715144b0fSOlivier Houchard */
float32_to_int32(float32 a)57815144b0fSOlivier Houchard int32 float32_to_int32( float32 a )
57915144b0fSOlivier Houchard {
58015144b0fSOlivier Houchard flag aSign;
58115144b0fSOlivier Houchard int16 aExp, shiftCount;
58215144b0fSOlivier Houchard bits32 aSig, aSigExtra;
58315144b0fSOlivier Houchard int32 z;
58415144b0fSOlivier Houchard int8 roundingMode;
58515144b0fSOlivier Houchard
58615144b0fSOlivier Houchard aSig = extractFloat32Frac( a );
58715144b0fSOlivier Houchard aExp = extractFloat32Exp( a );
58815144b0fSOlivier Houchard aSign = extractFloat32Sign( a );
58915144b0fSOlivier Houchard shiftCount = aExp - 0x96;
59015144b0fSOlivier Houchard if ( 0 <= shiftCount ) {
59115144b0fSOlivier Houchard if ( 0x9E <= aExp ) {
59215144b0fSOlivier Houchard if ( a != 0xCF000000 ) {
59315144b0fSOlivier Houchard float_raise( float_flag_invalid );
59415144b0fSOlivier Houchard if ( ! aSign || ( ( aExp == 0xFF ) && aSig ) ) {
59515144b0fSOlivier Houchard return 0x7FFFFFFF;
59615144b0fSOlivier Houchard }
59715144b0fSOlivier Houchard }
59815144b0fSOlivier Houchard return (sbits32) 0x80000000;
59915144b0fSOlivier Houchard }
60015144b0fSOlivier Houchard z = ( aSig | 0x00800000 )<<shiftCount;
60115144b0fSOlivier Houchard if ( aSign ) z = - z;
60215144b0fSOlivier Houchard }
60315144b0fSOlivier Houchard else {
60415144b0fSOlivier Houchard if ( aExp < 0x7E ) {
60515144b0fSOlivier Houchard aSigExtra = aExp | aSig;
60615144b0fSOlivier Houchard z = 0;
60715144b0fSOlivier Houchard }
60815144b0fSOlivier Houchard else {
60915144b0fSOlivier Houchard aSig |= 0x00800000;
61015144b0fSOlivier Houchard aSigExtra = aSig<<( shiftCount & 31 );
61115144b0fSOlivier Houchard z = aSig>>( - shiftCount );
61215144b0fSOlivier Houchard }
61315144b0fSOlivier Houchard if ( aSigExtra ) float_exception_flags |= float_flag_inexact;
61415144b0fSOlivier Houchard roundingMode = float_rounding_mode;
61515144b0fSOlivier Houchard if ( roundingMode == float_round_nearest_even ) {
61615144b0fSOlivier Houchard if ( (sbits32) aSigExtra < 0 ) {
61715144b0fSOlivier Houchard ++z;
61815144b0fSOlivier Houchard if ( (bits32) ( aSigExtra<<1 ) == 0 ) z &= ~1;
61915144b0fSOlivier Houchard }
62015144b0fSOlivier Houchard if ( aSign ) z = - z;
62115144b0fSOlivier Houchard }
62215144b0fSOlivier Houchard else {
62315144b0fSOlivier Houchard aSigExtra = ( aSigExtra != 0 );
62415144b0fSOlivier Houchard if ( aSign ) {
62515144b0fSOlivier Houchard z += ( roundingMode == float_round_down ) & aSigExtra;
62615144b0fSOlivier Houchard z = - z;
62715144b0fSOlivier Houchard }
62815144b0fSOlivier Houchard else {
62915144b0fSOlivier Houchard z += ( roundingMode == float_round_up ) & aSigExtra;
63015144b0fSOlivier Houchard }
63115144b0fSOlivier Houchard }
63215144b0fSOlivier Houchard }
63315144b0fSOlivier Houchard return z;
63415144b0fSOlivier Houchard
63515144b0fSOlivier Houchard }
63615144b0fSOlivier Houchard #endif
63715144b0fSOlivier Houchard
63815144b0fSOlivier Houchard /*
63915144b0fSOlivier Houchard -------------------------------------------------------------------------------
64015144b0fSOlivier Houchard Returns the result of converting the single-precision floating-point value
64115144b0fSOlivier Houchard `a' to the 32-bit two's complement integer format. The conversion is
64215144b0fSOlivier Houchard performed according to the IEC/IEEE Standard for Binary Floating-Point
64315144b0fSOlivier Houchard Arithmetic, except that the conversion is always rounded toward zero.
64415144b0fSOlivier Houchard If `a' is a NaN, the largest positive integer is returned. Otherwise, if
64515144b0fSOlivier Houchard the conversion overflows, the largest integer with the same sign as `a' is
64615144b0fSOlivier Houchard returned.
64715144b0fSOlivier Houchard -------------------------------------------------------------------------------
64815144b0fSOlivier Houchard */
float32_to_int32_round_to_zero(float32 a)64915144b0fSOlivier Houchard int32 float32_to_int32_round_to_zero( float32 a )
65015144b0fSOlivier Houchard {
65115144b0fSOlivier Houchard flag aSign;
65215144b0fSOlivier Houchard int16 aExp, shiftCount;
65315144b0fSOlivier Houchard bits32 aSig;
65415144b0fSOlivier Houchard int32 z;
65515144b0fSOlivier Houchard
65615144b0fSOlivier Houchard aSig = extractFloat32Frac( a );
65715144b0fSOlivier Houchard aExp = extractFloat32Exp( a );
65815144b0fSOlivier Houchard aSign = extractFloat32Sign( a );
65915144b0fSOlivier Houchard shiftCount = aExp - 0x9E;
66015144b0fSOlivier Houchard if ( 0 <= shiftCount ) {
66115144b0fSOlivier Houchard if ( a != 0xCF000000 ) {
66215144b0fSOlivier Houchard float_raise( float_flag_invalid );
66315144b0fSOlivier Houchard if ( ! aSign || ( ( aExp == 0xFF ) && aSig ) ) return 0x7FFFFFFF;
66415144b0fSOlivier Houchard }
66515144b0fSOlivier Houchard return (sbits32) 0x80000000;
66615144b0fSOlivier Houchard }
66715144b0fSOlivier Houchard else if ( aExp <= 0x7E ) {
66815144b0fSOlivier Houchard if ( aExp | aSig ) float_exception_flags |= float_flag_inexact;
66915144b0fSOlivier Houchard return 0;
67015144b0fSOlivier Houchard }
67115144b0fSOlivier Houchard aSig = ( aSig | 0x00800000 )<<8;
67215144b0fSOlivier Houchard z = aSig>>( - shiftCount );
67315144b0fSOlivier Houchard if ( (bits32) ( aSig<<( shiftCount & 31 ) ) ) {
67415144b0fSOlivier Houchard float_exception_flags |= float_flag_inexact;
67515144b0fSOlivier Houchard }
67615144b0fSOlivier Houchard if ( aSign ) z = - z;
67715144b0fSOlivier Houchard return z;
67815144b0fSOlivier Houchard
67915144b0fSOlivier Houchard }
68015144b0fSOlivier Houchard
68115144b0fSOlivier Houchard /*
68215144b0fSOlivier Houchard -------------------------------------------------------------------------------
68315144b0fSOlivier Houchard Returns the result of converting the single-precision floating-point value
68415144b0fSOlivier Houchard `a' to the double-precision floating-point format. The conversion is
68515144b0fSOlivier Houchard performed according to the IEC/IEEE Standard for Binary Floating-Point
68615144b0fSOlivier Houchard Arithmetic.
68715144b0fSOlivier Houchard -------------------------------------------------------------------------------
68815144b0fSOlivier Houchard */
float32_to_float64(float32 a)68915144b0fSOlivier Houchard float64 float32_to_float64( float32 a )
69015144b0fSOlivier Houchard {
69115144b0fSOlivier Houchard flag aSign;
69215144b0fSOlivier Houchard int16 aExp;
69315144b0fSOlivier Houchard bits32 aSig, zSig0, zSig1;
69415144b0fSOlivier Houchard
69515144b0fSOlivier Houchard aSig = extractFloat32Frac( a );
69615144b0fSOlivier Houchard aExp = extractFloat32Exp( a );
69715144b0fSOlivier Houchard aSign = extractFloat32Sign( a );
69815144b0fSOlivier Houchard if ( aExp == 0xFF ) {
69915144b0fSOlivier Houchard if ( aSig ) return commonNaNToFloat64( float32ToCommonNaN( a ) );
70015144b0fSOlivier Houchard return packFloat64( aSign, 0x7FF, 0, 0 );
70115144b0fSOlivier Houchard }
70215144b0fSOlivier Houchard if ( aExp == 0 ) {
70315144b0fSOlivier Houchard if ( aSig == 0 ) return packFloat64( aSign, 0, 0, 0 );
70415144b0fSOlivier Houchard normalizeFloat32Subnormal( aSig, &aExp, &aSig );
70515144b0fSOlivier Houchard --aExp;
70615144b0fSOlivier Houchard }
70715144b0fSOlivier Houchard shift64Right( aSig, 0, 3, &zSig0, &zSig1 );
70815144b0fSOlivier Houchard return packFloat64( aSign, aExp + 0x380, zSig0, zSig1 );
70915144b0fSOlivier Houchard
71015144b0fSOlivier Houchard }
71115144b0fSOlivier Houchard
71215144b0fSOlivier Houchard #ifndef SOFTFLOAT_FOR_GCC
71315144b0fSOlivier Houchard /*
71415144b0fSOlivier Houchard -------------------------------------------------------------------------------
71515144b0fSOlivier Houchard Rounds the single-precision floating-point value `a' to an integer,
71615144b0fSOlivier Houchard and returns the result as a single-precision floating-point value. The
71715144b0fSOlivier Houchard operation is performed according to the IEC/IEEE Standard for Binary
71815144b0fSOlivier Houchard Floating-Point Arithmetic.
71915144b0fSOlivier Houchard -------------------------------------------------------------------------------
72015144b0fSOlivier Houchard */
float32_round_to_int(float32 a)72115144b0fSOlivier Houchard float32 float32_round_to_int( float32 a )
72215144b0fSOlivier Houchard {
72315144b0fSOlivier Houchard flag aSign;
72415144b0fSOlivier Houchard int16 aExp;
72515144b0fSOlivier Houchard bits32 lastBitMask, roundBitsMask;
72615144b0fSOlivier Houchard int8 roundingMode;
72715144b0fSOlivier Houchard float32 z;
72815144b0fSOlivier Houchard
72915144b0fSOlivier Houchard aExp = extractFloat32Exp( a );
73015144b0fSOlivier Houchard if ( 0x96 <= aExp ) {
73115144b0fSOlivier Houchard if ( ( aExp == 0xFF ) && extractFloat32Frac( a ) ) {
73215144b0fSOlivier Houchard return propagateFloat32NaN( a, a );
73315144b0fSOlivier Houchard }
73415144b0fSOlivier Houchard return a;
73515144b0fSOlivier Houchard }
73615144b0fSOlivier Houchard if ( aExp <= 0x7E ) {
73715144b0fSOlivier Houchard if ( (bits32) ( a<<1 ) == 0 ) return a;
73815144b0fSOlivier Houchard float_exception_flags |= float_flag_inexact;
73915144b0fSOlivier Houchard aSign = extractFloat32Sign( a );
74015144b0fSOlivier Houchard switch ( float_rounding_mode ) {
74115144b0fSOlivier Houchard case float_round_nearest_even:
74215144b0fSOlivier Houchard if ( ( aExp == 0x7E ) && extractFloat32Frac( a ) ) {
74315144b0fSOlivier Houchard return packFloat32( aSign, 0x7F, 0 );
74415144b0fSOlivier Houchard }
74515144b0fSOlivier Houchard break;
74615144b0fSOlivier Houchard case float_round_to_zero:
74715144b0fSOlivier Houchard break;
74815144b0fSOlivier Houchard case float_round_down:
74915144b0fSOlivier Houchard return aSign ? 0xBF800000 : 0;
75015144b0fSOlivier Houchard case float_round_up:
75115144b0fSOlivier Houchard return aSign ? 0x80000000 : 0x3F800000;
75215144b0fSOlivier Houchard }
75315144b0fSOlivier Houchard return packFloat32( aSign, 0, 0 );
75415144b0fSOlivier Houchard }
75515144b0fSOlivier Houchard lastBitMask = 1;
75615144b0fSOlivier Houchard lastBitMask <<= 0x96 - aExp;
75715144b0fSOlivier Houchard roundBitsMask = lastBitMask - 1;
75815144b0fSOlivier Houchard z = a;
75915144b0fSOlivier Houchard roundingMode = float_rounding_mode;
76015144b0fSOlivier Houchard if ( roundingMode == float_round_nearest_even ) {
76115144b0fSOlivier Houchard z += lastBitMask>>1;
76215144b0fSOlivier Houchard if ( ( z & roundBitsMask ) == 0 ) z &= ~ lastBitMask;
76315144b0fSOlivier Houchard }
76415144b0fSOlivier Houchard else if ( roundingMode != float_round_to_zero ) {
76515144b0fSOlivier Houchard if ( extractFloat32Sign( z ) ^ ( roundingMode == float_round_up ) ) {
76615144b0fSOlivier Houchard z += roundBitsMask;
76715144b0fSOlivier Houchard }
76815144b0fSOlivier Houchard }
76915144b0fSOlivier Houchard z &= ~ roundBitsMask;
77015144b0fSOlivier Houchard if ( z != a ) float_exception_flags |= float_flag_inexact;
77115144b0fSOlivier Houchard return z;
77215144b0fSOlivier Houchard
77315144b0fSOlivier Houchard }
77415144b0fSOlivier Houchard #endif
77515144b0fSOlivier Houchard
77615144b0fSOlivier Houchard /*
77715144b0fSOlivier Houchard -------------------------------------------------------------------------------
77815144b0fSOlivier Houchard Returns the result of adding the absolute values of the single-precision
77915144b0fSOlivier Houchard floating-point values `a' and `b'. If `zSign' is 1, the sum is negated
78015144b0fSOlivier Houchard before being returned. `zSign' is ignored if the result is a NaN.
78115144b0fSOlivier Houchard The addition is performed according to the IEC/IEEE Standard for Binary
78215144b0fSOlivier Houchard Floating-Point Arithmetic.
78315144b0fSOlivier Houchard -------------------------------------------------------------------------------
78415144b0fSOlivier Houchard */
addFloat32Sigs(float32 a,float32 b,flag zSign)78515144b0fSOlivier Houchard static float32 addFloat32Sigs( float32 a, float32 b, flag zSign )
78615144b0fSOlivier Houchard {
78715144b0fSOlivier Houchard int16 aExp, bExp, zExp;
78815144b0fSOlivier Houchard bits32 aSig, bSig, zSig;
78915144b0fSOlivier Houchard int16 expDiff;
79015144b0fSOlivier Houchard
79115144b0fSOlivier Houchard aSig = extractFloat32Frac( a );
79215144b0fSOlivier Houchard aExp = extractFloat32Exp( a );
79315144b0fSOlivier Houchard bSig = extractFloat32Frac( b );
79415144b0fSOlivier Houchard bExp = extractFloat32Exp( b );
79515144b0fSOlivier Houchard expDiff = aExp - bExp;
79615144b0fSOlivier Houchard aSig <<= 6;
79715144b0fSOlivier Houchard bSig <<= 6;
79815144b0fSOlivier Houchard if ( 0 < expDiff ) {
79915144b0fSOlivier Houchard if ( aExp == 0xFF ) {
80015144b0fSOlivier Houchard if ( aSig ) return propagateFloat32NaN( a, b );
80115144b0fSOlivier Houchard return a;
80215144b0fSOlivier Houchard }
80315144b0fSOlivier Houchard if ( bExp == 0 ) {
80415144b0fSOlivier Houchard --expDiff;
80515144b0fSOlivier Houchard }
80615144b0fSOlivier Houchard else {
80715144b0fSOlivier Houchard bSig |= 0x20000000;
80815144b0fSOlivier Houchard }
80915144b0fSOlivier Houchard shift32RightJamming( bSig, expDiff, &bSig );
81015144b0fSOlivier Houchard zExp = aExp;
81115144b0fSOlivier Houchard }
81215144b0fSOlivier Houchard else if ( expDiff < 0 ) {
81315144b0fSOlivier Houchard if ( bExp == 0xFF ) {
81415144b0fSOlivier Houchard if ( bSig ) return propagateFloat32NaN( a, b );
81515144b0fSOlivier Houchard return packFloat32( zSign, 0xFF, 0 );
81615144b0fSOlivier Houchard }
81715144b0fSOlivier Houchard if ( aExp == 0 ) {
81815144b0fSOlivier Houchard ++expDiff;
81915144b0fSOlivier Houchard }
82015144b0fSOlivier Houchard else {
82115144b0fSOlivier Houchard aSig |= 0x20000000;
82215144b0fSOlivier Houchard }
82315144b0fSOlivier Houchard shift32RightJamming( aSig, - expDiff, &aSig );
82415144b0fSOlivier Houchard zExp = bExp;
82515144b0fSOlivier Houchard }
82615144b0fSOlivier Houchard else {
82715144b0fSOlivier Houchard if ( aExp == 0xFF ) {
82815144b0fSOlivier Houchard if ( aSig | bSig ) return propagateFloat32NaN( a, b );
82915144b0fSOlivier Houchard return a;
83015144b0fSOlivier Houchard }
83115144b0fSOlivier Houchard if ( aExp == 0 ) return packFloat32( zSign, 0, ( aSig + bSig )>>6 );
83215144b0fSOlivier Houchard zSig = 0x40000000 + aSig + bSig;
83315144b0fSOlivier Houchard zExp = aExp;
83415144b0fSOlivier Houchard goto roundAndPack;
83515144b0fSOlivier Houchard }
83615144b0fSOlivier Houchard aSig |= 0x20000000;
83715144b0fSOlivier Houchard zSig = ( aSig + bSig )<<1;
83815144b0fSOlivier Houchard --zExp;
83915144b0fSOlivier Houchard if ( (sbits32) zSig < 0 ) {
84015144b0fSOlivier Houchard zSig = aSig + bSig;
84115144b0fSOlivier Houchard ++zExp;
84215144b0fSOlivier Houchard }
84315144b0fSOlivier Houchard roundAndPack:
84415144b0fSOlivier Houchard return roundAndPackFloat32( zSign, zExp, zSig );
84515144b0fSOlivier Houchard
84615144b0fSOlivier Houchard }
84715144b0fSOlivier Houchard
84815144b0fSOlivier Houchard /*
84915144b0fSOlivier Houchard -------------------------------------------------------------------------------
85015144b0fSOlivier Houchard Returns the result of subtracting the absolute values of the single-
85115144b0fSOlivier Houchard precision floating-point values `a' and `b'. If `zSign' is 1, the
85215144b0fSOlivier Houchard difference is negated before being returned. `zSign' is ignored if the
85315144b0fSOlivier Houchard result is a NaN. The subtraction is performed according to the IEC/IEEE
85415144b0fSOlivier Houchard Standard for Binary Floating-Point Arithmetic.
85515144b0fSOlivier Houchard -------------------------------------------------------------------------------
85615144b0fSOlivier Houchard */
subFloat32Sigs(float32 a,float32 b,flag zSign)85715144b0fSOlivier Houchard static float32 subFloat32Sigs( float32 a, float32 b, flag zSign )
85815144b0fSOlivier Houchard {
85915144b0fSOlivier Houchard int16 aExp, bExp, zExp;
86015144b0fSOlivier Houchard bits32 aSig, bSig, zSig;
86115144b0fSOlivier Houchard int16 expDiff;
86215144b0fSOlivier Houchard
86315144b0fSOlivier Houchard aSig = extractFloat32Frac( a );
86415144b0fSOlivier Houchard aExp = extractFloat32Exp( a );
86515144b0fSOlivier Houchard bSig = extractFloat32Frac( b );
86615144b0fSOlivier Houchard bExp = extractFloat32Exp( b );
86715144b0fSOlivier Houchard expDiff = aExp - bExp;
86815144b0fSOlivier Houchard aSig <<= 7;
86915144b0fSOlivier Houchard bSig <<= 7;
87015144b0fSOlivier Houchard if ( 0 < expDiff ) goto aExpBigger;
87115144b0fSOlivier Houchard if ( expDiff < 0 ) goto bExpBigger;
87215144b0fSOlivier Houchard if ( aExp == 0xFF ) {
87315144b0fSOlivier Houchard if ( aSig | bSig ) return propagateFloat32NaN( a, b );
87415144b0fSOlivier Houchard float_raise( float_flag_invalid );
87515144b0fSOlivier Houchard return float32_default_nan;
87615144b0fSOlivier Houchard }
87715144b0fSOlivier Houchard if ( aExp == 0 ) {
87815144b0fSOlivier Houchard aExp = 1;
87915144b0fSOlivier Houchard bExp = 1;
88015144b0fSOlivier Houchard }
88115144b0fSOlivier Houchard if ( bSig < aSig ) goto aBigger;
88215144b0fSOlivier Houchard if ( aSig < bSig ) goto bBigger;
88315144b0fSOlivier Houchard return packFloat32( float_rounding_mode == float_round_down, 0, 0 );
88415144b0fSOlivier Houchard bExpBigger:
88515144b0fSOlivier Houchard if ( bExp == 0xFF ) {
88615144b0fSOlivier Houchard if ( bSig ) return propagateFloat32NaN( a, b );
88715144b0fSOlivier Houchard return packFloat32( zSign ^ 1, 0xFF, 0 );
88815144b0fSOlivier Houchard }
88915144b0fSOlivier Houchard if ( aExp == 0 ) {
89015144b0fSOlivier Houchard ++expDiff;
89115144b0fSOlivier Houchard }
89215144b0fSOlivier Houchard else {
89315144b0fSOlivier Houchard aSig |= 0x40000000;
89415144b0fSOlivier Houchard }
89515144b0fSOlivier Houchard shift32RightJamming( aSig, - expDiff, &aSig );
89615144b0fSOlivier Houchard bSig |= 0x40000000;
89715144b0fSOlivier Houchard bBigger:
89815144b0fSOlivier Houchard zSig = bSig - aSig;
89915144b0fSOlivier Houchard zExp = bExp;
90015144b0fSOlivier Houchard zSign ^= 1;
90115144b0fSOlivier Houchard goto normalizeRoundAndPack;
90215144b0fSOlivier Houchard aExpBigger:
90315144b0fSOlivier Houchard if ( aExp == 0xFF ) {
90415144b0fSOlivier Houchard if ( aSig ) return propagateFloat32NaN( a, b );
90515144b0fSOlivier Houchard return a;
90615144b0fSOlivier Houchard }
90715144b0fSOlivier Houchard if ( bExp == 0 ) {
90815144b0fSOlivier Houchard --expDiff;
90915144b0fSOlivier Houchard }
91015144b0fSOlivier Houchard else {
91115144b0fSOlivier Houchard bSig |= 0x40000000;
91215144b0fSOlivier Houchard }
91315144b0fSOlivier Houchard shift32RightJamming( bSig, expDiff, &bSig );
91415144b0fSOlivier Houchard aSig |= 0x40000000;
91515144b0fSOlivier Houchard aBigger:
91615144b0fSOlivier Houchard zSig = aSig - bSig;
91715144b0fSOlivier Houchard zExp = aExp;
91815144b0fSOlivier Houchard normalizeRoundAndPack:
91915144b0fSOlivier Houchard --zExp;
92015144b0fSOlivier Houchard return normalizeRoundAndPackFloat32( zSign, zExp, zSig );
92115144b0fSOlivier Houchard
92215144b0fSOlivier Houchard }
92315144b0fSOlivier Houchard
92415144b0fSOlivier Houchard /*
92515144b0fSOlivier Houchard -------------------------------------------------------------------------------
92615144b0fSOlivier Houchard Returns the result of adding the single-precision floating-point values `a'
92715144b0fSOlivier Houchard and `b'. The operation is performed according to the IEC/IEEE Standard for
92815144b0fSOlivier Houchard Binary Floating-Point Arithmetic.
92915144b0fSOlivier Houchard -------------------------------------------------------------------------------
93015144b0fSOlivier Houchard */
float32_add(float32 a,float32 b)93115144b0fSOlivier Houchard float32 float32_add( float32 a, float32 b )
93215144b0fSOlivier Houchard {
93315144b0fSOlivier Houchard flag aSign, bSign;
93415144b0fSOlivier Houchard
93515144b0fSOlivier Houchard aSign = extractFloat32Sign( a );
93615144b0fSOlivier Houchard bSign = extractFloat32Sign( b );
93715144b0fSOlivier Houchard if ( aSign == bSign ) {
93815144b0fSOlivier Houchard return addFloat32Sigs( a, b, aSign );
93915144b0fSOlivier Houchard }
94015144b0fSOlivier Houchard else {
94115144b0fSOlivier Houchard return subFloat32Sigs( a, b, aSign );
94215144b0fSOlivier Houchard }
94315144b0fSOlivier Houchard
94415144b0fSOlivier Houchard }
94515144b0fSOlivier Houchard
94615144b0fSOlivier Houchard /*
94715144b0fSOlivier Houchard -------------------------------------------------------------------------------
94815144b0fSOlivier Houchard Returns the result of subtracting the single-precision floating-point values
94915144b0fSOlivier Houchard `a' and `b'. The operation is performed according to the IEC/IEEE Standard
95015144b0fSOlivier Houchard for Binary Floating-Point Arithmetic.
95115144b0fSOlivier Houchard -------------------------------------------------------------------------------
95215144b0fSOlivier Houchard */
float32_sub(float32 a,float32 b)95315144b0fSOlivier Houchard float32 float32_sub( float32 a, float32 b )
95415144b0fSOlivier Houchard {
95515144b0fSOlivier Houchard flag aSign, bSign;
95615144b0fSOlivier Houchard
95715144b0fSOlivier Houchard aSign = extractFloat32Sign( a );
95815144b0fSOlivier Houchard bSign = extractFloat32Sign( b );
95915144b0fSOlivier Houchard if ( aSign == bSign ) {
96015144b0fSOlivier Houchard return subFloat32Sigs( a, b, aSign );
96115144b0fSOlivier Houchard }
96215144b0fSOlivier Houchard else {
96315144b0fSOlivier Houchard return addFloat32Sigs( a, b, aSign );
96415144b0fSOlivier Houchard }
96515144b0fSOlivier Houchard
96615144b0fSOlivier Houchard }
96715144b0fSOlivier Houchard
96815144b0fSOlivier Houchard /*
96915144b0fSOlivier Houchard -------------------------------------------------------------------------------
97015144b0fSOlivier Houchard Returns the result of multiplying the single-precision floating-point values
97115144b0fSOlivier Houchard `a' and `b'. The operation is performed according to the IEC/IEEE Standard
97215144b0fSOlivier Houchard for Binary Floating-Point Arithmetic.
97315144b0fSOlivier Houchard -------------------------------------------------------------------------------
97415144b0fSOlivier Houchard */
float32_mul(float32 a,float32 b)97515144b0fSOlivier Houchard float32 float32_mul( float32 a, float32 b )
97615144b0fSOlivier Houchard {
97715144b0fSOlivier Houchard flag aSign, bSign, zSign;
97815144b0fSOlivier Houchard int16 aExp, bExp, zExp;
97915144b0fSOlivier Houchard bits32 aSig, bSig, zSig0, zSig1;
98015144b0fSOlivier Houchard
98115144b0fSOlivier Houchard aSig = extractFloat32Frac( a );
98215144b0fSOlivier Houchard aExp = extractFloat32Exp( a );
98315144b0fSOlivier Houchard aSign = extractFloat32Sign( a );
98415144b0fSOlivier Houchard bSig = extractFloat32Frac( b );
98515144b0fSOlivier Houchard bExp = extractFloat32Exp( b );
98615144b0fSOlivier Houchard bSign = extractFloat32Sign( b );
98715144b0fSOlivier Houchard zSign = aSign ^ bSign;
98815144b0fSOlivier Houchard if ( aExp == 0xFF ) {
98915144b0fSOlivier Houchard if ( aSig || ( ( bExp == 0xFF ) && bSig ) ) {
99015144b0fSOlivier Houchard return propagateFloat32NaN( a, b );
99115144b0fSOlivier Houchard }
99215144b0fSOlivier Houchard if ( ( bExp | bSig ) == 0 ) {
99315144b0fSOlivier Houchard float_raise( float_flag_invalid );
99415144b0fSOlivier Houchard return float32_default_nan;
99515144b0fSOlivier Houchard }
99615144b0fSOlivier Houchard return packFloat32( zSign, 0xFF, 0 );
99715144b0fSOlivier Houchard }
99815144b0fSOlivier Houchard if ( bExp == 0xFF ) {
99915144b0fSOlivier Houchard if ( bSig ) return propagateFloat32NaN( a, b );
100015144b0fSOlivier Houchard if ( ( aExp | aSig ) == 0 ) {
100115144b0fSOlivier Houchard float_raise( float_flag_invalid );
100215144b0fSOlivier Houchard return float32_default_nan;
100315144b0fSOlivier Houchard }
100415144b0fSOlivier Houchard return packFloat32( zSign, 0xFF, 0 );
100515144b0fSOlivier Houchard }
100615144b0fSOlivier Houchard if ( aExp == 0 ) {
100715144b0fSOlivier Houchard if ( aSig == 0 ) return packFloat32( zSign, 0, 0 );
100815144b0fSOlivier Houchard normalizeFloat32Subnormal( aSig, &aExp, &aSig );
100915144b0fSOlivier Houchard }
101015144b0fSOlivier Houchard if ( bExp == 0 ) {
101115144b0fSOlivier Houchard if ( bSig == 0 ) return packFloat32( zSign, 0, 0 );
101215144b0fSOlivier Houchard normalizeFloat32Subnormal( bSig, &bExp, &bSig );
101315144b0fSOlivier Houchard }
101415144b0fSOlivier Houchard zExp = aExp + bExp - 0x7F;
101515144b0fSOlivier Houchard aSig = ( aSig | 0x00800000 )<<7;
101615144b0fSOlivier Houchard bSig = ( bSig | 0x00800000 )<<8;
101715144b0fSOlivier Houchard mul32To64( aSig, bSig, &zSig0, &zSig1 );
101815144b0fSOlivier Houchard zSig0 |= ( zSig1 != 0 );
101915144b0fSOlivier Houchard if ( 0 <= (sbits32) ( zSig0<<1 ) ) {
102015144b0fSOlivier Houchard zSig0 <<= 1;
102115144b0fSOlivier Houchard --zExp;
102215144b0fSOlivier Houchard }
102315144b0fSOlivier Houchard return roundAndPackFloat32( zSign, zExp, zSig0 );
102415144b0fSOlivier Houchard
102515144b0fSOlivier Houchard }
102615144b0fSOlivier Houchard
102715144b0fSOlivier Houchard /*
102815144b0fSOlivier Houchard -------------------------------------------------------------------------------
102915144b0fSOlivier Houchard Returns the result of dividing the single-precision floating-point value `a'
103015144b0fSOlivier Houchard by the corresponding value `b'. The operation is performed according to the
103115144b0fSOlivier Houchard IEC/IEEE Standard for Binary Floating-Point Arithmetic.
103215144b0fSOlivier Houchard -------------------------------------------------------------------------------
103315144b0fSOlivier Houchard */
float32_div(float32 a,float32 b)103415144b0fSOlivier Houchard float32 float32_div( float32 a, float32 b )
103515144b0fSOlivier Houchard {
103615144b0fSOlivier Houchard flag aSign, bSign, zSign;
103715144b0fSOlivier Houchard int16 aExp, bExp, zExp;
103815144b0fSOlivier Houchard bits32 aSig, bSig, zSig, rem0, rem1, term0, term1;
103915144b0fSOlivier Houchard
104015144b0fSOlivier Houchard aSig = extractFloat32Frac( a );
104115144b0fSOlivier Houchard aExp = extractFloat32Exp( a );
104215144b0fSOlivier Houchard aSign = extractFloat32Sign( a );
104315144b0fSOlivier Houchard bSig = extractFloat32Frac( b );
104415144b0fSOlivier Houchard bExp = extractFloat32Exp( b );
104515144b0fSOlivier Houchard bSign = extractFloat32Sign( b );
104615144b0fSOlivier Houchard zSign = aSign ^ bSign;
104715144b0fSOlivier Houchard if ( aExp == 0xFF ) {
104815144b0fSOlivier Houchard if ( aSig ) return propagateFloat32NaN( a, b );
104915144b0fSOlivier Houchard if ( bExp == 0xFF ) {
105015144b0fSOlivier Houchard if ( bSig ) return propagateFloat32NaN( a, b );
105115144b0fSOlivier Houchard float_raise( float_flag_invalid );
105215144b0fSOlivier Houchard return float32_default_nan;
105315144b0fSOlivier Houchard }
105415144b0fSOlivier Houchard return packFloat32( zSign, 0xFF, 0 );
105515144b0fSOlivier Houchard }
105615144b0fSOlivier Houchard if ( bExp == 0xFF ) {
105715144b0fSOlivier Houchard if ( bSig ) return propagateFloat32NaN( a, b );
105815144b0fSOlivier Houchard return packFloat32( zSign, 0, 0 );
105915144b0fSOlivier Houchard }
106015144b0fSOlivier Houchard if ( bExp == 0 ) {
106115144b0fSOlivier Houchard if ( bSig == 0 ) {
106215144b0fSOlivier Houchard if ( ( aExp | aSig ) == 0 ) {
106315144b0fSOlivier Houchard float_raise( float_flag_invalid );
106415144b0fSOlivier Houchard return float32_default_nan;
106515144b0fSOlivier Houchard }
106615144b0fSOlivier Houchard float_raise( float_flag_divbyzero );
106715144b0fSOlivier Houchard return packFloat32( zSign, 0xFF, 0 );
106815144b0fSOlivier Houchard }
106915144b0fSOlivier Houchard normalizeFloat32Subnormal( bSig, &bExp, &bSig );
107015144b0fSOlivier Houchard }
107115144b0fSOlivier Houchard if ( aExp == 0 ) {
107215144b0fSOlivier Houchard if ( aSig == 0 ) return packFloat32( zSign, 0, 0 );
107315144b0fSOlivier Houchard normalizeFloat32Subnormal( aSig, &aExp, &aSig );
107415144b0fSOlivier Houchard }
107515144b0fSOlivier Houchard zExp = aExp - bExp + 0x7D;
107615144b0fSOlivier Houchard aSig = ( aSig | 0x00800000 )<<7;
107715144b0fSOlivier Houchard bSig = ( bSig | 0x00800000 )<<8;
107815144b0fSOlivier Houchard if ( bSig <= ( aSig + aSig ) ) {
107915144b0fSOlivier Houchard aSig >>= 1;
108015144b0fSOlivier Houchard ++zExp;
108115144b0fSOlivier Houchard }
108215144b0fSOlivier Houchard zSig = estimateDiv64To32( aSig, 0, bSig );
108315144b0fSOlivier Houchard if ( ( zSig & 0x3F ) <= 2 ) {
108415144b0fSOlivier Houchard mul32To64( bSig, zSig, &term0, &term1 );
108515144b0fSOlivier Houchard sub64( aSig, 0, term0, term1, &rem0, &rem1 );
108615144b0fSOlivier Houchard while ( (sbits32) rem0 < 0 ) {
108715144b0fSOlivier Houchard --zSig;
108815144b0fSOlivier Houchard add64( rem0, rem1, 0, bSig, &rem0, &rem1 );
108915144b0fSOlivier Houchard }
109015144b0fSOlivier Houchard zSig |= ( rem1 != 0 );
109115144b0fSOlivier Houchard }
109215144b0fSOlivier Houchard return roundAndPackFloat32( zSign, zExp, zSig );
109315144b0fSOlivier Houchard
109415144b0fSOlivier Houchard }
109515144b0fSOlivier Houchard
109615144b0fSOlivier Houchard #ifndef SOFTFLOAT_FOR_GCC
109715144b0fSOlivier Houchard /*
109815144b0fSOlivier Houchard -------------------------------------------------------------------------------
109915144b0fSOlivier Houchard Returns the remainder of the single-precision floating-point value `a'
110015144b0fSOlivier Houchard with respect to the corresponding value `b'. The operation is performed
110115144b0fSOlivier Houchard according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
110215144b0fSOlivier Houchard -------------------------------------------------------------------------------
110315144b0fSOlivier Houchard */
float32_rem(float32 a,float32 b)110415144b0fSOlivier Houchard float32 float32_rem( float32 a, float32 b )
110515144b0fSOlivier Houchard {
110615144b0fSOlivier Houchard flag aSign, bSign, zSign;
110715144b0fSOlivier Houchard int16 aExp, bExp, expDiff;
110815144b0fSOlivier Houchard bits32 aSig, bSig, q, allZero, alternateASig;
110915144b0fSOlivier Houchard sbits32 sigMean;
111015144b0fSOlivier Houchard
111115144b0fSOlivier Houchard aSig = extractFloat32Frac( a );
111215144b0fSOlivier Houchard aExp = extractFloat32Exp( a );
111315144b0fSOlivier Houchard aSign = extractFloat32Sign( a );
111415144b0fSOlivier Houchard bSig = extractFloat32Frac( b );
111515144b0fSOlivier Houchard bExp = extractFloat32Exp( b );
111615144b0fSOlivier Houchard bSign = extractFloat32Sign( b );
111715144b0fSOlivier Houchard if ( aExp == 0xFF ) {
111815144b0fSOlivier Houchard if ( aSig || ( ( bExp == 0xFF ) && bSig ) ) {
111915144b0fSOlivier Houchard return propagateFloat32NaN( a, b );
112015144b0fSOlivier Houchard }
112115144b0fSOlivier Houchard float_raise( float_flag_invalid );
112215144b0fSOlivier Houchard return float32_default_nan;
112315144b0fSOlivier Houchard }
112415144b0fSOlivier Houchard if ( bExp == 0xFF ) {
112515144b0fSOlivier Houchard if ( bSig ) return propagateFloat32NaN( a, b );
112615144b0fSOlivier Houchard return a;
112715144b0fSOlivier Houchard }
112815144b0fSOlivier Houchard if ( bExp == 0 ) {
112915144b0fSOlivier Houchard if ( bSig == 0 ) {
113015144b0fSOlivier Houchard float_raise( float_flag_invalid );
113115144b0fSOlivier Houchard return float32_default_nan;
113215144b0fSOlivier Houchard }
113315144b0fSOlivier Houchard normalizeFloat32Subnormal( bSig, &bExp, &bSig );
113415144b0fSOlivier Houchard }
113515144b0fSOlivier Houchard if ( aExp == 0 ) {
113615144b0fSOlivier Houchard if ( aSig == 0 ) return a;
113715144b0fSOlivier Houchard normalizeFloat32Subnormal( aSig, &aExp, &aSig );
113815144b0fSOlivier Houchard }
113915144b0fSOlivier Houchard expDiff = aExp - bExp;
114015144b0fSOlivier Houchard aSig = ( aSig | 0x00800000 )<<8;
114115144b0fSOlivier Houchard bSig = ( bSig | 0x00800000 )<<8;
114215144b0fSOlivier Houchard if ( expDiff < 0 ) {
114315144b0fSOlivier Houchard if ( expDiff < -1 ) return a;
114415144b0fSOlivier Houchard aSig >>= 1;
114515144b0fSOlivier Houchard }
114615144b0fSOlivier Houchard q = ( bSig <= aSig );
114715144b0fSOlivier Houchard if ( q ) aSig -= bSig;
114815144b0fSOlivier Houchard expDiff -= 32;
114915144b0fSOlivier Houchard while ( 0 < expDiff ) {
115015144b0fSOlivier Houchard q = estimateDiv64To32( aSig, 0, bSig );
115115144b0fSOlivier Houchard q = ( 2 < q ) ? q - 2 : 0;
115215144b0fSOlivier Houchard aSig = - ( ( bSig>>2 ) * q );
115315144b0fSOlivier Houchard expDiff -= 30;
115415144b0fSOlivier Houchard }
115515144b0fSOlivier Houchard expDiff += 32;
115615144b0fSOlivier Houchard if ( 0 < expDiff ) {
115715144b0fSOlivier Houchard q = estimateDiv64To32( aSig, 0, bSig );
115815144b0fSOlivier Houchard q = ( 2 < q ) ? q - 2 : 0;
115915144b0fSOlivier Houchard q >>= 32 - expDiff;
116015144b0fSOlivier Houchard bSig >>= 2;
116115144b0fSOlivier Houchard aSig = ( ( aSig>>1 )<<( expDiff - 1 ) ) - bSig * q;
116215144b0fSOlivier Houchard }
116315144b0fSOlivier Houchard else {
116415144b0fSOlivier Houchard aSig >>= 2;
116515144b0fSOlivier Houchard bSig >>= 2;
116615144b0fSOlivier Houchard }
116715144b0fSOlivier Houchard do {
116815144b0fSOlivier Houchard alternateASig = aSig;
116915144b0fSOlivier Houchard ++q;
117015144b0fSOlivier Houchard aSig -= bSig;
117115144b0fSOlivier Houchard } while ( 0 <= (sbits32) aSig );
117215144b0fSOlivier Houchard sigMean = aSig + alternateASig;
117315144b0fSOlivier Houchard if ( ( sigMean < 0 ) || ( ( sigMean == 0 ) && ( q & 1 ) ) ) {
117415144b0fSOlivier Houchard aSig = alternateASig;
117515144b0fSOlivier Houchard }
117615144b0fSOlivier Houchard zSign = ( (sbits32) aSig < 0 );
117715144b0fSOlivier Houchard if ( zSign ) aSig = - aSig;
117815144b0fSOlivier Houchard return normalizeRoundAndPackFloat32( aSign ^ zSign, bExp, aSig );
117915144b0fSOlivier Houchard
118015144b0fSOlivier Houchard }
118115144b0fSOlivier Houchard #endif
118215144b0fSOlivier Houchard
118315144b0fSOlivier Houchard #ifndef SOFTFLOAT_FOR_GCC
118415144b0fSOlivier Houchard /*
118515144b0fSOlivier Houchard -------------------------------------------------------------------------------
118615144b0fSOlivier Houchard Returns the square root of the single-precision floating-point value `a'.
118715144b0fSOlivier Houchard The operation is performed according to the IEC/IEEE Standard for Binary
118815144b0fSOlivier Houchard Floating-Point Arithmetic.
118915144b0fSOlivier Houchard -------------------------------------------------------------------------------
119015144b0fSOlivier Houchard */
float32_sqrt(float32 a)119115144b0fSOlivier Houchard float32 float32_sqrt( float32 a )
119215144b0fSOlivier Houchard {
119315144b0fSOlivier Houchard flag aSign;
119415144b0fSOlivier Houchard int16 aExp, zExp;
119515144b0fSOlivier Houchard bits32 aSig, zSig, rem0, rem1, term0, term1;
119615144b0fSOlivier Houchard
119715144b0fSOlivier Houchard aSig = extractFloat32Frac( a );
119815144b0fSOlivier Houchard aExp = extractFloat32Exp( a );
119915144b0fSOlivier Houchard aSign = extractFloat32Sign( a );
120015144b0fSOlivier Houchard if ( aExp == 0xFF ) {
120115144b0fSOlivier Houchard if ( aSig ) return propagateFloat32NaN( a, 0 );
120215144b0fSOlivier Houchard if ( ! aSign ) return a;
120315144b0fSOlivier Houchard float_raise( float_flag_invalid );
120415144b0fSOlivier Houchard return float32_default_nan;
120515144b0fSOlivier Houchard }
120615144b0fSOlivier Houchard if ( aSign ) {
120715144b0fSOlivier Houchard if ( ( aExp | aSig ) == 0 ) return a;
120815144b0fSOlivier Houchard float_raise( float_flag_invalid );
120915144b0fSOlivier Houchard return float32_default_nan;
121015144b0fSOlivier Houchard }
121115144b0fSOlivier Houchard if ( aExp == 0 ) {
121215144b0fSOlivier Houchard if ( aSig == 0 ) return 0;
121315144b0fSOlivier Houchard normalizeFloat32Subnormal( aSig, &aExp, &aSig );
121415144b0fSOlivier Houchard }
121515144b0fSOlivier Houchard zExp = ( ( aExp - 0x7F )>>1 ) + 0x7E;
121615144b0fSOlivier Houchard aSig = ( aSig | 0x00800000 )<<8;
121715144b0fSOlivier Houchard zSig = estimateSqrt32( aExp, aSig ) + 2;
121815144b0fSOlivier Houchard if ( ( zSig & 0x7F ) <= 5 ) {
121915144b0fSOlivier Houchard if ( zSig < 2 ) {
122015144b0fSOlivier Houchard zSig = 0x7FFFFFFF;
122115144b0fSOlivier Houchard goto roundAndPack;
122215144b0fSOlivier Houchard }
122315144b0fSOlivier Houchard else {
122415144b0fSOlivier Houchard aSig >>= aExp & 1;
122515144b0fSOlivier Houchard mul32To64( zSig, zSig, &term0, &term1 );
122615144b0fSOlivier Houchard sub64( aSig, 0, term0, term1, &rem0, &rem1 );
122715144b0fSOlivier Houchard while ( (sbits32) rem0 < 0 ) {
122815144b0fSOlivier Houchard --zSig;
122915144b0fSOlivier Houchard shortShift64Left( 0, zSig, 1, &term0, &term1 );
123015144b0fSOlivier Houchard term1 |= 1;
123115144b0fSOlivier Houchard add64( rem0, rem1, term0, term1, &rem0, &rem1 );
123215144b0fSOlivier Houchard }
123315144b0fSOlivier Houchard zSig |= ( ( rem0 | rem1 ) != 0 );
123415144b0fSOlivier Houchard }
123515144b0fSOlivier Houchard }
123615144b0fSOlivier Houchard shift32RightJamming( zSig, 1, &zSig );
123715144b0fSOlivier Houchard roundAndPack:
123815144b0fSOlivier Houchard return roundAndPackFloat32( 0, zExp, zSig );
123915144b0fSOlivier Houchard
124015144b0fSOlivier Houchard }
124115144b0fSOlivier Houchard #endif
124215144b0fSOlivier Houchard
124315144b0fSOlivier Houchard /*
124415144b0fSOlivier Houchard -------------------------------------------------------------------------------
124515144b0fSOlivier Houchard Returns 1 if the single-precision floating-point value `a' is equal to
124615144b0fSOlivier Houchard the corresponding value `b', and 0 otherwise. The comparison is performed
124715144b0fSOlivier Houchard according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
124815144b0fSOlivier Houchard -------------------------------------------------------------------------------
124915144b0fSOlivier Houchard */
float32_eq(float32 a,float32 b)125015144b0fSOlivier Houchard flag float32_eq( float32 a, float32 b )
125115144b0fSOlivier Houchard {
125215144b0fSOlivier Houchard
125315144b0fSOlivier Houchard if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
125415144b0fSOlivier Houchard || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) )
125515144b0fSOlivier Houchard ) {
125615144b0fSOlivier Houchard if ( float32_is_signaling_nan( a ) || float32_is_signaling_nan( b ) ) {
125715144b0fSOlivier Houchard float_raise( float_flag_invalid );
125815144b0fSOlivier Houchard }
125915144b0fSOlivier Houchard return 0;
126015144b0fSOlivier Houchard }
126115144b0fSOlivier Houchard return ( a == b ) || ( (bits32) ( ( a | b )<<1 ) == 0 );
126215144b0fSOlivier Houchard
126315144b0fSOlivier Houchard }
126415144b0fSOlivier Houchard
126515144b0fSOlivier Houchard /*
126615144b0fSOlivier Houchard -------------------------------------------------------------------------------
126715144b0fSOlivier Houchard Returns 1 if the single-precision floating-point value `a' is less than
126815144b0fSOlivier Houchard or equal to the corresponding value `b', and 0 otherwise. The comparison
126915144b0fSOlivier Houchard is performed according to the IEC/IEEE Standard for Binary Floating-Point
127015144b0fSOlivier Houchard Arithmetic.
127115144b0fSOlivier Houchard -------------------------------------------------------------------------------
127215144b0fSOlivier Houchard */
float32_le(float32 a,float32 b)127315144b0fSOlivier Houchard flag float32_le( float32 a, float32 b )
127415144b0fSOlivier Houchard {
127515144b0fSOlivier Houchard flag aSign, bSign;
127615144b0fSOlivier Houchard
127715144b0fSOlivier Houchard if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
127815144b0fSOlivier Houchard || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) )
127915144b0fSOlivier Houchard ) {
128015144b0fSOlivier Houchard float_raise( float_flag_invalid );
128115144b0fSOlivier Houchard return 0;
128215144b0fSOlivier Houchard }
128315144b0fSOlivier Houchard aSign = extractFloat32Sign( a );
128415144b0fSOlivier Houchard bSign = extractFloat32Sign( b );
128515144b0fSOlivier Houchard if ( aSign != bSign ) return aSign || ( (bits32) ( ( a | b )<<1 ) == 0 );
128615144b0fSOlivier Houchard return ( a == b ) || ( aSign ^ ( a < b ) );
128715144b0fSOlivier Houchard
128815144b0fSOlivier Houchard }
128915144b0fSOlivier Houchard
129015144b0fSOlivier Houchard /*
129115144b0fSOlivier Houchard -------------------------------------------------------------------------------
129215144b0fSOlivier Houchard Returns 1 if the single-precision floating-point value `a' is less than
129315144b0fSOlivier Houchard the corresponding value `b', and 0 otherwise. The comparison is performed
129415144b0fSOlivier Houchard according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
129515144b0fSOlivier Houchard -------------------------------------------------------------------------------
129615144b0fSOlivier Houchard */
float32_lt(float32 a,float32 b)129715144b0fSOlivier Houchard flag float32_lt( float32 a, float32 b )
129815144b0fSOlivier Houchard {
129915144b0fSOlivier Houchard flag aSign, bSign;
130015144b0fSOlivier Houchard
130115144b0fSOlivier Houchard if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
130215144b0fSOlivier Houchard || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) )
130315144b0fSOlivier Houchard ) {
130415144b0fSOlivier Houchard float_raise( float_flag_invalid );
130515144b0fSOlivier Houchard return 0;
130615144b0fSOlivier Houchard }
130715144b0fSOlivier Houchard aSign = extractFloat32Sign( a );
130815144b0fSOlivier Houchard bSign = extractFloat32Sign( b );
130915144b0fSOlivier Houchard if ( aSign != bSign ) return aSign && ( (bits32) ( ( a | b )<<1 ) != 0 );
131015144b0fSOlivier Houchard return ( a != b ) && ( aSign ^ ( a < b ) );
131115144b0fSOlivier Houchard
131215144b0fSOlivier Houchard }
131315144b0fSOlivier Houchard
131415144b0fSOlivier Houchard #ifndef SOFTFLOAT_FOR_GCC /* Not needed */
131515144b0fSOlivier Houchard /*
131615144b0fSOlivier Houchard -------------------------------------------------------------------------------
131715144b0fSOlivier Houchard Returns 1 if the single-precision floating-point value `a' is equal to
131815144b0fSOlivier Houchard the corresponding value `b', and 0 otherwise. The invalid exception is
131915144b0fSOlivier Houchard raised if either operand is a NaN. Otherwise, the comparison is performed
132015144b0fSOlivier Houchard according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
132115144b0fSOlivier Houchard -------------------------------------------------------------------------------
132215144b0fSOlivier Houchard */
float32_eq_signaling(float32 a,float32 b)132315144b0fSOlivier Houchard flag float32_eq_signaling( float32 a, float32 b )
132415144b0fSOlivier Houchard {
132515144b0fSOlivier Houchard
132615144b0fSOlivier Houchard if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
132715144b0fSOlivier Houchard || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) )
132815144b0fSOlivier Houchard ) {
132915144b0fSOlivier Houchard float_raise( float_flag_invalid );
133015144b0fSOlivier Houchard return 0;
133115144b0fSOlivier Houchard }
133215144b0fSOlivier Houchard return ( a == b ) || ( (bits32) ( ( a | b )<<1 ) == 0 );
133315144b0fSOlivier Houchard
133415144b0fSOlivier Houchard }
133515144b0fSOlivier Houchard
133615144b0fSOlivier Houchard /*
133715144b0fSOlivier Houchard -------------------------------------------------------------------------------
133815144b0fSOlivier Houchard Returns 1 if the single-precision floating-point value `a' is less than or
133915144b0fSOlivier Houchard equal to the corresponding value `b', and 0 otherwise. Quiet NaNs do not
134015144b0fSOlivier Houchard cause an exception. Otherwise, the comparison is performed according to the
134115144b0fSOlivier Houchard IEC/IEEE Standard for Binary Floating-Point Arithmetic.
134215144b0fSOlivier Houchard -------------------------------------------------------------------------------
134315144b0fSOlivier Houchard */
float32_le_quiet(float32 a,float32 b)134415144b0fSOlivier Houchard flag float32_le_quiet( float32 a, float32 b )
134515144b0fSOlivier Houchard {
134615144b0fSOlivier Houchard flag aSign, bSign;
134715144b0fSOlivier Houchard int16 aExp, bExp;
134815144b0fSOlivier Houchard
134915144b0fSOlivier Houchard if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
135015144b0fSOlivier Houchard || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) )
135115144b0fSOlivier Houchard ) {
135215144b0fSOlivier Houchard if ( float32_is_signaling_nan( a ) || float32_is_signaling_nan( b ) ) {
135315144b0fSOlivier Houchard float_raise( float_flag_invalid );
135415144b0fSOlivier Houchard }
135515144b0fSOlivier Houchard return 0;
135615144b0fSOlivier Houchard }
135715144b0fSOlivier Houchard aSign = extractFloat32Sign( a );
135815144b0fSOlivier Houchard bSign = extractFloat32Sign( b );
135915144b0fSOlivier Houchard if ( aSign != bSign ) return aSign || ( (bits32) ( ( a | b )<<1 ) == 0 );
136015144b0fSOlivier Houchard return ( a == b ) || ( aSign ^ ( a < b ) );
136115144b0fSOlivier Houchard
136215144b0fSOlivier Houchard }
136315144b0fSOlivier Houchard
136415144b0fSOlivier Houchard /*
136515144b0fSOlivier Houchard -------------------------------------------------------------------------------
136615144b0fSOlivier Houchard Returns 1 if the single-precision floating-point value `a' is less than
136715144b0fSOlivier Houchard the corresponding value `b', and 0 otherwise. Quiet NaNs do not cause an
136815144b0fSOlivier Houchard exception. Otherwise, the comparison is performed according to the IEC/IEEE
136915144b0fSOlivier Houchard Standard for Binary Floating-Point Arithmetic.
137015144b0fSOlivier Houchard -------------------------------------------------------------------------------
137115144b0fSOlivier Houchard */
float32_lt_quiet(float32 a,float32 b)137215144b0fSOlivier Houchard flag float32_lt_quiet( float32 a, float32 b )
137315144b0fSOlivier Houchard {
137415144b0fSOlivier Houchard flag aSign, bSign;
137515144b0fSOlivier Houchard
137615144b0fSOlivier Houchard if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
137715144b0fSOlivier Houchard || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) )
137815144b0fSOlivier Houchard ) {
137915144b0fSOlivier Houchard if ( float32_is_signaling_nan( a ) || float32_is_signaling_nan( b ) ) {
138015144b0fSOlivier Houchard float_raise( float_flag_invalid );
138115144b0fSOlivier Houchard }
138215144b0fSOlivier Houchard return 0;
138315144b0fSOlivier Houchard }
138415144b0fSOlivier Houchard aSign = extractFloat32Sign( a );
138515144b0fSOlivier Houchard bSign = extractFloat32Sign( b );
138615144b0fSOlivier Houchard if ( aSign != bSign ) return aSign && ( (bits32) ( ( a | b )<<1 ) != 0 );
138715144b0fSOlivier Houchard return ( a != b ) && ( aSign ^ ( a < b ) );
138815144b0fSOlivier Houchard
138915144b0fSOlivier Houchard }
139015144b0fSOlivier Houchard #endif /* !SOFTFLOAT_FOR_GCC */
139115144b0fSOlivier Houchard
139215144b0fSOlivier Houchard #ifndef SOFTFLOAT_FOR_GCC /* Not needed */
139315144b0fSOlivier Houchard /*
139415144b0fSOlivier Houchard -------------------------------------------------------------------------------
139515144b0fSOlivier Houchard Returns the result of converting the double-precision floating-point value
139615144b0fSOlivier Houchard `a' to the 32-bit two's complement integer format. The conversion is
139715144b0fSOlivier Houchard performed according to the IEC/IEEE Standard for Binary Floating-Point
139815144b0fSOlivier Houchard Arithmetic---which means in particular that the conversion is rounded
139915144b0fSOlivier Houchard according to the current rounding mode. If `a' is a NaN, the largest
140015144b0fSOlivier Houchard positive integer is returned. Otherwise, if the conversion overflows, the
140115144b0fSOlivier Houchard largest integer with the same sign as `a' is returned.
140215144b0fSOlivier Houchard -------------------------------------------------------------------------------
140315144b0fSOlivier Houchard */
float64_to_int32(float64 a)140415144b0fSOlivier Houchard int32 float64_to_int32( float64 a )
140515144b0fSOlivier Houchard {
140615144b0fSOlivier Houchard flag aSign;
140715144b0fSOlivier Houchard int16 aExp, shiftCount;
140815144b0fSOlivier Houchard bits32 aSig0, aSig1, absZ, aSigExtra;
140915144b0fSOlivier Houchard int32 z;
141015144b0fSOlivier Houchard int8 roundingMode;
141115144b0fSOlivier Houchard
141215144b0fSOlivier Houchard aSig1 = extractFloat64Frac1( a );
141315144b0fSOlivier Houchard aSig0 = extractFloat64Frac0( a );
141415144b0fSOlivier Houchard aExp = extractFloat64Exp( a );
141515144b0fSOlivier Houchard aSign = extractFloat64Sign( a );
141615144b0fSOlivier Houchard shiftCount = aExp - 0x413;
141715144b0fSOlivier Houchard if ( 0 <= shiftCount ) {
141815144b0fSOlivier Houchard if ( 0x41E < aExp ) {
141915144b0fSOlivier Houchard if ( ( aExp == 0x7FF ) && ( aSig0 | aSig1 ) ) aSign = 0;
142015144b0fSOlivier Houchard goto invalid;
142115144b0fSOlivier Houchard }
142215144b0fSOlivier Houchard shortShift64Left(
142315144b0fSOlivier Houchard aSig0 | 0x00100000, aSig1, shiftCount, &absZ, &aSigExtra );
142415144b0fSOlivier Houchard if ( 0x80000000 < absZ ) goto invalid;
142515144b0fSOlivier Houchard }
142615144b0fSOlivier Houchard else {
142715144b0fSOlivier Houchard aSig1 = ( aSig1 != 0 );
142815144b0fSOlivier Houchard if ( aExp < 0x3FE ) {
142915144b0fSOlivier Houchard aSigExtra = aExp | aSig0 | aSig1;
143015144b0fSOlivier Houchard absZ = 0;
143115144b0fSOlivier Houchard }
143215144b0fSOlivier Houchard else {
143315144b0fSOlivier Houchard aSig0 |= 0x00100000;
143415144b0fSOlivier Houchard aSigExtra = ( aSig0<<( shiftCount & 31 ) ) | aSig1;
143515144b0fSOlivier Houchard absZ = aSig0>>( - shiftCount );
143615144b0fSOlivier Houchard }
143715144b0fSOlivier Houchard }
143815144b0fSOlivier Houchard roundingMode = float_rounding_mode;
143915144b0fSOlivier Houchard if ( roundingMode == float_round_nearest_even ) {
144015144b0fSOlivier Houchard if ( (sbits32) aSigExtra < 0 ) {
144115144b0fSOlivier Houchard ++absZ;
144215144b0fSOlivier Houchard if ( (bits32) ( aSigExtra<<1 ) == 0 ) absZ &= ~1;
144315144b0fSOlivier Houchard }
144415144b0fSOlivier Houchard z = aSign ? - absZ : absZ;
144515144b0fSOlivier Houchard }
144615144b0fSOlivier Houchard else {
144715144b0fSOlivier Houchard aSigExtra = ( aSigExtra != 0 );
144815144b0fSOlivier Houchard if ( aSign ) {
144915144b0fSOlivier Houchard z = - ( absZ
145015144b0fSOlivier Houchard + ( ( roundingMode == float_round_down ) & aSigExtra ) );
145115144b0fSOlivier Houchard }
145215144b0fSOlivier Houchard else {
145315144b0fSOlivier Houchard z = absZ + ( ( roundingMode == float_round_up ) & aSigExtra );
145415144b0fSOlivier Houchard }
145515144b0fSOlivier Houchard }
145615144b0fSOlivier Houchard if ( ( aSign ^ ( z < 0 ) ) && z ) {
145715144b0fSOlivier Houchard invalid:
145815144b0fSOlivier Houchard float_raise( float_flag_invalid );
145915144b0fSOlivier Houchard return aSign ? (sbits32) 0x80000000 : 0x7FFFFFFF;
146015144b0fSOlivier Houchard }
146115144b0fSOlivier Houchard if ( aSigExtra ) float_exception_flags |= float_flag_inexact;
146215144b0fSOlivier Houchard return z;
146315144b0fSOlivier Houchard
146415144b0fSOlivier Houchard }
146515144b0fSOlivier Houchard #endif /* !SOFTFLOAT_FOR_GCC */
146615144b0fSOlivier Houchard
146715144b0fSOlivier Houchard /*
146815144b0fSOlivier Houchard -------------------------------------------------------------------------------
146915144b0fSOlivier Houchard Returns the result of converting the double-precision floating-point value
147015144b0fSOlivier Houchard `a' to the 32-bit two's complement integer format. The conversion is
147115144b0fSOlivier Houchard performed according to the IEC/IEEE Standard for Binary Floating-Point
147215144b0fSOlivier Houchard Arithmetic, except that the conversion is always rounded toward zero.
147315144b0fSOlivier Houchard If `a' is a NaN, the largest positive integer is returned. Otherwise, if
147415144b0fSOlivier Houchard the conversion overflows, the largest integer with the same sign as `a' is
147515144b0fSOlivier Houchard returned.
147615144b0fSOlivier Houchard -------------------------------------------------------------------------------
147715144b0fSOlivier Houchard */
float64_to_int32_round_to_zero(float64 a)147815144b0fSOlivier Houchard int32 float64_to_int32_round_to_zero( float64 a )
147915144b0fSOlivier Houchard {
148015144b0fSOlivier Houchard flag aSign;
148115144b0fSOlivier Houchard int16 aExp, shiftCount;
148215144b0fSOlivier Houchard bits32 aSig0, aSig1, absZ, aSigExtra;
148315144b0fSOlivier Houchard int32 z;
148415144b0fSOlivier Houchard
148515144b0fSOlivier Houchard aSig1 = extractFloat64Frac1( a );
148615144b0fSOlivier Houchard aSig0 = extractFloat64Frac0( a );
148715144b0fSOlivier Houchard aExp = extractFloat64Exp( a );
148815144b0fSOlivier Houchard aSign = extractFloat64Sign( a );
148915144b0fSOlivier Houchard shiftCount = aExp - 0x413;
149015144b0fSOlivier Houchard if ( 0 <= shiftCount ) {
149115144b0fSOlivier Houchard if ( 0x41E < aExp ) {
149215144b0fSOlivier Houchard if ( ( aExp == 0x7FF ) && ( aSig0 | aSig1 ) ) aSign = 0;
149315144b0fSOlivier Houchard goto invalid;
149415144b0fSOlivier Houchard }
149515144b0fSOlivier Houchard shortShift64Left(
149615144b0fSOlivier Houchard aSig0 | 0x00100000, aSig1, shiftCount, &absZ, &aSigExtra );
149715144b0fSOlivier Houchard }
149815144b0fSOlivier Houchard else {
149915144b0fSOlivier Houchard if ( aExp < 0x3FF ) {
150015144b0fSOlivier Houchard if ( aExp | aSig0 | aSig1 ) {
150115144b0fSOlivier Houchard float_exception_flags |= float_flag_inexact;
150215144b0fSOlivier Houchard }
150315144b0fSOlivier Houchard return 0;
150415144b0fSOlivier Houchard }
150515144b0fSOlivier Houchard aSig0 |= 0x00100000;
150615144b0fSOlivier Houchard aSigExtra = ( aSig0<<( shiftCount & 31 ) ) | aSig1;
150715144b0fSOlivier Houchard absZ = aSig0>>( - shiftCount );
150815144b0fSOlivier Houchard }
150915144b0fSOlivier Houchard z = aSign ? - absZ : absZ;
151015144b0fSOlivier Houchard if ( ( aSign ^ ( z < 0 ) ) && z ) {
151115144b0fSOlivier Houchard invalid:
151215144b0fSOlivier Houchard float_raise( float_flag_invalid );
151315144b0fSOlivier Houchard return aSign ? (sbits32) 0x80000000 : 0x7FFFFFFF;
151415144b0fSOlivier Houchard }
151515144b0fSOlivier Houchard if ( aSigExtra ) float_exception_flags |= float_flag_inexact;
151615144b0fSOlivier Houchard return z;
151715144b0fSOlivier Houchard
151815144b0fSOlivier Houchard }
151915144b0fSOlivier Houchard
152015144b0fSOlivier Houchard /*
152115144b0fSOlivier Houchard -------------------------------------------------------------------------------
152215144b0fSOlivier Houchard Returns the result of converting the double-precision floating-point value
152315144b0fSOlivier Houchard `a' to the single-precision floating-point format. The conversion is
152415144b0fSOlivier Houchard performed according to the IEC/IEEE Standard for Binary Floating-Point
152515144b0fSOlivier Houchard Arithmetic.
152615144b0fSOlivier Houchard -------------------------------------------------------------------------------
152715144b0fSOlivier Houchard */
float64_to_float32(float64 a)152815144b0fSOlivier Houchard float32 float64_to_float32( float64 a )
152915144b0fSOlivier Houchard {
153015144b0fSOlivier Houchard flag aSign;
153115144b0fSOlivier Houchard int16 aExp;
153215144b0fSOlivier Houchard bits32 aSig0, aSig1, zSig;
153315144b0fSOlivier Houchard bits32 allZero;
153415144b0fSOlivier Houchard
153515144b0fSOlivier Houchard aSig1 = extractFloat64Frac1( a );
153615144b0fSOlivier Houchard aSig0 = extractFloat64Frac0( a );
153715144b0fSOlivier Houchard aExp = extractFloat64Exp( a );
153815144b0fSOlivier Houchard aSign = extractFloat64Sign( a );
153915144b0fSOlivier Houchard if ( aExp == 0x7FF ) {
154015144b0fSOlivier Houchard if ( aSig0 | aSig1 ) {
154115144b0fSOlivier Houchard return commonNaNToFloat32( float64ToCommonNaN( a ) );
154215144b0fSOlivier Houchard }
154315144b0fSOlivier Houchard return packFloat32( aSign, 0xFF, 0 );
154415144b0fSOlivier Houchard }
154515144b0fSOlivier Houchard shift64RightJamming( aSig0, aSig1, 22, &allZero, &zSig );
154615144b0fSOlivier Houchard if ( aExp ) zSig |= 0x40000000;
154715144b0fSOlivier Houchard return roundAndPackFloat32( aSign, aExp - 0x381, zSig );
154815144b0fSOlivier Houchard
154915144b0fSOlivier Houchard }
155015144b0fSOlivier Houchard
155115144b0fSOlivier Houchard #ifndef SOFTFLOAT_FOR_GCC
155215144b0fSOlivier Houchard /*
155315144b0fSOlivier Houchard -------------------------------------------------------------------------------
155415144b0fSOlivier Houchard Rounds the double-precision floating-point value `a' to an integer,
155515144b0fSOlivier Houchard and returns the result as a double-precision floating-point value. The
155615144b0fSOlivier Houchard operation is performed according to the IEC/IEEE Standard for Binary
155715144b0fSOlivier Houchard Floating-Point Arithmetic.
155815144b0fSOlivier Houchard -------------------------------------------------------------------------------
155915144b0fSOlivier Houchard */
float64_round_to_int(float64 a)156015144b0fSOlivier Houchard float64 float64_round_to_int( float64 a )
156115144b0fSOlivier Houchard {
156215144b0fSOlivier Houchard flag aSign;
156315144b0fSOlivier Houchard int16 aExp;
156415144b0fSOlivier Houchard bits32 lastBitMask, roundBitsMask;
156515144b0fSOlivier Houchard int8 roundingMode;
156615144b0fSOlivier Houchard float64 z;
156715144b0fSOlivier Houchard
156815144b0fSOlivier Houchard aExp = extractFloat64Exp( a );
156915144b0fSOlivier Houchard if ( 0x413 <= aExp ) {
157015144b0fSOlivier Houchard if ( 0x433 <= aExp ) {
157115144b0fSOlivier Houchard if ( ( aExp == 0x7FF )
157215144b0fSOlivier Houchard && ( extractFloat64Frac0( a ) | extractFloat64Frac1( a ) ) ) {
157315144b0fSOlivier Houchard return propagateFloat64NaN( a, a );
157415144b0fSOlivier Houchard }
157515144b0fSOlivier Houchard return a;
157615144b0fSOlivier Houchard }
157715144b0fSOlivier Houchard lastBitMask = 1;
157815144b0fSOlivier Houchard lastBitMask = ( lastBitMask<<( 0x432 - aExp ) )<<1;
157915144b0fSOlivier Houchard roundBitsMask = lastBitMask - 1;
158015144b0fSOlivier Houchard z = a;
158115144b0fSOlivier Houchard roundingMode = float_rounding_mode;
158215144b0fSOlivier Houchard if ( roundingMode == float_round_nearest_even ) {
158315144b0fSOlivier Houchard if ( lastBitMask ) {
158415144b0fSOlivier Houchard add64( z.high, z.low, 0, lastBitMask>>1, &z.high, &z.low );
158515144b0fSOlivier Houchard if ( ( z.low & roundBitsMask ) == 0 ) z.low &= ~ lastBitMask;
158615144b0fSOlivier Houchard }
158715144b0fSOlivier Houchard else {
158815144b0fSOlivier Houchard if ( (sbits32) z.low < 0 ) {
158915144b0fSOlivier Houchard ++z.high;
159015144b0fSOlivier Houchard if ( (bits32) ( z.low<<1 ) == 0 ) z.high &= ~1;
159115144b0fSOlivier Houchard }
159215144b0fSOlivier Houchard }
159315144b0fSOlivier Houchard }
159415144b0fSOlivier Houchard else if ( roundingMode != float_round_to_zero ) {
159515144b0fSOlivier Houchard if ( extractFloat64Sign( z )
159615144b0fSOlivier Houchard ^ ( roundingMode == float_round_up ) ) {
159715144b0fSOlivier Houchard add64( z.high, z.low, 0, roundBitsMask, &z.high, &z.low );
159815144b0fSOlivier Houchard }
159915144b0fSOlivier Houchard }
160015144b0fSOlivier Houchard z.low &= ~ roundBitsMask;
160115144b0fSOlivier Houchard }
160215144b0fSOlivier Houchard else {
160315144b0fSOlivier Houchard if ( aExp <= 0x3FE ) {
160415144b0fSOlivier Houchard if ( ( ( (bits32) ( a.high<<1 ) ) | a.low ) == 0 ) return a;
160515144b0fSOlivier Houchard float_exception_flags |= float_flag_inexact;
160615144b0fSOlivier Houchard aSign = extractFloat64Sign( a );
160715144b0fSOlivier Houchard switch ( float_rounding_mode ) {
160815144b0fSOlivier Houchard case float_round_nearest_even:
160915144b0fSOlivier Houchard if ( ( aExp == 0x3FE )
161015144b0fSOlivier Houchard && ( extractFloat64Frac0( a ) | extractFloat64Frac1( a ) )
161115144b0fSOlivier Houchard ) {
161215144b0fSOlivier Houchard return packFloat64( aSign, 0x3FF, 0, 0 );
161315144b0fSOlivier Houchard }
161415144b0fSOlivier Houchard break;
161515144b0fSOlivier Houchard case float_round_down:
161615144b0fSOlivier Houchard return
161715144b0fSOlivier Houchard aSign ? packFloat64( 1, 0x3FF, 0, 0 )
161815144b0fSOlivier Houchard : packFloat64( 0, 0, 0, 0 );
161915144b0fSOlivier Houchard case float_round_up:
162015144b0fSOlivier Houchard return
162115144b0fSOlivier Houchard aSign ? packFloat64( 1, 0, 0, 0 )
162215144b0fSOlivier Houchard : packFloat64( 0, 0x3FF, 0, 0 );
162315144b0fSOlivier Houchard }
162415144b0fSOlivier Houchard return packFloat64( aSign, 0, 0, 0 );
162515144b0fSOlivier Houchard }
162615144b0fSOlivier Houchard lastBitMask = 1;
162715144b0fSOlivier Houchard lastBitMask <<= 0x413 - aExp;
162815144b0fSOlivier Houchard roundBitsMask = lastBitMask - 1;
162915144b0fSOlivier Houchard z.low = 0;
163015144b0fSOlivier Houchard z.high = a.high;
163115144b0fSOlivier Houchard roundingMode = float_rounding_mode;
163215144b0fSOlivier Houchard if ( roundingMode == float_round_nearest_even ) {
163315144b0fSOlivier Houchard z.high += lastBitMask>>1;
163415144b0fSOlivier Houchard if ( ( ( z.high & roundBitsMask ) | a.low ) == 0 ) {
163515144b0fSOlivier Houchard z.high &= ~ lastBitMask;
163615144b0fSOlivier Houchard }
163715144b0fSOlivier Houchard }
163815144b0fSOlivier Houchard else if ( roundingMode != float_round_to_zero ) {
163915144b0fSOlivier Houchard if ( extractFloat64Sign( z )
164015144b0fSOlivier Houchard ^ ( roundingMode == float_round_up ) ) {
164115144b0fSOlivier Houchard z.high |= ( a.low != 0 );
164215144b0fSOlivier Houchard z.high += roundBitsMask;
164315144b0fSOlivier Houchard }
164415144b0fSOlivier Houchard }
164515144b0fSOlivier Houchard z.high &= ~ roundBitsMask;
164615144b0fSOlivier Houchard }
164715144b0fSOlivier Houchard if ( ( z.low != a.low ) || ( z.high != a.high ) ) {
164815144b0fSOlivier Houchard float_exception_flags |= float_flag_inexact;
164915144b0fSOlivier Houchard }
165015144b0fSOlivier Houchard return z;
165115144b0fSOlivier Houchard
165215144b0fSOlivier Houchard }
165315144b0fSOlivier Houchard #endif
165415144b0fSOlivier Houchard
165515144b0fSOlivier Houchard /*
165615144b0fSOlivier Houchard -------------------------------------------------------------------------------
165715144b0fSOlivier Houchard Returns the result of adding the absolute values of the double-precision
165815144b0fSOlivier Houchard floating-point values `a' and `b'. If `zSign' is 1, the sum is negated
165915144b0fSOlivier Houchard before being returned. `zSign' is ignored if the result is a NaN.
166015144b0fSOlivier Houchard The addition is performed according to the IEC/IEEE Standard for Binary
166115144b0fSOlivier Houchard Floating-Point Arithmetic.
166215144b0fSOlivier Houchard -------------------------------------------------------------------------------
166315144b0fSOlivier Houchard */
addFloat64Sigs(float64 a,float64 b,flag zSign)166415144b0fSOlivier Houchard static float64 addFloat64Sigs( float64 a, float64 b, flag zSign )
166515144b0fSOlivier Houchard {
166615144b0fSOlivier Houchard int16 aExp, bExp, zExp;
166715144b0fSOlivier Houchard bits32 aSig0, aSig1, bSig0, bSig1, zSig0, zSig1, zSig2;
166815144b0fSOlivier Houchard int16 expDiff;
166915144b0fSOlivier Houchard
167015144b0fSOlivier Houchard aSig1 = extractFloat64Frac1( a );
167115144b0fSOlivier Houchard aSig0 = extractFloat64Frac0( a );
167215144b0fSOlivier Houchard aExp = extractFloat64Exp( a );
167315144b0fSOlivier Houchard bSig1 = extractFloat64Frac1( b );
167415144b0fSOlivier Houchard bSig0 = extractFloat64Frac0( b );
167515144b0fSOlivier Houchard bExp = extractFloat64Exp( b );
167615144b0fSOlivier Houchard expDiff = aExp - bExp;
167715144b0fSOlivier Houchard if ( 0 < expDiff ) {
167815144b0fSOlivier Houchard if ( aExp == 0x7FF ) {
167915144b0fSOlivier Houchard if ( aSig0 | aSig1 ) return propagateFloat64NaN( a, b );
168015144b0fSOlivier Houchard return a;
168115144b0fSOlivier Houchard }
168215144b0fSOlivier Houchard if ( bExp == 0 ) {
168315144b0fSOlivier Houchard --expDiff;
168415144b0fSOlivier Houchard }
168515144b0fSOlivier Houchard else {
168615144b0fSOlivier Houchard bSig0 |= 0x00100000;
168715144b0fSOlivier Houchard }
168815144b0fSOlivier Houchard shift64ExtraRightJamming(
168915144b0fSOlivier Houchard bSig0, bSig1, 0, expDiff, &bSig0, &bSig1, &zSig2 );
169015144b0fSOlivier Houchard zExp = aExp;
169115144b0fSOlivier Houchard }
169215144b0fSOlivier Houchard else if ( expDiff < 0 ) {
169315144b0fSOlivier Houchard if ( bExp == 0x7FF ) {
169415144b0fSOlivier Houchard if ( bSig0 | bSig1 ) return propagateFloat64NaN( a, b );
169515144b0fSOlivier Houchard return packFloat64( zSign, 0x7FF, 0, 0 );
169615144b0fSOlivier Houchard }
169715144b0fSOlivier Houchard if ( aExp == 0 ) {
169815144b0fSOlivier Houchard ++expDiff;
169915144b0fSOlivier Houchard }
170015144b0fSOlivier Houchard else {
170115144b0fSOlivier Houchard aSig0 |= 0x00100000;
170215144b0fSOlivier Houchard }
170315144b0fSOlivier Houchard shift64ExtraRightJamming(
170415144b0fSOlivier Houchard aSig0, aSig1, 0, - expDiff, &aSig0, &aSig1, &zSig2 );
170515144b0fSOlivier Houchard zExp = bExp;
170615144b0fSOlivier Houchard }
170715144b0fSOlivier Houchard else {
170815144b0fSOlivier Houchard if ( aExp == 0x7FF ) {
170915144b0fSOlivier Houchard if ( aSig0 | aSig1 | bSig0 | bSig1 ) {
171015144b0fSOlivier Houchard return propagateFloat64NaN( a, b );
171115144b0fSOlivier Houchard }
171215144b0fSOlivier Houchard return a;
171315144b0fSOlivier Houchard }
171415144b0fSOlivier Houchard add64( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1 );
171515144b0fSOlivier Houchard if ( aExp == 0 ) return packFloat64( zSign, 0, zSig0, zSig1 );
171615144b0fSOlivier Houchard zSig2 = 0;
171715144b0fSOlivier Houchard zSig0 |= 0x00200000;
171815144b0fSOlivier Houchard zExp = aExp;
171915144b0fSOlivier Houchard goto shiftRight1;
172015144b0fSOlivier Houchard }
172115144b0fSOlivier Houchard aSig0 |= 0x00100000;
172215144b0fSOlivier Houchard add64( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1 );
172315144b0fSOlivier Houchard --zExp;
172415144b0fSOlivier Houchard if ( zSig0 < 0x00200000 ) goto roundAndPack;
172515144b0fSOlivier Houchard ++zExp;
172615144b0fSOlivier Houchard shiftRight1:
172715144b0fSOlivier Houchard shift64ExtraRightJamming( zSig0, zSig1, zSig2, 1, &zSig0, &zSig1, &zSig2 );
172815144b0fSOlivier Houchard roundAndPack:
172915144b0fSOlivier Houchard return roundAndPackFloat64( zSign, zExp, zSig0, zSig1, zSig2 );
173015144b0fSOlivier Houchard
173115144b0fSOlivier Houchard }
173215144b0fSOlivier Houchard
173315144b0fSOlivier Houchard /*
173415144b0fSOlivier Houchard -------------------------------------------------------------------------------
173515144b0fSOlivier Houchard Returns the result of subtracting the absolute values of the double-
173615144b0fSOlivier Houchard precision floating-point values `a' and `b'. If `zSign' is 1, the
173715144b0fSOlivier Houchard difference is negated before being returned. `zSign' is ignored if the
173815144b0fSOlivier Houchard result is a NaN. The subtraction is performed according to the IEC/IEEE
173915144b0fSOlivier Houchard Standard for Binary Floating-Point Arithmetic.
174015144b0fSOlivier Houchard -------------------------------------------------------------------------------
174115144b0fSOlivier Houchard */
subFloat64Sigs(float64 a,float64 b,flag zSign)174215144b0fSOlivier Houchard static float64 subFloat64Sigs( float64 a, float64 b, flag zSign )
174315144b0fSOlivier Houchard {
174415144b0fSOlivier Houchard int16 aExp, bExp, zExp;
174515144b0fSOlivier Houchard bits32 aSig0, aSig1, bSig0, bSig1, zSig0, zSig1;
174615144b0fSOlivier Houchard int16 expDiff;
174715144b0fSOlivier Houchard
174815144b0fSOlivier Houchard aSig1 = extractFloat64Frac1( a );
174915144b0fSOlivier Houchard aSig0 = extractFloat64Frac0( a );
175015144b0fSOlivier Houchard aExp = extractFloat64Exp( a );
175115144b0fSOlivier Houchard bSig1 = extractFloat64Frac1( b );
175215144b0fSOlivier Houchard bSig0 = extractFloat64Frac0( b );
175315144b0fSOlivier Houchard bExp = extractFloat64Exp( b );
175415144b0fSOlivier Houchard expDiff = aExp - bExp;
175515144b0fSOlivier Houchard shortShift64Left( aSig0, aSig1, 10, &aSig0, &aSig1 );
175615144b0fSOlivier Houchard shortShift64Left( bSig0, bSig1, 10, &bSig0, &bSig1 );
175715144b0fSOlivier Houchard if ( 0 < expDiff ) goto aExpBigger;
175815144b0fSOlivier Houchard if ( expDiff < 0 ) goto bExpBigger;
175915144b0fSOlivier Houchard if ( aExp == 0x7FF ) {
176015144b0fSOlivier Houchard if ( aSig0 | aSig1 | bSig0 | bSig1 ) {
176115144b0fSOlivier Houchard return propagateFloat64NaN( a, b );
176215144b0fSOlivier Houchard }
176315144b0fSOlivier Houchard float_raise( float_flag_invalid );
176415144b0fSOlivier Houchard return float64_default_nan;
176515144b0fSOlivier Houchard }
176615144b0fSOlivier Houchard if ( aExp == 0 ) {
176715144b0fSOlivier Houchard aExp = 1;
176815144b0fSOlivier Houchard bExp = 1;
176915144b0fSOlivier Houchard }
177015144b0fSOlivier Houchard if ( bSig0 < aSig0 ) goto aBigger;
177115144b0fSOlivier Houchard if ( aSig0 < bSig0 ) goto bBigger;
177215144b0fSOlivier Houchard if ( bSig1 < aSig1 ) goto aBigger;
177315144b0fSOlivier Houchard if ( aSig1 < bSig1 ) goto bBigger;
177415144b0fSOlivier Houchard return packFloat64( float_rounding_mode == float_round_down, 0, 0, 0 );
177515144b0fSOlivier Houchard bExpBigger:
177615144b0fSOlivier Houchard if ( bExp == 0x7FF ) {
177715144b0fSOlivier Houchard if ( bSig0 | bSig1 ) return propagateFloat64NaN( a, b );
177815144b0fSOlivier Houchard return packFloat64( zSign ^ 1, 0x7FF, 0, 0 );
177915144b0fSOlivier Houchard }
178015144b0fSOlivier Houchard if ( aExp == 0 ) {
178115144b0fSOlivier Houchard ++expDiff;
178215144b0fSOlivier Houchard }
178315144b0fSOlivier Houchard else {
178415144b0fSOlivier Houchard aSig0 |= 0x40000000;
178515144b0fSOlivier Houchard }
178615144b0fSOlivier Houchard shift64RightJamming( aSig0, aSig1, - expDiff, &aSig0, &aSig1 );
178715144b0fSOlivier Houchard bSig0 |= 0x40000000;
178815144b0fSOlivier Houchard bBigger:
178915144b0fSOlivier Houchard sub64( bSig0, bSig1, aSig0, aSig1, &zSig0, &zSig1 );
179015144b0fSOlivier Houchard zExp = bExp;
179115144b0fSOlivier Houchard zSign ^= 1;
179215144b0fSOlivier Houchard goto normalizeRoundAndPack;
179315144b0fSOlivier Houchard aExpBigger:
179415144b0fSOlivier Houchard if ( aExp == 0x7FF ) {
179515144b0fSOlivier Houchard if ( aSig0 | aSig1 ) return propagateFloat64NaN( a, b );
179615144b0fSOlivier Houchard return a;
179715144b0fSOlivier Houchard }
179815144b0fSOlivier Houchard if ( bExp == 0 ) {
179915144b0fSOlivier Houchard --expDiff;
180015144b0fSOlivier Houchard }
180115144b0fSOlivier Houchard else {
180215144b0fSOlivier Houchard bSig0 |= 0x40000000;
180315144b0fSOlivier Houchard }
180415144b0fSOlivier Houchard shift64RightJamming( bSig0, bSig1, expDiff, &bSig0, &bSig1 );
180515144b0fSOlivier Houchard aSig0 |= 0x40000000;
180615144b0fSOlivier Houchard aBigger:
180715144b0fSOlivier Houchard sub64( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1 );
180815144b0fSOlivier Houchard zExp = aExp;
180915144b0fSOlivier Houchard normalizeRoundAndPack:
181015144b0fSOlivier Houchard --zExp;
181115144b0fSOlivier Houchard return normalizeRoundAndPackFloat64( zSign, zExp - 10, zSig0, zSig1 );
181215144b0fSOlivier Houchard
181315144b0fSOlivier Houchard }
181415144b0fSOlivier Houchard
181515144b0fSOlivier Houchard /*
181615144b0fSOlivier Houchard -------------------------------------------------------------------------------
181715144b0fSOlivier Houchard Returns the result of adding the double-precision floating-point values `a'
181815144b0fSOlivier Houchard and `b'. The operation is performed according to the IEC/IEEE Standard for
181915144b0fSOlivier Houchard Binary Floating-Point Arithmetic.
182015144b0fSOlivier Houchard -------------------------------------------------------------------------------
182115144b0fSOlivier Houchard */
float64_add(float64 a,float64 b)182215144b0fSOlivier Houchard float64 float64_add( float64 a, float64 b )
182315144b0fSOlivier Houchard {
182415144b0fSOlivier Houchard flag aSign, bSign;
182515144b0fSOlivier Houchard
182615144b0fSOlivier Houchard aSign = extractFloat64Sign( a );
182715144b0fSOlivier Houchard bSign = extractFloat64Sign( b );
182815144b0fSOlivier Houchard if ( aSign == bSign ) {
182915144b0fSOlivier Houchard return addFloat64Sigs( a, b, aSign );
183015144b0fSOlivier Houchard }
183115144b0fSOlivier Houchard else {
183215144b0fSOlivier Houchard return subFloat64Sigs( a, b, aSign );
183315144b0fSOlivier Houchard }
183415144b0fSOlivier Houchard
183515144b0fSOlivier Houchard }
183615144b0fSOlivier Houchard
183715144b0fSOlivier Houchard /*
183815144b0fSOlivier Houchard -------------------------------------------------------------------------------
183915144b0fSOlivier Houchard Returns the result of subtracting the double-precision floating-point values
184015144b0fSOlivier Houchard `a' and `b'. The operation is performed according to the IEC/IEEE Standard
184115144b0fSOlivier Houchard for Binary Floating-Point Arithmetic.
184215144b0fSOlivier Houchard -------------------------------------------------------------------------------
184315144b0fSOlivier Houchard */
float64_sub(float64 a,float64 b)184415144b0fSOlivier Houchard float64 float64_sub( float64 a, float64 b )
184515144b0fSOlivier Houchard {
184615144b0fSOlivier Houchard flag aSign, bSign;
184715144b0fSOlivier Houchard
184815144b0fSOlivier Houchard aSign = extractFloat64Sign( a );
184915144b0fSOlivier Houchard bSign = extractFloat64Sign( b );
185015144b0fSOlivier Houchard if ( aSign == bSign ) {
185115144b0fSOlivier Houchard return subFloat64Sigs( a, b, aSign );
185215144b0fSOlivier Houchard }
185315144b0fSOlivier Houchard else {
185415144b0fSOlivier Houchard return addFloat64Sigs( a, b, aSign );
185515144b0fSOlivier Houchard }
185615144b0fSOlivier Houchard
185715144b0fSOlivier Houchard }
185815144b0fSOlivier Houchard
185915144b0fSOlivier Houchard /*
186015144b0fSOlivier Houchard -------------------------------------------------------------------------------
186115144b0fSOlivier Houchard Returns the result of multiplying the double-precision floating-point values
186215144b0fSOlivier Houchard `a' and `b'. The operation is performed according to the IEC/IEEE Standard
186315144b0fSOlivier Houchard for Binary Floating-Point Arithmetic.
186415144b0fSOlivier Houchard -------------------------------------------------------------------------------
186515144b0fSOlivier Houchard */
float64_mul(float64 a,float64 b)186615144b0fSOlivier Houchard float64 float64_mul( float64 a, float64 b )
186715144b0fSOlivier Houchard {
186815144b0fSOlivier Houchard flag aSign, bSign, zSign;
186915144b0fSOlivier Houchard int16 aExp, bExp, zExp;
187015144b0fSOlivier Houchard bits32 aSig0, aSig1, bSig0, bSig1, zSig0, zSig1, zSig2, zSig3;
187115144b0fSOlivier Houchard
187215144b0fSOlivier Houchard aSig1 = extractFloat64Frac1( a );
187315144b0fSOlivier Houchard aSig0 = extractFloat64Frac0( a );
187415144b0fSOlivier Houchard aExp = extractFloat64Exp( a );
187515144b0fSOlivier Houchard aSign = extractFloat64Sign( a );
187615144b0fSOlivier Houchard bSig1 = extractFloat64Frac1( b );
187715144b0fSOlivier Houchard bSig0 = extractFloat64Frac0( b );
187815144b0fSOlivier Houchard bExp = extractFloat64Exp( b );
187915144b0fSOlivier Houchard bSign = extractFloat64Sign( b );
188015144b0fSOlivier Houchard zSign = aSign ^ bSign;
188115144b0fSOlivier Houchard if ( aExp == 0x7FF ) {
188215144b0fSOlivier Houchard if ( ( aSig0 | aSig1 )
188315144b0fSOlivier Houchard || ( ( bExp == 0x7FF ) && ( bSig0 | bSig1 ) ) ) {
188415144b0fSOlivier Houchard return propagateFloat64NaN( a, b );
188515144b0fSOlivier Houchard }
188615144b0fSOlivier Houchard if ( ( bExp | bSig0 | bSig1 ) == 0 ) goto invalid;
188715144b0fSOlivier Houchard return packFloat64( zSign, 0x7FF, 0, 0 );
188815144b0fSOlivier Houchard }
188915144b0fSOlivier Houchard if ( bExp == 0x7FF ) {
189015144b0fSOlivier Houchard if ( bSig0 | bSig1 ) return propagateFloat64NaN( a, b );
189115144b0fSOlivier Houchard if ( ( aExp | aSig0 | aSig1 ) == 0 ) {
189215144b0fSOlivier Houchard invalid:
189315144b0fSOlivier Houchard float_raise( float_flag_invalid );
189415144b0fSOlivier Houchard return float64_default_nan;
189515144b0fSOlivier Houchard }
189615144b0fSOlivier Houchard return packFloat64( zSign, 0x7FF, 0, 0 );
189715144b0fSOlivier Houchard }
189815144b0fSOlivier Houchard if ( aExp == 0 ) {
189915144b0fSOlivier Houchard if ( ( aSig0 | aSig1 ) == 0 ) return packFloat64( zSign, 0, 0, 0 );
190015144b0fSOlivier Houchard normalizeFloat64Subnormal( aSig0, aSig1, &aExp, &aSig0, &aSig1 );
190115144b0fSOlivier Houchard }
190215144b0fSOlivier Houchard if ( bExp == 0 ) {
190315144b0fSOlivier Houchard if ( ( bSig0 | bSig1 ) == 0 ) return packFloat64( zSign, 0, 0, 0 );
190415144b0fSOlivier Houchard normalizeFloat64Subnormal( bSig0, bSig1, &bExp, &bSig0, &bSig1 );
190515144b0fSOlivier Houchard }
190615144b0fSOlivier Houchard zExp = aExp + bExp - 0x400;
190715144b0fSOlivier Houchard aSig0 |= 0x00100000;
190815144b0fSOlivier Houchard shortShift64Left( bSig0, bSig1, 12, &bSig0, &bSig1 );
190915144b0fSOlivier Houchard mul64To128( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1, &zSig2, &zSig3 );
191015144b0fSOlivier Houchard add64( zSig0, zSig1, aSig0, aSig1, &zSig0, &zSig1 );
191115144b0fSOlivier Houchard zSig2 |= ( zSig3 != 0 );
191215144b0fSOlivier Houchard if ( 0x00200000 <= zSig0 ) {
191315144b0fSOlivier Houchard shift64ExtraRightJamming(
191415144b0fSOlivier Houchard zSig0, zSig1, zSig2, 1, &zSig0, &zSig1, &zSig2 );
191515144b0fSOlivier Houchard ++zExp;
191615144b0fSOlivier Houchard }
191715144b0fSOlivier Houchard return roundAndPackFloat64( zSign, zExp, zSig0, zSig1, zSig2 );
191815144b0fSOlivier Houchard
191915144b0fSOlivier Houchard }
192015144b0fSOlivier Houchard
192115144b0fSOlivier Houchard /*
192215144b0fSOlivier Houchard -------------------------------------------------------------------------------
192315144b0fSOlivier Houchard Returns the result of dividing the double-precision floating-point value `a'
192415144b0fSOlivier Houchard by the corresponding value `b'. The operation is performed according to the
192515144b0fSOlivier Houchard IEC/IEEE Standard for Binary Floating-Point Arithmetic.
192615144b0fSOlivier Houchard -------------------------------------------------------------------------------
192715144b0fSOlivier Houchard */
float64_div(float64 a,float64 b)192815144b0fSOlivier Houchard float64 float64_div( float64 a, float64 b )
192915144b0fSOlivier Houchard {
193015144b0fSOlivier Houchard flag aSign, bSign, zSign;
193115144b0fSOlivier Houchard int16 aExp, bExp, zExp;
193215144b0fSOlivier Houchard bits32 aSig0, aSig1, bSig0, bSig1, zSig0, zSig1, zSig2;
193315144b0fSOlivier Houchard bits32 rem0, rem1, rem2, rem3, term0, term1, term2, term3;
193415144b0fSOlivier Houchard
193515144b0fSOlivier Houchard aSig1 = extractFloat64Frac1( a );
193615144b0fSOlivier Houchard aSig0 = extractFloat64Frac0( a );
193715144b0fSOlivier Houchard aExp = extractFloat64Exp( a );
193815144b0fSOlivier Houchard aSign = extractFloat64Sign( a );
193915144b0fSOlivier Houchard bSig1 = extractFloat64Frac1( b );
194015144b0fSOlivier Houchard bSig0 = extractFloat64Frac0( b );
194115144b0fSOlivier Houchard bExp = extractFloat64Exp( b );
194215144b0fSOlivier Houchard bSign = extractFloat64Sign( b );
194315144b0fSOlivier Houchard zSign = aSign ^ bSign;
194415144b0fSOlivier Houchard if ( aExp == 0x7FF ) {
194515144b0fSOlivier Houchard if ( aSig0 | aSig1 ) return propagateFloat64NaN( a, b );
194615144b0fSOlivier Houchard if ( bExp == 0x7FF ) {
194715144b0fSOlivier Houchard if ( bSig0 | bSig1 ) return propagateFloat64NaN( a, b );
194815144b0fSOlivier Houchard goto invalid;
194915144b0fSOlivier Houchard }
195015144b0fSOlivier Houchard return packFloat64( zSign, 0x7FF, 0, 0 );
195115144b0fSOlivier Houchard }
195215144b0fSOlivier Houchard if ( bExp == 0x7FF ) {
195315144b0fSOlivier Houchard if ( bSig0 | bSig1 ) return propagateFloat64NaN( a, b );
195415144b0fSOlivier Houchard return packFloat64( zSign, 0, 0, 0 );
195515144b0fSOlivier Houchard }
195615144b0fSOlivier Houchard if ( bExp == 0 ) {
195715144b0fSOlivier Houchard if ( ( bSig0 | bSig1 ) == 0 ) {
195815144b0fSOlivier Houchard if ( ( aExp | aSig0 | aSig1 ) == 0 ) {
195915144b0fSOlivier Houchard invalid:
196015144b0fSOlivier Houchard float_raise( float_flag_invalid );
196115144b0fSOlivier Houchard return float64_default_nan;
196215144b0fSOlivier Houchard }
196315144b0fSOlivier Houchard float_raise( float_flag_divbyzero );
196415144b0fSOlivier Houchard return packFloat64( zSign, 0x7FF, 0, 0 );
196515144b0fSOlivier Houchard }
196615144b0fSOlivier Houchard normalizeFloat64Subnormal( bSig0, bSig1, &bExp, &bSig0, &bSig1 );
196715144b0fSOlivier Houchard }
196815144b0fSOlivier Houchard if ( aExp == 0 ) {
196915144b0fSOlivier Houchard if ( ( aSig0 | aSig1 ) == 0 ) return packFloat64( zSign, 0, 0, 0 );
197015144b0fSOlivier Houchard normalizeFloat64Subnormal( aSig0, aSig1, &aExp, &aSig0, &aSig1 );
197115144b0fSOlivier Houchard }
197215144b0fSOlivier Houchard zExp = aExp - bExp + 0x3FD;
197315144b0fSOlivier Houchard shortShift64Left( aSig0 | 0x00100000, aSig1, 11, &aSig0, &aSig1 );
197415144b0fSOlivier Houchard shortShift64Left( bSig0 | 0x00100000, bSig1, 11, &bSig0, &bSig1 );
197515144b0fSOlivier Houchard if ( le64( bSig0, bSig1, aSig0, aSig1 ) ) {
197615144b0fSOlivier Houchard shift64Right( aSig0, aSig1, 1, &aSig0, &aSig1 );
197715144b0fSOlivier Houchard ++zExp;
197815144b0fSOlivier Houchard }
197915144b0fSOlivier Houchard zSig0 = estimateDiv64To32( aSig0, aSig1, bSig0 );
198015144b0fSOlivier Houchard mul64By32To96( bSig0, bSig1, zSig0, &term0, &term1, &term2 );
198115144b0fSOlivier Houchard sub96( aSig0, aSig1, 0, term0, term1, term2, &rem0, &rem1, &rem2 );
198215144b0fSOlivier Houchard while ( (sbits32) rem0 < 0 ) {
198315144b0fSOlivier Houchard --zSig0;
198415144b0fSOlivier Houchard add96( rem0, rem1, rem2, 0, bSig0, bSig1, &rem0, &rem1, &rem2 );
198515144b0fSOlivier Houchard }
198615144b0fSOlivier Houchard zSig1 = estimateDiv64To32( rem1, rem2, bSig0 );
198715144b0fSOlivier Houchard if ( ( zSig1 & 0x3FF ) <= 4 ) {
198815144b0fSOlivier Houchard mul64By32To96( bSig0, bSig1, zSig1, &term1, &term2, &term3 );
198915144b0fSOlivier Houchard sub96( rem1, rem2, 0, term1, term2, term3, &rem1, &rem2, &rem3 );
199015144b0fSOlivier Houchard while ( (sbits32) rem1 < 0 ) {
199115144b0fSOlivier Houchard --zSig1;
199215144b0fSOlivier Houchard add96( rem1, rem2, rem3, 0, bSig0, bSig1, &rem1, &rem2, &rem3 );
199315144b0fSOlivier Houchard }
199415144b0fSOlivier Houchard zSig1 |= ( ( rem1 | rem2 | rem3 ) != 0 );
199515144b0fSOlivier Houchard }
199615144b0fSOlivier Houchard shift64ExtraRightJamming( zSig0, zSig1, 0, 11, &zSig0, &zSig1, &zSig2 );
199715144b0fSOlivier Houchard return roundAndPackFloat64( zSign, zExp, zSig0, zSig1, zSig2 );
199815144b0fSOlivier Houchard
199915144b0fSOlivier Houchard }
200015144b0fSOlivier Houchard
200115144b0fSOlivier Houchard #ifndef SOFTFLOAT_FOR_GCC
200215144b0fSOlivier Houchard /*
200315144b0fSOlivier Houchard -------------------------------------------------------------------------------
200415144b0fSOlivier Houchard Returns the remainder of the double-precision floating-point value `a'
200515144b0fSOlivier Houchard with respect to the corresponding value `b'. The operation is performed
200615144b0fSOlivier Houchard according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
200715144b0fSOlivier Houchard -------------------------------------------------------------------------------
200815144b0fSOlivier Houchard */
float64_rem(float64 a,float64 b)200915144b0fSOlivier Houchard float64 float64_rem( float64 a, float64 b )
201015144b0fSOlivier Houchard {
201115144b0fSOlivier Houchard flag aSign, bSign, zSign;
201215144b0fSOlivier Houchard int16 aExp, bExp, expDiff;
201315144b0fSOlivier Houchard bits32 aSig0, aSig1, bSig0, bSig1, q, term0, term1, term2;
201415144b0fSOlivier Houchard bits32 allZero, alternateASig0, alternateASig1, sigMean1;
201515144b0fSOlivier Houchard sbits32 sigMean0;
201615144b0fSOlivier Houchard float64 z;
201715144b0fSOlivier Houchard
201815144b0fSOlivier Houchard aSig1 = extractFloat64Frac1( a );
201915144b0fSOlivier Houchard aSig0 = extractFloat64Frac0( a );
202015144b0fSOlivier Houchard aExp = extractFloat64Exp( a );
202115144b0fSOlivier Houchard aSign = extractFloat64Sign( a );
202215144b0fSOlivier Houchard bSig1 = extractFloat64Frac1( b );
202315144b0fSOlivier Houchard bSig0 = extractFloat64Frac0( b );
202415144b0fSOlivier Houchard bExp = extractFloat64Exp( b );
202515144b0fSOlivier Houchard bSign = extractFloat64Sign( b );
202615144b0fSOlivier Houchard if ( aExp == 0x7FF ) {
202715144b0fSOlivier Houchard if ( ( aSig0 | aSig1 )
202815144b0fSOlivier Houchard || ( ( bExp == 0x7FF ) && ( bSig0 | bSig1 ) ) ) {
202915144b0fSOlivier Houchard return propagateFloat64NaN( a, b );
203015144b0fSOlivier Houchard }
203115144b0fSOlivier Houchard goto invalid;
203215144b0fSOlivier Houchard }
203315144b0fSOlivier Houchard if ( bExp == 0x7FF ) {
203415144b0fSOlivier Houchard if ( bSig0 | bSig1 ) return propagateFloat64NaN( a, b );
203515144b0fSOlivier Houchard return a;
203615144b0fSOlivier Houchard }
203715144b0fSOlivier Houchard if ( bExp == 0 ) {
203815144b0fSOlivier Houchard if ( ( bSig0 | bSig1 ) == 0 ) {
203915144b0fSOlivier Houchard invalid:
204015144b0fSOlivier Houchard float_raise( float_flag_invalid );
204115144b0fSOlivier Houchard return float64_default_nan;
204215144b0fSOlivier Houchard }
204315144b0fSOlivier Houchard normalizeFloat64Subnormal( bSig0, bSig1, &bExp, &bSig0, &bSig1 );
204415144b0fSOlivier Houchard }
204515144b0fSOlivier Houchard if ( aExp == 0 ) {
204615144b0fSOlivier Houchard if ( ( aSig0 | aSig1 ) == 0 ) return a;
204715144b0fSOlivier Houchard normalizeFloat64Subnormal( aSig0, aSig1, &aExp, &aSig0, &aSig1 );
204815144b0fSOlivier Houchard }
204915144b0fSOlivier Houchard expDiff = aExp - bExp;
205015144b0fSOlivier Houchard if ( expDiff < -1 ) return a;
205115144b0fSOlivier Houchard shortShift64Left(
205215144b0fSOlivier Houchard aSig0 | 0x00100000, aSig1, 11 - ( expDiff < 0 ), &aSig0, &aSig1 );
205315144b0fSOlivier Houchard shortShift64Left( bSig0 | 0x00100000, bSig1, 11, &bSig0, &bSig1 );
205415144b0fSOlivier Houchard q = le64( bSig0, bSig1, aSig0, aSig1 );
205515144b0fSOlivier Houchard if ( q ) sub64( aSig0, aSig1, bSig0, bSig1, &aSig0, &aSig1 );
205615144b0fSOlivier Houchard expDiff -= 32;
205715144b0fSOlivier Houchard while ( 0 < expDiff ) {
205815144b0fSOlivier Houchard q = estimateDiv64To32( aSig0, aSig1, bSig0 );
205915144b0fSOlivier Houchard q = ( 4 < q ) ? q - 4 : 0;
206015144b0fSOlivier Houchard mul64By32To96( bSig0, bSig1, q, &term0, &term1, &term2 );
206115144b0fSOlivier Houchard shortShift96Left( term0, term1, term2, 29, &term1, &term2, &allZero );
206215144b0fSOlivier Houchard shortShift64Left( aSig0, aSig1, 29, &aSig0, &allZero );
206315144b0fSOlivier Houchard sub64( aSig0, 0, term1, term2, &aSig0, &aSig1 );
206415144b0fSOlivier Houchard expDiff -= 29;
206515144b0fSOlivier Houchard }
206615144b0fSOlivier Houchard if ( -32 < expDiff ) {
206715144b0fSOlivier Houchard q = estimateDiv64To32( aSig0, aSig1, bSig0 );
206815144b0fSOlivier Houchard q = ( 4 < q ) ? q - 4 : 0;
206915144b0fSOlivier Houchard q >>= - expDiff;
207015144b0fSOlivier Houchard shift64Right( bSig0, bSig1, 8, &bSig0, &bSig1 );
207115144b0fSOlivier Houchard expDiff += 24;
207215144b0fSOlivier Houchard if ( expDiff < 0 ) {
207315144b0fSOlivier Houchard shift64Right( aSig0, aSig1, - expDiff, &aSig0, &aSig1 );
207415144b0fSOlivier Houchard }
207515144b0fSOlivier Houchard else {
207615144b0fSOlivier Houchard shortShift64Left( aSig0, aSig1, expDiff, &aSig0, &aSig1 );
207715144b0fSOlivier Houchard }
207815144b0fSOlivier Houchard mul64By32To96( bSig0, bSig1, q, &term0, &term1, &term2 );
207915144b0fSOlivier Houchard sub64( aSig0, aSig1, term1, term2, &aSig0, &aSig1 );
208015144b0fSOlivier Houchard }
208115144b0fSOlivier Houchard else {
208215144b0fSOlivier Houchard shift64Right( aSig0, aSig1, 8, &aSig0, &aSig1 );
208315144b0fSOlivier Houchard shift64Right( bSig0, bSig1, 8, &bSig0, &bSig1 );
208415144b0fSOlivier Houchard }
208515144b0fSOlivier Houchard do {
208615144b0fSOlivier Houchard alternateASig0 = aSig0;
208715144b0fSOlivier Houchard alternateASig1 = aSig1;
208815144b0fSOlivier Houchard ++q;
208915144b0fSOlivier Houchard sub64( aSig0, aSig1, bSig0, bSig1, &aSig0, &aSig1 );
209015144b0fSOlivier Houchard } while ( 0 <= (sbits32) aSig0 );
209115144b0fSOlivier Houchard add64(
209215144b0fSOlivier Houchard aSig0, aSig1, alternateASig0, alternateASig1, &sigMean0, &sigMean1 );
209315144b0fSOlivier Houchard if ( ( sigMean0 < 0 )
209415144b0fSOlivier Houchard || ( ( ( sigMean0 | sigMean1 ) == 0 ) && ( q & 1 ) ) ) {
209515144b0fSOlivier Houchard aSig0 = alternateASig0;
209615144b0fSOlivier Houchard aSig1 = alternateASig1;
209715144b0fSOlivier Houchard }
209815144b0fSOlivier Houchard zSign = ( (sbits32) aSig0 < 0 );
209915144b0fSOlivier Houchard if ( zSign ) sub64( 0, 0, aSig0, aSig1, &aSig0, &aSig1 );
210015144b0fSOlivier Houchard return
210115144b0fSOlivier Houchard normalizeRoundAndPackFloat64( aSign ^ zSign, bExp - 4, aSig0, aSig1 );
210215144b0fSOlivier Houchard
210315144b0fSOlivier Houchard }
210415144b0fSOlivier Houchard #endif
210515144b0fSOlivier Houchard
210615144b0fSOlivier Houchard #ifndef SOFTFLOAT_FOR_GCC
210715144b0fSOlivier Houchard /*
210815144b0fSOlivier Houchard -------------------------------------------------------------------------------
210915144b0fSOlivier Houchard Returns the square root of the double-precision floating-point value `a'.
211015144b0fSOlivier Houchard The operation is performed according to the IEC/IEEE Standard for Binary
211115144b0fSOlivier Houchard Floating-Point Arithmetic.
211215144b0fSOlivier Houchard -------------------------------------------------------------------------------
211315144b0fSOlivier Houchard */
float64_sqrt(float64 a)211415144b0fSOlivier Houchard float64 float64_sqrt( float64 a )
211515144b0fSOlivier Houchard {
211615144b0fSOlivier Houchard flag aSign;
211715144b0fSOlivier Houchard int16 aExp, zExp;
211815144b0fSOlivier Houchard bits32 aSig0, aSig1, zSig0, zSig1, zSig2, doubleZSig0;
211915144b0fSOlivier Houchard bits32 rem0, rem1, rem2, rem3, term0, term1, term2, term3;
212015144b0fSOlivier Houchard float64 z;
212115144b0fSOlivier Houchard
212215144b0fSOlivier Houchard aSig1 = extractFloat64Frac1( a );
212315144b0fSOlivier Houchard aSig0 = extractFloat64Frac0( a );
212415144b0fSOlivier Houchard aExp = extractFloat64Exp( a );
212515144b0fSOlivier Houchard aSign = extractFloat64Sign( a );
212615144b0fSOlivier Houchard if ( aExp == 0x7FF ) {
212715144b0fSOlivier Houchard if ( aSig0 | aSig1 ) return propagateFloat64NaN( a, a );
212815144b0fSOlivier Houchard if ( ! aSign ) return a;
212915144b0fSOlivier Houchard goto invalid;
213015144b0fSOlivier Houchard }
213115144b0fSOlivier Houchard if ( aSign ) {
213215144b0fSOlivier Houchard if ( ( aExp | aSig0 | aSig1 ) == 0 ) return a;
213315144b0fSOlivier Houchard invalid:
213415144b0fSOlivier Houchard float_raise( float_flag_invalid );
213515144b0fSOlivier Houchard return float64_default_nan;
213615144b0fSOlivier Houchard }
213715144b0fSOlivier Houchard if ( aExp == 0 ) {
213815144b0fSOlivier Houchard if ( ( aSig0 | aSig1 ) == 0 ) return packFloat64( 0, 0, 0, 0 );
213915144b0fSOlivier Houchard normalizeFloat64Subnormal( aSig0, aSig1, &aExp, &aSig0, &aSig1 );
214015144b0fSOlivier Houchard }
214115144b0fSOlivier Houchard zExp = ( ( aExp - 0x3FF )>>1 ) + 0x3FE;
214215144b0fSOlivier Houchard aSig0 |= 0x00100000;
214315144b0fSOlivier Houchard shortShift64Left( aSig0, aSig1, 11, &term0, &term1 );
214415144b0fSOlivier Houchard zSig0 = ( estimateSqrt32( aExp, term0 )>>1 ) + 1;
214515144b0fSOlivier Houchard if ( zSig0 == 0 ) zSig0 = 0x7FFFFFFF;
214615144b0fSOlivier Houchard doubleZSig0 = zSig0 + zSig0;
214715144b0fSOlivier Houchard shortShift64Left( aSig0, aSig1, 9 - ( aExp & 1 ), &aSig0, &aSig1 );
214815144b0fSOlivier Houchard mul32To64( zSig0, zSig0, &term0, &term1 );
214915144b0fSOlivier Houchard sub64( aSig0, aSig1, term0, term1, &rem0, &rem1 );
215015144b0fSOlivier Houchard while ( (sbits32) rem0 < 0 ) {
215115144b0fSOlivier Houchard --zSig0;
215215144b0fSOlivier Houchard doubleZSig0 -= 2;
215315144b0fSOlivier Houchard add64( rem0, rem1, 0, doubleZSig0 | 1, &rem0, &rem1 );
215415144b0fSOlivier Houchard }
215515144b0fSOlivier Houchard zSig1 = estimateDiv64To32( rem1, 0, doubleZSig0 );
215615144b0fSOlivier Houchard if ( ( zSig1 & 0x1FF ) <= 5 ) {
215715144b0fSOlivier Houchard if ( zSig1 == 0 ) zSig1 = 1;
215815144b0fSOlivier Houchard mul32To64( doubleZSig0, zSig1, &term1, &term2 );
215915144b0fSOlivier Houchard sub64( rem1, 0, term1, term2, &rem1, &rem2 );
216015144b0fSOlivier Houchard mul32To64( zSig1, zSig1, &term2, &term3 );
216115144b0fSOlivier Houchard sub96( rem1, rem2, 0, 0, term2, term3, &rem1, &rem2, &rem3 );
216215144b0fSOlivier Houchard while ( (sbits32) rem1 < 0 ) {
216315144b0fSOlivier Houchard --zSig1;
216415144b0fSOlivier Houchard shortShift64Left( 0, zSig1, 1, &term2, &term3 );
216515144b0fSOlivier Houchard term3 |= 1;
216615144b0fSOlivier Houchard term2 |= doubleZSig0;
216715144b0fSOlivier Houchard add96( rem1, rem2, rem3, 0, term2, term3, &rem1, &rem2, &rem3 );
216815144b0fSOlivier Houchard }
216915144b0fSOlivier Houchard zSig1 |= ( ( rem1 | rem2 | rem3 ) != 0 );
217015144b0fSOlivier Houchard }
217115144b0fSOlivier Houchard shift64ExtraRightJamming( zSig0, zSig1, 0, 10, &zSig0, &zSig1, &zSig2 );
217215144b0fSOlivier Houchard return roundAndPackFloat64( 0, zExp, zSig0, zSig1, zSig2 );
217315144b0fSOlivier Houchard
217415144b0fSOlivier Houchard }
217515144b0fSOlivier Houchard #endif
217615144b0fSOlivier Houchard
217715144b0fSOlivier Houchard /*
217815144b0fSOlivier Houchard -------------------------------------------------------------------------------
217915144b0fSOlivier Houchard Returns 1 if the double-precision floating-point value `a' is equal to
218015144b0fSOlivier Houchard the corresponding value `b', and 0 otherwise. The comparison is performed
218115144b0fSOlivier Houchard according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
218215144b0fSOlivier Houchard -------------------------------------------------------------------------------
218315144b0fSOlivier Houchard */
float64_eq(float64 a,float64 b)218415144b0fSOlivier Houchard flag float64_eq( float64 a, float64 b )
218515144b0fSOlivier Houchard {
218615144b0fSOlivier Houchard
218715144b0fSOlivier Houchard if ( ( ( extractFloat64Exp( a ) == 0x7FF )
218815144b0fSOlivier Houchard && ( extractFloat64Frac0( a ) | extractFloat64Frac1( a ) ) )
218915144b0fSOlivier Houchard || ( ( extractFloat64Exp( b ) == 0x7FF )
219015144b0fSOlivier Houchard && ( extractFloat64Frac0( b ) | extractFloat64Frac1( b ) ) )
219115144b0fSOlivier Houchard ) {
219215144b0fSOlivier Houchard if ( float64_is_signaling_nan( a ) || float64_is_signaling_nan( b ) ) {
219315144b0fSOlivier Houchard float_raise( float_flag_invalid );
219415144b0fSOlivier Houchard }
219515144b0fSOlivier Houchard return 0;
219615144b0fSOlivier Houchard }
219715144b0fSOlivier Houchard return ( a == b ) ||
219815144b0fSOlivier Houchard ( (bits64) ( ( FLOAT64_DEMANGLE(a) | FLOAT64_DEMANGLE(b) )<<1 ) == 0 );
219915144b0fSOlivier Houchard
220015144b0fSOlivier Houchard }
220115144b0fSOlivier Houchard
220215144b0fSOlivier Houchard /*
220315144b0fSOlivier Houchard -------------------------------------------------------------------------------
220415144b0fSOlivier Houchard Returns 1 if the double-precision floating-point value `a' is less than
220515144b0fSOlivier Houchard or equal to the corresponding value `b', and 0 otherwise. The comparison
220615144b0fSOlivier Houchard is performed according to the IEC/IEEE Standard for Binary Floating-Point
220715144b0fSOlivier Houchard Arithmetic.
220815144b0fSOlivier Houchard -------------------------------------------------------------------------------
220915144b0fSOlivier Houchard */
float64_le(float64 a,float64 b)221015144b0fSOlivier Houchard flag float64_le( float64 a, float64 b )
221115144b0fSOlivier Houchard {
221215144b0fSOlivier Houchard flag aSign, bSign;
221315144b0fSOlivier Houchard
221415144b0fSOlivier Houchard if ( ( ( extractFloat64Exp( a ) == 0x7FF )
221515144b0fSOlivier Houchard && ( extractFloat64Frac0( a ) | extractFloat64Frac1( a ) ) )
221615144b0fSOlivier Houchard || ( ( extractFloat64Exp( b ) == 0x7FF )
221715144b0fSOlivier Houchard && ( extractFloat64Frac0( b ) | extractFloat64Frac1( b ) ) )
221815144b0fSOlivier Houchard ) {
221915144b0fSOlivier Houchard float_raise( float_flag_invalid );
222015144b0fSOlivier Houchard return 0;
222115144b0fSOlivier Houchard }
222215144b0fSOlivier Houchard aSign = extractFloat64Sign( a );
222315144b0fSOlivier Houchard bSign = extractFloat64Sign( b );
222415144b0fSOlivier Houchard if ( aSign != bSign )
222515144b0fSOlivier Houchard return aSign ||
222615144b0fSOlivier Houchard ( (bits64) ( ( FLOAT64_DEMANGLE(a) | FLOAT64_DEMANGLE(b) )<<1 ) ==
222715144b0fSOlivier Houchard 0 );
222815144b0fSOlivier Houchard return ( a == b ) ||
222915144b0fSOlivier Houchard ( aSign ^ ( FLOAT64_DEMANGLE(a) < FLOAT64_DEMANGLE(b) ) );
223015144b0fSOlivier Houchard }
223115144b0fSOlivier Houchard
223215144b0fSOlivier Houchard /*
223315144b0fSOlivier Houchard -------------------------------------------------------------------------------
223415144b0fSOlivier Houchard Returns 1 if the double-precision floating-point value `a' is less than
223515144b0fSOlivier Houchard the corresponding value `b', and 0 otherwise. The comparison is performed
223615144b0fSOlivier Houchard according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
223715144b0fSOlivier Houchard -------------------------------------------------------------------------------
223815144b0fSOlivier Houchard */
float64_lt(float64 a,float64 b)223915144b0fSOlivier Houchard flag float64_lt( float64 a, float64 b )
224015144b0fSOlivier Houchard {
224115144b0fSOlivier Houchard flag aSign, bSign;
224215144b0fSOlivier Houchard
224315144b0fSOlivier Houchard if ( ( ( extractFloat64Exp( a ) == 0x7FF )
224415144b0fSOlivier Houchard && ( extractFloat64Frac0( a ) | extractFloat64Frac1( a ) ) )
224515144b0fSOlivier Houchard || ( ( extractFloat64Exp( b ) == 0x7FF )
224615144b0fSOlivier Houchard && ( extractFloat64Frac0( b ) | extractFloat64Frac1( b ) ) )
224715144b0fSOlivier Houchard ) {
224815144b0fSOlivier Houchard float_raise( float_flag_invalid );
224915144b0fSOlivier Houchard return 0;
225015144b0fSOlivier Houchard }
225115144b0fSOlivier Houchard aSign = extractFloat64Sign( a );
225215144b0fSOlivier Houchard bSign = extractFloat64Sign( b );
225315144b0fSOlivier Houchard if ( aSign != bSign )
225415144b0fSOlivier Houchard return aSign &&
225515144b0fSOlivier Houchard ( (bits64) ( ( FLOAT64_DEMANGLE(a) | FLOAT64_DEMANGLE(b) )<<1 ) !=
225615144b0fSOlivier Houchard 0 );
225715144b0fSOlivier Houchard return ( a != b ) &&
225815144b0fSOlivier Houchard ( aSign ^ ( FLOAT64_DEMANGLE(a) < FLOAT64_DEMANGLE(b) ) );
225915144b0fSOlivier Houchard
226015144b0fSOlivier Houchard }
226115144b0fSOlivier Houchard
226215144b0fSOlivier Houchard #ifndef SOFTFLOAT_FOR_GCC
226315144b0fSOlivier Houchard /*
226415144b0fSOlivier Houchard -------------------------------------------------------------------------------
226515144b0fSOlivier Houchard Returns 1 if the double-precision floating-point value `a' is equal to
226615144b0fSOlivier Houchard the corresponding value `b', and 0 otherwise. The invalid exception is
226715144b0fSOlivier Houchard raised if either operand is a NaN. Otherwise, the comparison is performed
226815144b0fSOlivier Houchard according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
226915144b0fSOlivier Houchard -------------------------------------------------------------------------------
227015144b0fSOlivier Houchard */
float64_eq_signaling(float64 a,float64 b)227115144b0fSOlivier Houchard flag float64_eq_signaling( float64 a, float64 b )
227215144b0fSOlivier Houchard {
227315144b0fSOlivier Houchard
227415144b0fSOlivier Houchard if ( ( ( extractFloat64Exp( a ) == 0x7FF )
227515144b0fSOlivier Houchard && ( extractFloat64Frac0( a ) | extractFloat64Frac1( a ) ) )
227615144b0fSOlivier Houchard || ( ( extractFloat64Exp( b ) == 0x7FF )
227715144b0fSOlivier Houchard && ( extractFloat64Frac0( b ) | extractFloat64Frac1( b ) ) )
227815144b0fSOlivier Houchard ) {
227915144b0fSOlivier Houchard float_raise( float_flag_invalid );
228015144b0fSOlivier Houchard return 0;
228115144b0fSOlivier Houchard }
228215144b0fSOlivier Houchard return ( a == b ) || ( (bits64) ( ( a | b )<<1 ) == 0 );
228315144b0fSOlivier Houchard
228415144b0fSOlivier Houchard }
228515144b0fSOlivier Houchard
228615144b0fSOlivier Houchard /*
228715144b0fSOlivier Houchard -------------------------------------------------------------------------------
228815144b0fSOlivier Houchard Returns 1 if the double-precision floating-point value `a' is less than or
228915144b0fSOlivier Houchard equal to the corresponding value `b', and 0 otherwise. Quiet NaNs do not
229015144b0fSOlivier Houchard cause an exception. Otherwise, the comparison is performed according to the
229115144b0fSOlivier Houchard IEC/IEEE Standard for Binary Floating-Point Arithmetic.
229215144b0fSOlivier Houchard -------------------------------------------------------------------------------
229315144b0fSOlivier Houchard */
float64_le_quiet(float64 a,float64 b)229415144b0fSOlivier Houchard flag float64_le_quiet( float64 a, float64 b )
229515144b0fSOlivier Houchard {
229615144b0fSOlivier Houchard flag aSign, bSign;
229715144b0fSOlivier Houchard
229815144b0fSOlivier Houchard if ( ( ( extractFloat64Exp( a ) == 0x7FF )
229915144b0fSOlivier Houchard && ( extractFloat64Frac0( a ) | extractFloat64Frac1( a ) ) )
230015144b0fSOlivier Houchard || ( ( extractFloat64Exp( b ) == 0x7FF )
230115144b0fSOlivier Houchard && ( extractFloat64Frac0( b ) | extractFloat64Frac1( b ) ) )
230215144b0fSOlivier Houchard ) {
230315144b0fSOlivier Houchard if ( float64_is_signaling_nan( a ) || float64_is_signaling_nan( b ) ) {
230415144b0fSOlivier Houchard float_raise( float_flag_invalid );
230515144b0fSOlivier Houchard }
230615144b0fSOlivier Houchard return 0;
230715144b0fSOlivier Houchard }
230815144b0fSOlivier Houchard aSign = extractFloat64Sign( a );
230915144b0fSOlivier Houchard bSign = extractFloat64Sign( b );
231015144b0fSOlivier Houchard if ( aSign != bSign ) return aSign || ( (bits64) ( ( a | b )<<1 ) == 0 );
231115144b0fSOlivier Houchard return ( a == b ) || ( aSign ^ ( a < b ) );
231215144b0fSOlivier Houchard
231315144b0fSOlivier Houchard }
231415144b0fSOlivier Houchard
231515144b0fSOlivier Houchard /*
231615144b0fSOlivier Houchard -------------------------------------------------------------------------------
231715144b0fSOlivier Houchard Returns 1 if the double-precision floating-point value `a' is less than
231815144b0fSOlivier Houchard the corresponding value `b', and 0 otherwise. Quiet NaNs do not cause an
231915144b0fSOlivier Houchard exception. Otherwise, the comparison is performed according to the IEC/IEEE
232015144b0fSOlivier Houchard Standard for Binary Floating-Point Arithmetic.
232115144b0fSOlivier Houchard -------------------------------------------------------------------------------
232215144b0fSOlivier Houchard */
float64_lt_quiet(float64 a,float64 b)232315144b0fSOlivier Houchard flag float64_lt_quiet( float64 a, float64 b )
232415144b0fSOlivier Houchard {
232515144b0fSOlivier Houchard flag aSign, bSign;
232615144b0fSOlivier Houchard
232715144b0fSOlivier Houchard if ( ( ( extractFloat64Exp( a ) == 0x7FF )
232815144b0fSOlivier Houchard && ( extractFloat64Frac0( a ) | extractFloat64Frac1( a ) ) )
232915144b0fSOlivier Houchard || ( ( extractFloat64Exp( b ) == 0x7FF )
233015144b0fSOlivier Houchard && ( extractFloat64Frac0( b ) | extractFloat64Frac1( b ) ) )
233115144b0fSOlivier Houchard ) {
233215144b0fSOlivier Houchard if ( float64_is_signaling_nan( a ) || float64_is_signaling_nan( b ) ) {
233315144b0fSOlivier Houchard float_raise( float_flag_invalid );
233415144b0fSOlivier Houchard }
233515144b0fSOlivier Houchard return 0;
233615144b0fSOlivier Houchard }
233715144b0fSOlivier Houchard aSign = extractFloat64Sign( a );
233815144b0fSOlivier Houchard bSign = extractFloat64Sign( b );
233915144b0fSOlivier Houchard if ( aSign != bSign ) return aSign && ( (bits64) ( ( a | b )<<1 ) != 0 );
234015144b0fSOlivier Houchard return ( a != b ) && ( aSign ^ ( a < b ) );
234115144b0fSOlivier Houchard
234215144b0fSOlivier Houchard }
234315144b0fSOlivier Houchard
234415144b0fSOlivier Houchard #endif
2345