| |
| /*============================================================================ |
| |
| This C source file is part of TestFloat, Release 3, a package of programs for |
| testing the correctness of floating-point arithmetic complying with the IEEE |
| Standard for Floating-Point, by John R. Hauser. |
| |
| Copyright 2011, 2012, 2013, 2014 The Regents of the University of California |
| (Regents). All Rights Reserved. Redistribution and use in source and binary |
| forms, with or without modification, are permitted provided that the following |
| conditions are met: |
| |
| Redistributions of source code must retain the above copyright notice, |
| this list of conditions, and the following two paragraphs of disclaimer. |
| Redistributions in binary form must reproduce the above copyright notice, |
| this list of conditions, and the following two paragraphs of disclaimer in the |
| documentation and/or other materials provided with the distribution. Neither |
| the name of the Regents nor the names of its contributors may be used to |
| endorse or promote products derived from this software without specific prior |
| written permission. |
| |
| IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, |
| SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING |
| OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS |
| BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| |
| REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED |
| TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED |
| HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE |
| MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. |
| |
| =============================================================================*/ |
| |
| #include <stdbool.h> |
| #include <stdint.h> |
| #include "platform.h" |
| #include "uint128.h" |
| #include "softfloat.h" |
| #include "slowfloat.h" |
| |
| uint_fast8_t slowfloat_roundingMode; |
| uint_fast8_t slowfloat_detectTininess; |
| uint_fast8_t slowfloat_exceptionFlags; |
| #ifdef EXTFLOAT80 |
| uint_fast8_t slow_extF80_roundingPrecision; |
| #endif |
| |
| union ui32_f32 { uint32_t ui; float32_t f; }; |
| union ui64_f64 { uint64_t ui; float64_t f; }; |
| |
| /*---------------------------------------------------------------------------- |
| *----------------------------------------------------------------------------*/ |
| |
| struct floatX { |
| bool isNaN; |
| bool isInf; |
| bool isZero; |
| bool sign; |
| int_fast32_t exp; |
| struct uint128 sig; |
| }; |
| |
| static const struct floatX floatXNaN = |
| { true, false, false, false, 0, { 0, 0 } }; |
| static const struct floatX floatXPositiveZero = |
| { false, false, true, false, 0, { 0, 0 } }; |
| static const struct floatX floatXNegativeZero = |
| { false, false, true, true, 0, { 0, 0 } }; |
| |
| static |
| void |
| roundFloatXTo24( |
| bool isTiny, struct floatX *xPtr, uint_fast8_t roundingMode, bool exact ) |
| { |
| uint_fast64_t sigX64; |
| uint_fast32_t roundBits; |
| |
| sigX64 = xPtr->sig.v64 | (xPtr->sig.v0 != 0); |
| roundBits = (uint32_t) sigX64; |
| sigX64 -= roundBits; |
| if ( roundBits ) { |
| if ( exact ) slowfloat_exceptionFlags |= softfloat_flag_inexact; |
| if ( isTiny ) slowfloat_exceptionFlags |= softfloat_flag_underflow; |
| switch ( roundingMode ) { |
| case softfloat_round_near_even: |
| if ( roundBits < 0x80000000 ) goto noIncrement; |
| if ( |
| (roundBits == 0x80000000) |
| && ! (sigX64 & UINT64_C( 0x100000000 )) |
| ) { |
| goto noIncrement; |
| } |
| break; |
| case softfloat_round_minMag: |
| goto noIncrement; |
| case softfloat_round_min: |
| if ( ! xPtr->sign ) goto noIncrement; |
| break; |
| case softfloat_round_max: |
| if ( xPtr->sign ) goto noIncrement; |
| break; |
| case softfloat_round_near_maxMag: |
| if ( roundBits < 0x80000000 ) goto noIncrement; |
| break; |
| } |
| sigX64 += UINT64_C( 0x100000000 ); |
| if ( sigX64 == UINT64_C( 0x0100000000000000 ) ) { |
| ++xPtr->exp; |
| sigX64 = UINT64_C( 0x0080000000000000 ); |
| } |
| } |
| noIncrement: |
| xPtr->sig.v64 = sigX64; |
| xPtr->sig.v0 = 0; |
| |
| } |
| |
| static |
| void |
| roundFloatXTo53( |
| bool isTiny, struct floatX *xPtr, uint_fast8_t roundingMode, bool exact ) |
| { |
| uint_fast64_t sigX64; |
| uint_fast8_t roundBits; |
| |
| sigX64 = xPtr->sig.v64 | (xPtr->sig.v0 != 0); |
| roundBits = sigX64 & 7; |
| sigX64 -= roundBits; |
| if ( roundBits ) { |
| if ( exact ) slowfloat_exceptionFlags |= softfloat_flag_inexact; |
| if ( isTiny ) slowfloat_exceptionFlags |= softfloat_flag_underflow; |
| switch ( roundingMode ) { |
| case softfloat_round_near_even: |
| if ( roundBits < 4 ) goto noIncrement; |
| if ( (roundBits == 4) && ! (sigX64 & 8) ) goto noIncrement; |
| break; |
| case softfloat_round_minMag: |
| goto noIncrement; |
| case softfloat_round_min: |
| if ( ! xPtr->sign ) goto noIncrement; |
| break; |
| case softfloat_round_max: |
| if ( xPtr->sign ) goto noIncrement; |
| break; |
| case softfloat_round_near_maxMag: |
| if ( roundBits < 4 ) goto noIncrement; |
| break; |
| } |
| sigX64 += 8; |
| if ( sigX64 == UINT64_C( 0x0100000000000000 ) ) { |
| ++xPtr->exp; |
| sigX64 = UINT64_C( 0x0080000000000000 ); |
| } |
| } |
| noIncrement: |
| xPtr->sig.v64 = sigX64; |
| xPtr->sig.v0 = 0; |
| |
| } |
| |
| static |
| void |
| roundFloatXTo64( |
| bool isTiny, struct floatX *xPtr, uint_fast8_t roundingMode, bool exact ) |
| { |
| uint_fast64_t sigX0; |
| int_fast64_t roundBits; |
| uint_fast64_t sigX64; |
| |
| sigX0 = xPtr->sig.v0; |
| roundBits = sigX0 & UINT64_C( 0x00FFFFFFFFFFFFFF ); |
| sigX0 -= roundBits; |
| if ( roundBits ) { |
| if ( exact ) slowfloat_exceptionFlags |= softfloat_flag_inexact; |
| if ( isTiny ) slowfloat_exceptionFlags |= softfloat_flag_underflow; |
| switch ( roundingMode ) { |
| case softfloat_round_near_even: |
| if ( roundBits < UINT64_C( 0x0080000000000000 ) ) goto noIncrement; |
| if ( |
| (roundBits == UINT64_C( 0x0080000000000000 )) |
| && ! (sigX0 & UINT64_C( 0x0100000000000000 )) |
| ) { |
| goto noIncrement; |
| } |
| break; |
| case softfloat_round_minMag: |
| goto noIncrement; |
| case softfloat_round_min: |
| if ( ! xPtr->sign ) goto noIncrement; |
| break; |
| case softfloat_round_max: |
| if ( xPtr->sign ) goto noIncrement; |
| break; |
| case softfloat_round_near_maxMag: |
| if ( roundBits < UINT64_C( 0x0080000000000000 ) ) goto noIncrement; |
| break; |
| } |
| sigX0 += UINT64_C( 0x0100000000000000 ); |
| sigX64 = xPtr->sig.v64 + ! sigX0; |
| if ( sigX64 == UINT64_C( 0x0100000000000000 ) ) { |
| ++xPtr->exp; |
| sigX64 = UINT64_C( 0x0080000000000000 ); |
| } |
| xPtr->sig.v64 = sigX64; |
| } |
| noIncrement: |
| xPtr->sig.v0 = sigX0; |
| |
| } |
| |
| static |
| void |
| roundFloatXTo113( |
| bool isTiny, struct floatX *xPtr, uint_fast8_t roundingMode, bool exact ) |
| { |
| uint_fast64_t sigX0; |
| int_fast64_t roundBits; |
| uint_fast64_t sigX64; |
| |
| sigX0 = xPtr->sig.v0; |
| roundBits = sigX0 & 0x7F; |
| sigX0 -= roundBits; |
| if ( roundBits ) { |
| if ( exact ) slowfloat_exceptionFlags |= softfloat_flag_inexact; |
| if ( isTiny ) slowfloat_exceptionFlags |= softfloat_flag_underflow; |
| switch ( roundingMode ) { |
| case softfloat_round_near_even: |
| if ( roundBits < 0x40 ) goto noIncrement; |
| if ( (roundBits == 0x40) && ! (sigX0 & 0x80) ) goto noIncrement; |
| break; |
| case softfloat_round_minMag: |
| goto noIncrement; |
| case softfloat_round_min: |
| if ( ! xPtr->sign ) goto noIncrement; |
| break; |
| case softfloat_round_max: |
| if ( xPtr->sign ) goto noIncrement; |
| break; |
| case softfloat_round_near_maxMag: |
| if ( roundBits < 0x40 ) goto noIncrement; |
| break; |
| } |
| sigX0 += 0x80; |
| sigX64 = xPtr->sig.v64 + ! sigX0; |
| if ( sigX64 == UINT64_C( 0x0100000000000000 ) ) { |
| ++xPtr->exp; |
| sigX64 = UINT64_C( 0x0080000000000000 ); |
| } |
| xPtr->sig.v64 = sigX64; |
| } |
| noIncrement: |
| xPtr->sig.v0 = sigX0; |
| |
| } |
| |
| static void ui32ToFloatX( uint_fast32_t a, struct floatX *xPtr ) |
| { |
| uint_fast64_t sig64; |
| int_fast32_t exp; |
| |
| xPtr->isNaN = false; |
| xPtr->isInf = false; |
| xPtr->sign = false; |
| sig64 = a; |
| if ( a ) { |
| xPtr->isZero = false; |
| exp = 31; |
| sig64 <<= 24; |
| while ( sig64 < UINT64_C( 0x0080000000000000 ) ) { |
| --exp; |
| sig64 <<= 1; |
| } |
| xPtr->exp = exp; |
| } else { |
| xPtr->isZero = true; |
| } |
| xPtr->sig.v64 = sig64; |
| xPtr->sig.v0 = 0; |
| |
| } |
| |
| static |
| uint_fast32_t |
| floatXToUI32( |
| const struct floatX *xPtr, uint_fast8_t roundingMode, bool exact ) |
| { |
| uint_fast8_t savedExceptionFlags; |
| struct floatX x; |
| int_fast32_t shiftCount; |
| uint_fast32_t z; |
| |
| if ( xPtr->isInf || xPtr->isNaN ) { |
| slowfloat_exceptionFlags |= softfloat_flag_invalid; |
| return 0xFFFFFFFF; |
| } |
| if ( xPtr->isZero ) return 0; |
| savedExceptionFlags = slowfloat_exceptionFlags; |
| x = *xPtr; |
| shiftCount = 52 - x.exp; |
| if ( 56 < shiftCount ) { |
| x.sig.v64 = 0; |
| x.sig.v0 = 1; |
| } else { |
| while ( 0 < shiftCount ) { |
| x.sig = shortShiftRightJam128( x.sig, 1 ); |
| --shiftCount; |
| } |
| } |
| roundFloatXTo53( false, &x, roundingMode, exact ); |
| x.sig = shortShiftRightJam128( x.sig, 3 ); |
| z = x.sig.v64; |
| if ( (shiftCount < 0) || x.sig.v64>>32 || (x.sign && z) ) { |
| slowfloat_exceptionFlags = |
| savedExceptionFlags | softfloat_flag_invalid; |
| return 0xFFFFFFFF; |
| } |
| return z; |
| |
| } |
| |
| static void ui64ToFloatX( uint_fast64_t a, struct floatX *xPtr ) |
| { |
| struct uint128 sig; |
| int_fast32_t exp; |
| |
| xPtr->isNaN = false; |
| xPtr->isInf = false; |
| xPtr->sign = false; |
| sig.v64 = 0; |
| sig.v0 = a; |
| if ( a ) { |
| xPtr->isZero = false; |
| exp = 63; |
| sig = shortShiftLeft128( sig, 56 ); |
| while ( sig.v64 < UINT64_C( 0x0080000000000000 ) ) { |
| --exp; |
| sig = shortShiftLeft128( sig, 1 ); |
| } |
| xPtr->exp = exp; |
| } else { |
| xPtr->isZero = true; |
| } |
| xPtr->sig = sig; |
| |
| } |
| |
| static |
| uint_fast64_t |
| floatXToUI64( |
| const struct floatX *xPtr, uint_fast8_t roundingMode, bool exact ) |
| { |
| uint_fast8_t savedExceptionFlags; |
| struct floatX x; |
| int_fast32_t shiftCount; |
| uint_fast64_t z; |
| |
| if ( xPtr->isInf || xPtr->isNaN ) { |
| slowfloat_exceptionFlags |= softfloat_flag_invalid; |
| return UINT64_C( 0xFFFFFFFFFFFFFFFF ); |
| } |
| if ( xPtr->isZero ) return 0; |
| savedExceptionFlags = slowfloat_exceptionFlags; |
| x = *xPtr; |
| shiftCount = 112 - x.exp; |
| if ( 116 < shiftCount ) { |
| x.sig.v64 = 0; |
| x.sig.v0 = 1; |
| } else { |
| while ( 0 < shiftCount ) { |
| x.sig = shortShiftRightJam128( x.sig, 1 ); |
| --shiftCount; |
| } |
| } |
| roundFloatXTo113( false, &x, roundingMode, exact ); |
| x.sig = shortShiftRightJam128( x.sig, 7 ); |
| z = x.sig.v0; |
| if ( (shiftCount < 0) || x.sig.v64 || (x.sign && z) ) { |
| slowfloat_exceptionFlags = |
| savedExceptionFlags | softfloat_flag_invalid; |
| return UINT64_C( 0xFFFFFFFFFFFFFFFF ); |
| } |
| return z; |
| |
| } |
| |
| static void i32ToFloatX( int_fast32_t a, struct floatX *xPtr ) |
| { |
| bool sign; |
| uint_fast64_t sig64; |
| int_fast32_t exp; |
| |
| xPtr->isNaN = false; |
| xPtr->isInf = false; |
| sign = (a < 0); |
| xPtr->sign = sign; |
| sig64 = sign ? -(uint64_t) a : a; |
| if ( a ) { |
| xPtr->isZero = false; |
| exp = 31; |
| sig64 <<= 24; |
| while ( sig64 < UINT64_C( 0x0080000000000000 ) ) { |
| --exp; |
| sig64 <<= 1; |
| } |
| xPtr->exp = exp; |
| } else { |
| xPtr->isZero = true; |
| } |
| xPtr->sig.v64 = sig64; |
| xPtr->sig.v0 = 0; |
| |
| } |
| |
| static |
| int_fast32_t |
| floatXToI32( |
| const struct floatX *xPtr, uint_fast8_t roundingMode, bool exact ) |
| { |
| uint_fast8_t savedExceptionFlags; |
| struct floatX x; |
| int_fast32_t shiftCount; |
| union { uint32_t ui; int32_t i; } uZ; |
| |
| if ( xPtr->isInf || xPtr->isNaN ) { |
| slowfloat_exceptionFlags |= softfloat_flag_invalid; |
| return (xPtr->isInf & xPtr->sign) ? -0x7FFFFFFF - 1 : 0x7FFFFFFF; |
| } |
| if ( xPtr->isZero ) return 0; |
| savedExceptionFlags = slowfloat_exceptionFlags; |
| x = *xPtr; |
| shiftCount = 52 - x.exp; |
| if ( 56 < shiftCount ) { |
| x.sig.v64 = 0; |
| x.sig.v0 = 1; |
| } else { |
| while ( 0 < shiftCount ) { |
| x.sig = shortShiftRightJam128( x.sig, 1 ); |
| --shiftCount; |
| } |
| } |
| roundFloatXTo53( false, &x, roundingMode, exact ); |
| x.sig = shortShiftRightJam128( x.sig, 3 ); |
| uZ.ui = x.sig.v64; |
| if ( x.sign ) uZ.ui = -uZ.ui; |
| if ( |
| (shiftCount < 0) || x.sig.v64>>32 |
| || ((uZ.i != 0) && (x.sign != (uZ.i < 0))) |
| ) { |
| slowfloat_exceptionFlags = |
| savedExceptionFlags | softfloat_flag_invalid; |
| return x.sign ? -0x7FFFFFFF - 1 : 0x7FFFFFFF; |
| } |
| return uZ.i; |
| |
| } |
| |
| static void i64ToFloatX( int_fast64_t a, struct floatX *xPtr ) |
| { |
| bool sign; |
| struct uint128 sig; |
| int_fast32_t exp; |
| |
| xPtr->isNaN = false; |
| xPtr->isInf = false; |
| sign = (a < 0); |
| xPtr->sign = sign; |
| sig.v64 = 0; |
| sig.v0 = sign ? -(uint_fast64_t) a : a; |
| if ( a ) { |
| xPtr->isZero = false; |
| exp = 63; |
| sig = shortShiftLeft128( sig, 56 ); |
| while ( sig.v64 < UINT64_C( 0x0080000000000000 ) ) { |
| --exp; |
| sig = shortShiftLeft128( sig, 1 ); |
| } |
| xPtr->exp = exp; |
| } else { |
| xPtr->isZero = true; |
| } |
| xPtr->sig = sig; |
| |
| } |
| |
| static |
| int_fast64_t |
| floatXToI64( |
| const struct floatX *xPtr, uint_fast8_t roundingMode, bool exact ) |
| { |
| uint_fast8_t savedExceptionFlags; |
| struct floatX x; |
| int_fast32_t shiftCount; |
| union { uint64_t ui; int64_t i; } uZ; |
| |
| if ( xPtr->isInf || xPtr->isNaN ) { |
| slowfloat_exceptionFlags |= softfloat_flag_invalid; |
| return |
| (xPtr->isInf & xPtr->sign) ? -INT64_C( 0x7FFFFFFFFFFFFFFF ) - 1 |
| : INT64_C( 0x7FFFFFFFFFFFFFFF ); |
| } |
| if ( xPtr->isZero ) return 0; |
| savedExceptionFlags = slowfloat_exceptionFlags; |
| x = *xPtr; |
| shiftCount = 112 - x.exp; |
| if ( 116 < shiftCount ) { |
| x.sig.v64 = 0; |
| x.sig.v0 = 1; |
| } else { |
| while ( 0 < shiftCount ) { |
| x.sig = shortShiftRightJam128( x.sig, 1 ); |
| --shiftCount; |
| } |
| } |
| roundFloatXTo113( false, &x, roundingMode, exact ); |
| x.sig = shortShiftRightJam128( x.sig, 7 ); |
| uZ.ui = x.sig.v0; |
| if ( x.sign ) uZ.ui = -uZ.ui; |
| if ( |
| (shiftCount < 0) || x.sig.v64 |
| || ((uZ.i != 0) && (x.sign != (uZ.i < 0))) |
| ) { |
| slowfloat_exceptionFlags = |
| savedExceptionFlags | softfloat_flag_invalid; |
| return |
| x.sign ? -INT64_C( 0x7FFFFFFFFFFFFFFF ) - 1 |
| : INT64_C( 0x7FFFFFFFFFFFFFFF ); |
| } |
| return uZ.i; |
| |
| } |
| |
| static void f32ToFloatX( float32_t a, struct floatX *xPtr ) |
| { |
| union ui32_f32 uA; |
| uint_fast32_t uiA; |
| int_fast16_t exp; |
| uint_fast64_t sig64; |
| |
| uA.f = a; |
| uiA = uA.ui; |
| xPtr->isNaN = false; |
| xPtr->isInf = false; |
| xPtr->isZero = false; |
| xPtr->sign = ((uiA & 0x80000000) != 0); |
| exp = uiA>>23 & 0xFF; |
| sig64 = uiA & 0x007FFFFF; |
| sig64 <<= 32; |
| if ( exp == 0xFF ) { |
| if ( sig64 ) { |
| xPtr->isNaN = true; |
| } else { |
| xPtr->isInf = true; |
| } |
| } else if ( ! exp ) { |
| if ( ! sig64 ) { |
| xPtr->isZero = true; |
| } else { |
| exp = 1 - 0x7F; |
| do { |
| --exp; |
| sig64 <<= 1; |
| } while ( sig64 < UINT64_C( 0x0080000000000000 ) ); |
| xPtr->exp = exp; |
| } |
| } else { |
| xPtr->exp = exp - 0x7F; |
| sig64 |= UINT64_C( 0x0080000000000000 ); |
| } |
| xPtr->sig.v64 = sig64; |
| xPtr->sig.v0 = 0; |
| |
| } |
| |
| static float32_t floatXToF32( const struct floatX *xPtr ) |
| { |
| uint_fast32_t uiZ; |
| struct floatX x, savedX; |
| bool isTiny; |
| int_fast32_t exp; |
| union ui32_f32 uZ; |
| |
| if ( xPtr->isNaN ) { |
| uiZ = 0xFFFFFFFF; |
| goto uiZ; |
| } |
| if ( xPtr->isInf ) { |
| uiZ = xPtr->sign ? 0xFF800000 : 0x7F800000; |
| goto uiZ; |
| } |
| if ( xPtr->isZero ) { |
| uiZ = xPtr->sign ? 0x80000000 : 0; |
| goto uiZ; |
| } |
| x = *xPtr; |
| while ( UINT64_C( 0x0100000000000000 ) <= x.sig.v64 ) { |
| ++x.exp; |
| x.sig = shortShiftRightJam128( x.sig, 1 ); |
| } |
| while ( x.sig.v64 < UINT64_C( 0x0080000000000000 ) ) { |
| --x.exp; |
| x.sig = shortShiftLeft128( x.sig, 1 ); |
| } |
| savedX = x; |
| isTiny = |
| (slowfloat_detectTininess == softfloat_tininess_beforeRounding) |
| && (x.exp + 0x7F <= 0); |
| roundFloatXTo24( isTiny, &x, slowfloat_roundingMode, true ); |
| exp = x.exp + 0x7F; |
| if ( 0xFF <= exp ) { |
| slowfloat_exceptionFlags |= |
| softfloat_flag_overflow | softfloat_flag_inexact; |
| if ( x.sign ) { |
| switch ( slowfloat_roundingMode ) { |
| case softfloat_round_near_even: |
| case softfloat_round_min: |
| case softfloat_round_near_maxMag: |
| uiZ = 0xFF800000; |
| break; |
| case softfloat_round_minMag: |
| case softfloat_round_max: |
| uiZ = 0xFF7FFFFF; |
| break; |
| } |
| } else { |
| switch ( slowfloat_roundingMode ) { |
| case softfloat_round_near_even: |
| case softfloat_round_max: |
| case softfloat_round_near_maxMag: |
| uiZ = 0x7F800000; |
| break; |
| case softfloat_round_minMag: |
| case softfloat_round_min: |
| uiZ = 0x7F7FFFFF; |
| break; |
| } |
| } |
| goto uiZ; |
| } |
| if ( exp <= 0 ) { |
| isTiny = true; |
| x = savedX; |
| exp = x.exp + 0x7F; |
| if ( exp < -27 ) { |
| x.sig.v0 = (x.sig.v64 != 0) || (x.sig.v0 != 0); |
| x.sig.v64 = 0; |
| } else { |
| while ( exp <= 0 ) { |
| ++exp; |
| x.sig = shortShiftRightJam128( x.sig, 1 ); |
| } |
| } |
| roundFloatXTo24( isTiny, &x, slowfloat_roundingMode, true ); |
| exp = (UINT64_C( 0x0080000000000000 ) <= x.sig.v64) ? 1 : 0; |
| } |
| uiZ = (uint_fast32_t) exp<<23; |
| if ( x.sign ) uiZ |= 0x80000000; |
| uiZ |= x.sig.v64>>32 & 0x007FFFFF; |
| uiZ: |
| uZ.ui = uiZ; |
| return uZ.f; |
| |
| } |
| |
| static void f64ToFloatX( float64_t a, struct floatX *xPtr ) |
| { |
| union ui64_f64 uA; |
| uint_fast64_t uiA; |
| int_fast16_t exp; |
| uint_fast64_t sig64; |
| |
| uA.f = a; |
| uiA = uA.ui; |
| xPtr->isNaN = false; |
| xPtr->isInf = false; |
| xPtr->isZero = false; |
| xPtr->sign = ((uiA & UINT64_C( 0x8000000000000000 )) != 0); |
| exp = uiA>>52 & 0x7FF; |
| sig64 = uiA & UINT64_C( 0x000FFFFFFFFFFFFF ); |
| if ( exp == 0x7FF ) { |
| if ( sig64 ) { |
| xPtr->isNaN = true; |
| } else { |
| xPtr->isInf = true; |
| } |
| } else if ( ! exp ) { |
| if ( ! sig64 ) { |
| xPtr->isZero = true; |
| } else { |
| exp = 1 - 0x3FF; |
| do { |
| --exp; |
| sig64 <<= 1; |
| } while ( sig64 < UINT64_C( 0x0010000000000000 ) ); |
| xPtr->exp = exp; |
| } |
| } else { |
| xPtr->exp = exp - 0x3FF; |
| sig64 |= UINT64_C( 0x0010000000000000 ); |
| } |
| xPtr->sig.v64 = sig64<<3; |
| xPtr->sig.v0 = 0; |
| |
| } |
| |
| static float64_t floatXToF64( const struct floatX *xPtr ) |
| { |
| uint_fast64_t uiZ; |
| struct floatX x, savedX; |
| bool isTiny; |
| int_fast32_t exp; |
| union ui64_f64 uZ; |
| |
| if ( xPtr->isNaN ) { |
| uiZ = UINT64_C( 0xFFFFFFFFFFFFFFFF ); |
| goto uiZ; |
| } |
| if ( xPtr->isInf ) { |
| uiZ = |
| xPtr->sign ? UINT64_C( 0xFFF0000000000000 ) |
| : UINT64_C( 0x7FF0000000000000 ); |
| goto uiZ; |
| } |
| if ( xPtr->isZero ) { |
| uiZ = xPtr->sign ? UINT64_C( 0x8000000000000000 ) : 0; |
| goto uiZ; |
| } |
| x = *xPtr; |
| while ( UINT64_C( 0x0100000000000000 ) <= x.sig.v64 ) { |
| ++x.exp; |
| x.sig = shortShiftRightJam128( x.sig, 1 ); |
| } |
| while ( x.sig.v64 < UINT64_C( 0x0080000000000000 ) ) { |
| --x.exp; |
| x.sig = shortShiftLeft128( x.sig, 1 ); |
| } |
| savedX = x; |
| isTiny = |
| (slowfloat_detectTininess == softfloat_tininess_beforeRounding) |
| && (x.exp + 0x3FF <= 0); |
| roundFloatXTo53( isTiny, &x, slowfloat_roundingMode, true ); |
| exp = x.exp + 0x3FF; |
| if ( 0x7FF <= exp ) { |
| slowfloat_exceptionFlags |= |
| softfloat_flag_overflow | softfloat_flag_inexact; |
| if ( x.sign ) { |
| switch ( slowfloat_roundingMode ) { |
| case softfloat_round_near_even: |
| case softfloat_round_min: |
| case softfloat_round_near_maxMag: |
| uiZ = UINT64_C( 0xFFF0000000000000 ); |
| break; |
| case softfloat_round_minMag: |
| case softfloat_round_max: |
| uiZ = UINT64_C( 0xFFEFFFFFFFFFFFFF ); |
| break; |
| } |
| } else { |
| switch ( slowfloat_roundingMode ) { |
| case softfloat_round_near_even: |
| case softfloat_round_max: |
| case softfloat_round_near_maxMag: |
| uiZ = UINT64_C( 0x7FF0000000000000 ); |
| break; |
| case softfloat_round_minMag: |
| case softfloat_round_min: |
| uiZ = UINT64_C( 0x7FEFFFFFFFFFFFFF ); |
| break; |
| } |
| } |
| goto uiZ; |
| } |
| if ( exp <= 0 ) { |
| isTiny = true; |
| x = savedX; |
| exp = x.exp + 0x3FF; |
| if ( exp < -56 ) { |
| x.sig.v0 = (x.sig.v64 != 0) || (x.sig.v0 != 0); |
| x.sig.v64 = 0; |
| } else { |
| while ( exp <= 0 ) { |
| ++exp; |
| x.sig = shortShiftRightJam128( x.sig, 1 ); |
| } |
| } |
| roundFloatXTo53( isTiny, &x, slowfloat_roundingMode, true ); |
| exp = (UINT64_C( 0x0080000000000000 ) <= x.sig.v64) ? 1 : 0; |
| } |
| uiZ = (uint_fast64_t) exp<<52; |
| if ( x.sign ) uiZ |= UINT64_C( 0x8000000000000000 ); |
| uiZ |= x.sig.v64>>3 & UINT64_C( 0x000FFFFFFFFFFFFF ); |
| uiZ: |
| uZ.ui = uiZ; |
| return uZ.f; |
| |
| } |
| |
| #ifdef EXTFLOAT80 |
| |
| static void extF80MToFloatX( const extFloat80_t *aPtr, struct floatX *xPtr ) |
| { |
| const struct extFloat80M *aSPtr; |
| uint_fast16_t uiA64; |
| int_fast32_t exp; |
| struct uint128 sig; |
| |
| aSPtr = (const struct extFloat80M *) aPtr; |
| xPtr->isNaN = false; |
| xPtr->isInf = false; |
| xPtr->isZero = false; |
| uiA64 = aSPtr->signExp; |
| xPtr->sign = ((uiA64 & 0x8000) != 0); |
| exp = uiA64 & 0x7FFF; |
| sig.v64 = 0; |
| sig.v0 = aSPtr->signif; |
| if ( exp == 0x7FFF ) { |
| if ( sig.v0 & UINT64_C( 0x7FFFFFFFFFFFFFFF ) ) { |
| xPtr->isNaN = true; |
| } else { |
| xPtr->isInf = true; |
| } |
| } else { |
| if ( ! exp ) ++exp; |
| exp -= 0x3FFF; |
| if ( ! (sig.v0 & UINT64_C( 0x8000000000000000 )) ) { |
| if ( ! sig.v0 ) { |
| xPtr->isZero = true; |
| } else { |
| do { |
| --exp; |
| sig.v0 <<= 1; |
| } while ( sig.v0 < UINT64_C( 0x8000000000000000 ) ); |
| } |
| } |
| xPtr->exp = exp; |
| } |
| xPtr->sig = shortShiftLeft128( sig, 56 ); |
| |
| } |
| |
| static void floatXToExtF80M( const struct floatX *xPtr, extFloat80_t *zPtr ) |
| { |
| struct extFloat80M *zSPtr; |
| struct floatX x, savedX; |
| bool isTiny; |
| int_fast32_t exp; |
| uint_fast64_t uiZ0; |
| uint_fast16_t uiZ64; |
| |
| zSPtr = (struct extFloat80M *) zPtr; |
| if ( xPtr->isNaN ) { |
| zSPtr->signExp = 0xFFFF; |
| zSPtr->signif = UINT64_C( 0xFFFFFFFFFFFFFFFF ); |
| return; |
| } |
| if ( xPtr->isInf ) { |
| zSPtr->signExp = xPtr->sign ? 0xFFFF : 0x7FFF; |
| zSPtr->signif = UINT64_C( 0x8000000000000000 ); |
| return; |
| } |
| if ( xPtr->isZero ) { |
| zSPtr->signExp = xPtr->sign ? 0x8000 : 0; |
| zSPtr->signif = 0; |
| return; |
| } |
| x = *xPtr; |
| while ( UINT64_C( 0x0100000000000000 ) <= x.sig.v64 ) { |
| ++x.exp; |
| x.sig = shortShiftRightJam128( x.sig, 1 ); |
| } |
| while ( x.sig.v64 < UINT64_C( 0x0080000000000000 ) ) { |
| --x.exp; |
| x.sig = shortShiftLeft128( x.sig, 1 ); |
| } |
| savedX = x; |
| isTiny = |
| (slowfloat_detectTininess == softfloat_tininess_beforeRounding) |
| && (x.exp + 0x3FFF <= 0); |
| switch ( slow_extF80_roundingPrecision ) { |
| case 32: |
| roundFloatXTo24( isTiny, &x, slowfloat_roundingMode, true ); |
| break; |
| case 64: |
| roundFloatXTo53( isTiny, &x, slowfloat_roundingMode, true ); |
| break; |
| default: |
| roundFloatXTo64( isTiny, &x, slowfloat_roundingMode, true ); |
| break; |
| } |
| exp = x.exp + 0x3FFF; |
| if ( 0x7FFF <= exp ) { |
| slowfloat_exceptionFlags |= |
| softfloat_flag_overflow | softfloat_flag_inexact; |
| if ( x.sign ) { |
| switch ( slowfloat_roundingMode ) { |
| case softfloat_round_near_even: |
| case softfloat_round_min: |
| case softfloat_round_near_maxMag: |
| zSPtr->signExp = 0xFFFF; |
| zSPtr->signif = UINT64_C( 0x8000000000000000 ); |
| break; |
| case softfloat_round_minMag: |
| case softfloat_round_max: |
| switch ( slow_extF80_roundingPrecision ) { |
| case 32: |
| uiZ0 = UINT64_C( 0xFFFFFF0000000000 ); |
| break; |
| case 64: |
| uiZ0 = UINT64_C( 0xFFFFFFFFFFFFF800 ); |
| break; |
| default: |
| uiZ0 = UINT64_C( 0xFFFFFFFFFFFFFFFF ); |
| break; |
| } |
| zSPtr->signExp = 0xFFFE; |
| zSPtr->signif = uiZ0; |
| break; |
| } |
| } else { |
| switch ( slowfloat_roundingMode ) { |
| case softfloat_round_near_even: |
| case softfloat_round_max: |
| case softfloat_round_near_maxMag: |
| zSPtr->signExp = 0x7FFF; |
| zSPtr->signif = UINT64_C( 0x8000000000000000 ); |
| break; |
| case softfloat_round_minMag: |
| case softfloat_round_min: |
| switch ( slow_extF80_roundingPrecision ) { |
| case 32: |
| uiZ0 = UINT64_C( 0xFFFFFF0000000000 ); |
| break; |
| case 64: |
| uiZ0 = UINT64_C( 0xFFFFFFFFFFFFF800 ); |
| break; |
| default: |
| uiZ0 = UINT64_C( 0xFFFFFFFFFFFFFFFF ); |
| break; |
| } |
| zSPtr->signExp = 0x7FFE; |
| zSPtr->signif = uiZ0; |
| break; |
| } |
| } |
| return; |
| } |
| if ( exp <= 0 ) { |
| isTiny = true; |
| x = savedX; |
| exp = x.exp + 0x3FFF; |
| if ( exp < -70 ) { |
| x.sig.v0 = (x.sig.v64 != 0) || (x.sig.v0 != 0); |
| x.sig.v64 = 0; |
| } else { |
| while ( exp <= 0 ) { |
| ++exp; |
| x.sig = shortShiftRightJam128( x.sig, 1 ); |
| } |
| } |
| switch ( slow_extF80_roundingPrecision ) { |
| case 32: |
| roundFloatXTo24( isTiny, &x, slowfloat_roundingMode, true ); |
| break; |
| case 64: |
| roundFloatXTo53( isTiny, &x, slowfloat_roundingMode, true ); |
| break; |
| default: |
| roundFloatXTo64( isTiny, &x, slowfloat_roundingMode, true ); |
| break; |
| } |
| exp = (UINT64_C( 0x0080000000000000 ) <= x.sig.v64) ? 1 : 0; |
| } |
| uiZ64 = exp; |
| if ( x.sign ) uiZ64 |= 0x8000; |
| zSPtr->signExp = uiZ64; |
| zSPtr->signif = shortShiftRightJam128( x.sig, 56 ).v0; |
| |
| } |
| |
| #endif |
| |
| #ifdef FLOAT128 |
| |
| static void f128MToFloatX( const float128_t *aPtr, struct floatX *xPtr ) |
| { |
| const struct uint128 *uiAPtr; |
| uint_fast64_t uiA64; |
| int_fast32_t exp; |
| struct uint128 sig; |
| |
| uiAPtr = (const struct uint128 *) aPtr; |
| xPtr->isNaN = false; |
| xPtr->isInf = false; |
| xPtr->isZero = false; |
| uiA64 = uiAPtr->v64; |
| xPtr->sign = ((uiA64 & UINT64_C( 0x8000000000000000 )) != 0); |
| exp = uiA64>>48 & 0x7FFF; |
| sig.v64 = uiA64 & UINT64_C( 0x0000FFFFFFFFFFFF ); |
| sig.v0 = uiAPtr->v0; |
| if ( exp == 0x7FFF ) { |
| if ( sig.v64 || sig.v0 ) { |
| xPtr->isNaN = true; |
| } else { |
| xPtr->isInf = true; |
| } |
| } else if ( ! exp ) { |
| if ( ! sig.v64 && ! sig.v0 ) { |
| xPtr->isZero = true; |
| } else { |
| exp = 1 - 0x3FFF; |
| do { |
| --exp; |
| sig = shortShiftLeft128( sig, 1 ); |
| } while ( sig.v64 < UINT64_C( 0x0001000000000000 ) ); |
| xPtr->exp = exp; |
| } |
| } else { |
| xPtr->exp = exp - 0x3FFF; |
| sig.v64 |= UINT64_C( 0x0001000000000000 ); |
| } |
| xPtr->sig = shortShiftLeft128( sig, 7 ); |
| |
| } |
| |
| static void floatXToF128M( const struct floatX *xPtr, float128_t *zPtr ) |
| { |
| struct uint128 *uiZPtr; |
| struct floatX x, savedX; |
| bool isTiny; |
| int_fast32_t exp; |
| uint_fast64_t uiZ64; |
| |
| uiZPtr = (struct uint128 *) zPtr; |
| if ( xPtr->isNaN ) { |
| uiZPtr->v64 = uiZPtr->v0 = UINT64_C( 0xFFFFFFFFFFFFFFFF ); |
| return; |
| } |
| if ( xPtr->isInf ) { |
| uiZPtr->v64 = |
| xPtr->sign ? UINT64_C( 0xFFFF000000000000 ) |
| : UINT64_C( 0x7FFF000000000000 ); |
| uiZPtr->v0 = 0; |
| return; |
| } |
| if ( xPtr->isZero ) { |
| uiZPtr->v64 = xPtr->sign ? UINT64_C( 0x8000000000000000 ) : 0; |
| uiZPtr->v0 = 0; |
| return; |
| } |
| x = *xPtr; |
| while ( UINT64_C( 0x0100000000000000 ) <= x.sig.v64 ) { |
| ++x.exp; |
| x.sig = shortShiftRightJam128( x.sig, 1 ); |
| } |
| while ( x.sig.v64 < UINT64_C( 0x0080000000000000 ) ) { |
| --x.exp; |
| x.sig = shortShiftLeft128( x.sig, 1 ); |
| } |
| savedX = x; |
| isTiny = |
| (slowfloat_detectTininess == softfloat_tininess_beforeRounding) |
| && (x.exp + 0x3FFF <= 0); |
| roundFloatXTo113( isTiny, &x, slowfloat_roundingMode, true ); |
| exp = x.exp + 0x3FFF; |
| if ( 0x7FFF <= exp ) { |
| slowfloat_exceptionFlags |= |
| softfloat_flag_overflow | softfloat_flag_inexact; |
| if ( x.sign ) { |
| switch ( slowfloat_roundingMode ) { |
| case softfloat_round_near_even: |
| case softfloat_round_min: |
| case softfloat_round_near_maxMag: |
| uiZPtr->v64 = UINT64_C( 0xFFFF000000000000 ); |
| uiZPtr->v0 = 0; |
| break; |
| case softfloat_round_minMag: |
| case softfloat_round_max: |
| uiZPtr->v64 = UINT64_C( 0xFFFEFFFFFFFFFFFF ); |
| uiZPtr->v0 = UINT64_C( 0xFFFFFFFFFFFFFFFF ); |
| break; |
| } |
| } else { |
| switch ( slowfloat_roundingMode ) { |
| case softfloat_round_near_even: |
| case softfloat_round_max: |
| case softfloat_round_near_maxMag: |
| uiZPtr->v64 = UINT64_C( 0x7FFF000000000000 ); |
| uiZPtr->v0 = 0; |
| break; |
| case softfloat_round_minMag: |
| case softfloat_round_min: |
| uiZPtr->v64 = UINT64_C( 0x7FFEFFFFFFFFFFFF ); |
| uiZPtr->v0 = UINT64_C( 0xFFFFFFFFFFFFFFFF ); |
| break; |
| } |
| } |
| return; |
| } |
| if ( exp <= 0 ) { |
| isTiny = true; |
| x = savedX; |
| exp = x.exp + 0x3FFF; |
| if ( exp < -120 ) { |
| x.sig.v0 = (x.sig.v64 != 0) || (x.sig.v0 != 0); |
| x.sig.v64 = 0; |
| } else { |
| while ( exp <= 0 ) { |
| ++exp; |
| x.sig = shortShiftRightJam128( x.sig, 1 ); |
| } |
| } |
| roundFloatXTo113( isTiny, &x, slowfloat_roundingMode, true ); |
| exp = (UINT64_C( 0x0080000000000000 ) <= x.sig.v64) ? 1 : 0; |
| } |
| uiZ64 = (uint_fast64_t) exp<<48; |
| if ( x.sign ) uiZ64 |= UINT64_C( 0x8000000000000000 ); |
| x.sig = shortShiftRightJam128( x.sig, 7 ); |
| uiZPtr->v64 = uiZ64 | x.sig.v64 & UINT64_C( 0x0000FFFFFFFFFFFF ); |
| uiZPtr->v0 = x.sig.v0; |
| |
| } |
| |
| #endif |
| |
| static void floatXInvalid( struct floatX *xPtr ) |
| { |
| |
| slowfloat_exceptionFlags |= softfloat_flag_invalid; |
| *xPtr = floatXNaN; |
| |
| } |
| |
| static |
| void |
| floatXRoundToInt( |
| struct floatX *xPtr, uint_fast8_t roundingMode, bool exact ) |
| { |
| int_fast32_t exp, shiftCount; |
| struct uint128 sig; |
| |
| if ( xPtr->isNaN || xPtr->isInf ) return; |
| exp = xPtr->exp; |
| shiftCount = 112 - exp; |
| if ( shiftCount <= 0 ) return; |
| if ( 119 < shiftCount ) { |
| xPtr->exp = 112; |
| xPtr->sig.v64 = 0; |
| xPtr->sig.v0 = ! xPtr->isZero; |
| } else { |
| sig = xPtr->sig; |
| while ( 0 < shiftCount ) { |
| ++exp; |
| sig = shortShiftRightJam128( sig, 1 ); |
| --shiftCount; |
| } |
| xPtr->exp = exp; |
| xPtr->sig = sig; |
| } |
| roundFloatXTo113( false, xPtr, roundingMode, exact ); |
| if ( ! xPtr->sig.v64 && ! xPtr->sig.v0 ) xPtr->isZero = true; |
| |
| } |
| |
| static void floatXAdd( struct floatX *xPtr, const struct floatX *yPtr ) |
| { |
| int_fast32_t expX, expY, expDiff; |
| struct uint128 sigY; |
| |
| if ( xPtr->isNaN ) return; |
| if ( yPtr->isNaN ) goto copyY; |
| if ( xPtr->isInf && yPtr->isInf ) { |
| if ( xPtr->sign != yPtr->sign ) floatXInvalid( xPtr ); |
| return; |
| } |
| if ( xPtr->isInf ) return; |
| if ( yPtr->isInf ) goto copyY; |
| if ( xPtr->isZero && yPtr->isZero ) { |
| if ( xPtr->sign == yPtr->sign ) return; |
| goto completeCancellation; |
| } |
| expX = xPtr->exp; |
| expY = yPtr->exp; |
| if ( |
| (xPtr->sign != yPtr->sign) && (expX == expY) |
| && eq128( xPtr->sig, yPtr->sig ) |
| ) { |
| completeCancellation: |
| if (slowfloat_roundingMode == softfloat_round_min) { |
| *xPtr = floatXNegativeZero; |
| } else { |
| *xPtr = floatXPositiveZero; |
| } |
| return; |
| } |
| if ( xPtr->isZero ) goto copyY; |
| if ( yPtr->isZero ) return; |
| expDiff = expX - expY; |
| if ( expDiff < 0 ) { |
| xPtr->exp = expY; |
| if ( expDiff < -120 ) { |
| xPtr->sig.v64 = 0; |
| xPtr->sig.v0 = 1; |
| } else { |
| while ( expDiff < 0 ) { |
| ++expDiff; |
| xPtr->sig = shortShiftRightJam128( xPtr->sig, 1 ); |
| } |
| } |
| if ( xPtr->sign != yPtr->sign ) xPtr->sig = neg128( xPtr->sig ); |
| xPtr->sign = yPtr->sign; |
| xPtr->sig = add128( xPtr->sig, yPtr->sig ); |
| } else { |
| sigY = yPtr->sig; |
| if ( 120 < expDiff ) { |
| sigY.v64 = 0; |
| sigY.v0 = 1; |
| } else { |
| while ( 0 < expDiff ) { |
| --expDiff; |
| sigY = shortShiftRightJam128( sigY, 1 ); |
| } |
| } |
| if ( xPtr->sign != yPtr->sign ) sigY = neg128( sigY ); |
| xPtr->sig = add128( xPtr->sig, sigY ); |
| } |
| if ( xPtr->sig.v64 & UINT64_C( 0x8000000000000000 ) ) { |
| xPtr->sign = ! xPtr->sign; |
| xPtr->sig = neg128( xPtr->sig ); |
| } |
| return; |
| copyY: |
| *xPtr = *yPtr; |
| |
| } |
| |
| static void floatXMul( struct floatX *xPtr, const struct floatX *yPtr ) |
| { |
| struct uint128 sig; |
| int bitNum; |
| |
| if ( xPtr->isNaN ) return; |
| if ( yPtr->isNaN ) { |
| xPtr->isNaN = true; |
| xPtr->isInf = false; |
| xPtr->isZero = false; |
| xPtr->sign = yPtr->sign; |
| return; |
| } |
| if ( yPtr->sign ) xPtr->sign = ! xPtr->sign; |
| if ( xPtr->isInf ) { |
| if ( yPtr->isZero ) floatXInvalid( xPtr ); |
| return; |
| } |
| if ( yPtr->isInf ) { |
| if ( xPtr->isZero ) { |
| floatXInvalid( xPtr ); |
| return; |
| } |
| xPtr->isInf = true; |
| return; |
| } |
| if ( xPtr->isZero || yPtr->isZero ) { |
| if ( xPtr->sign ) { |
| *xPtr = floatXNegativeZero; |
| } else { |
| *xPtr = floatXPositiveZero; |
| } |
| return; |
| } |
| xPtr->exp += yPtr->exp; |
| sig.v64 = 0; |
| sig.v0 = 0; |
| for ( bitNum = 0; bitNum < 120; ++bitNum ) { |
| sig = shortShiftRightJam128( sig, 1 ); |
| if ( xPtr->sig.v0 & 1 ) sig = add128( sig, yPtr->sig ); |
| xPtr->sig = shortShiftRight128( xPtr->sig, 1 ); |
| } |
| if ( UINT64_C( 0x0100000000000000 ) <= sig.v64 ) { |
| ++xPtr->exp; |
| sig = shortShiftRightJam128( sig, 1 ); |
| } |
| xPtr->sig = sig; |
| |
| } |
| |
| static void floatXDiv( struct floatX *xPtr, const struct floatX *yPtr ) |
| { |
| struct uint128 sig, negSigY; |
| int bitNum; |
| |
| if ( xPtr->isNaN ) return; |
| if ( yPtr->isNaN ) { |
| xPtr->isNaN = true; |
| xPtr->isInf = false; |
| xPtr->isZero = false; |
| xPtr->sign = yPtr->sign; |
| return; |
| } |
| if ( yPtr->sign ) xPtr->sign = ! xPtr->sign; |
| if ( xPtr->isInf ) { |
| if ( yPtr->isInf ) floatXInvalid( xPtr ); |
| return; |
| } |
| if ( yPtr->isZero ) { |
| if ( xPtr->isZero ) { |
| floatXInvalid( xPtr ); |
| return; |
| } |
| slowfloat_exceptionFlags |= softfloat_flag_infinite; |
| xPtr->isInf = true; |
| return; |
| } |
| if ( xPtr->isZero || yPtr->isInf ) { |
| if ( xPtr->sign ) { |
| *xPtr = floatXNegativeZero; |
| } else { |
| *xPtr = floatXPositiveZero; |
| } |
| return; |
| } |
| xPtr->exp -= yPtr->exp + 1; |
| sig.v64 = 0; |
| sig.v0 = 0; |
| negSigY = neg128( yPtr->sig ); |
| for ( bitNum = 0; bitNum < 120; ++bitNum ) { |
| if ( le128( yPtr->sig, xPtr->sig ) ) { |
| sig.v0 |= 1; |
| xPtr->sig = add128( xPtr->sig, negSigY ); |
| } |
| xPtr->sig = shortShiftLeft128( xPtr->sig, 1 ); |
| sig = shortShiftLeft128( sig, 1 ); |
| } |
| if ( xPtr->sig.v64 || xPtr->sig.v0 ) sig.v0 |= 1; |
| xPtr->sig = sig; |
| |
| } |
| |
| static void floatXRem( struct floatX *xPtr, const struct floatX *yPtr ) |
| { |
| int_fast32_t expX, expY; |
| struct uint128 sigY, negSigY; |
| bool lastQuotientBit; |
| struct uint128 savedSigX; |
| |
| if ( xPtr->isNaN ) return; |
| if ( yPtr->isNaN ) { |
| xPtr->isNaN = true; |
| xPtr->isInf = false; |
| xPtr->isZero = false; |
| xPtr->sign = yPtr->sign; |
| return; |
| } |
| if ( xPtr->isInf || yPtr->isZero ) { |
| floatXInvalid( xPtr ); |
| return; |
| } |
| if ( xPtr->isZero || yPtr->isInf ) return; |
| expX = xPtr->exp; |
| expY = yPtr->exp - 1; |
| if ( expX < expY ) return; |
| sigY = shortShiftLeft128( yPtr->sig, 1 ); |
| negSigY = neg128( sigY ); |
| while ( expY < expX ) { |
| --expX; |
| if ( le128( sigY, xPtr->sig ) ) { |
| xPtr->sig = add128( xPtr->sig, negSigY ); |
| } |
| xPtr->sig = shortShiftLeft128( xPtr->sig, 1 ); |
| } |
| xPtr->exp = expX; |
| lastQuotientBit = le128( sigY, xPtr->sig ); |
| if ( lastQuotientBit ) xPtr->sig = add128( xPtr->sig, negSigY ); |
| savedSigX = xPtr->sig; |
| xPtr->sig = neg128( add128( xPtr->sig, negSigY ) ); |
| if ( lt128( xPtr->sig, savedSigX ) ) { |
| xPtr->sign = ! xPtr->sign; |
| } else if ( lt128( savedSigX, xPtr->sig ) ) { |
| goto restoreSavedSigX; |
| } else { |
| if ( lastQuotientBit ) { |
| xPtr->sign = ! xPtr->sign; |
| } else { |
| restoreSavedSigX: |
| xPtr->sig = savedSigX; |
| } |
| } |
| if ( ! xPtr->sig.v64 && ! xPtr->sig.v0 ) xPtr->isZero = true; |
| |
| } |
| |
| static void floatXSqrt( struct floatX *xPtr ) |
| { |
| struct uint128 sig, bitSig; |
| int bitNum; |
| struct uint128 savedSigX; |
| |
| if ( xPtr->isNaN || xPtr->isZero ) return; |
| if ( xPtr->sign ) { |
| floatXInvalid( xPtr ); |
| return; |
| } |
| if ( xPtr->isInf ) return; |
| if ( ! (xPtr->exp & 1) ) xPtr->sig = shortShiftRightJam128( xPtr->sig, 1 ); |
| xPtr->exp >>= 1; |
| sig.v64 = 0; |
| sig.v0 = 0; |
| bitSig.v64 = UINT64_C( 0x0080000000000000 ); |
| bitSig.v0 = 0; |
| for ( bitNum = 0; bitNum < 120; ++bitNum ) { |
| savedSigX = xPtr->sig; |
| xPtr->sig = add128( xPtr->sig, neg128( sig ) ); |
| xPtr->sig = shortShiftLeft128( xPtr->sig, 1 ); |
| xPtr->sig = add128( xPtr->sig, neg128( bitSig ) ); |
| if ( xPtr->sig.v64 & UINT64_C( 0x8000000000000000 ) ) { |
| xPtr->sig = shortShiftLeft128( savedSigX, 1 ); |
| } else { |
| sig.v64 |= bitSig.v64; |
| sig.v0 |= bitSig.v0; |
| } |
| bitSig = shortShiftRightJam128( bitSig, 1 ); |
| } |
| if ( xPtr->sig.v64 || xPtr->sig.v0 ) sig.v0 |= 1; |
| xPtr->sig = sig; |
| |
| } |
| |
| static bool floatXEq( const struct floatX *xPtr, const struct floatX *yPtr ) |
| { |
| |
| if ( xPtr->isNaN || yPtr->isNaN ) return false; |
| if ( xPtr->isZero && yPtr->isZero ) return true; |
| if ( xPtr->sign != yPtr->sign ) return false; |
| if ( xPtr->isInf || yPtr->isInf ) return xPtr->isInf && yPtr->isInf; |
| return ( xPtr->exp == yPtr->exp ) && eq128( xPtr->sig, yPtr->sig ); |
| |
| } |
| |
| static bool floatXLe( const struct floatX *xPtr, const struct floatX *yPtr ) |
| { |
| |
| if ( xPtr->isNaN || yPtr->isNaN ) return false; |
| if ( xPtr->isZero && yPtr->isZero ) return true; |
| if ( xPtr->sign != yPtr->sign ) return xPtr->sign; |
| if ( xPtr->sign ) { |
| if ( xPtr->isInf || yPtr->isZero ) return true; |
| if ( yPtr->isInf || xPtr->isZero ) return false; |
| if ( yPtr->exp < xPtr->exp ) return true; |
| if ( xPtr->exp < yPtr->exp ) return false; |
| return le128( yPtr->sig, xPtr->sig ); |
| } else { |
| if ( yPtr->isInf || xPtr->isZero ) return true; |
| if ( xPtr->isInf || yPtr->isZero ) return false; |
| if ( xPtr->exp < yPtr->exp ) return true; |
| if ( yPtr->exp < xPtr->exp ) return false; |
| return le128( xPtr->sig, yPtr->sig ); |
| } |
| |
| } |
| |
| static bool floatXLt( const struct floatX *xPtr, const struct floatX *yPtr ) |
| { |
| |
| if ( xPtr->isNaN || yPtr->isNaN ) return false; |
| if ( xPtr->isZero && yPtr->isZero ) return false; |
| if ( xPtr->sign != yPtr->sign ) return xPtr->sign; |
| if ( xPtr->isInf && yPtr->isInf ) return false; |
| if ( xPtr->sign ) { |
| if ( xPtr->isInf || yPtr->isZero ) return true; |
| if ( yPtr->isInf || xPtr->isZero ) return false; |
| if ( yPtr->exp < xPtr->exp ) return true; |
| if ( xPtr->exp < yPtr->exp ) return false; |
| return lt128( yPtr->sig, xPtr->sig ); |
| } else { |
| if ( yPtr->isInf || xPtr->isZero ) return true; |
| if ( xPtr->isInf || yPtr->isZero ) return false; |
| if ( xPtr->exp < yPtr->exp ) return true; |
| if ( yPtr->exp < xPtr->exp ) return false; |
| return lt128( xPtr->sig, yPtr->sig ); |
| } |
| |
| } |
| |
| /*---------------------------------------------------------------------------- |
| *----------------------------------------------------------------------------*/ |
| |
| #if defined EXTFLOAT80 || defined FLOAT128 |
| |
| #ifdef LITTLEENDIAN |
| struct uint256 { uint64_t v0, v64, v128, v192; }; |
| #else |
| struct uint256 { uint64_t v192, v128 v64, v0; }; |
| #endif |
| |
| static bool eq256M( const struct uint256 *aPtr, const struct uint256 *bPtr ) |
| { |
| |
| return |
| (aPtr->v192 == bPtr->v192) && (aPtr->v128 == bPtr->v128) |
| && (aPtr->v64 == bPtr->v64) && (aPtr->v0 == bPtr->v0); |
| |
| } |
| |
| static void shiftLeft1256M( struct uint256 *ptr ) |
| { |
| uint64_t dword1, dword2; |
| |
| dword1 = ptr->v128; |
| ptr->v192 = ptr->v192<<1 | dword1>>63; |
| dword2 = ptr->v64; |
| ptr->v128 = dword1<<1 | dword2>>63; |
| dword1 = ptr->v0; |
| ptr->v64 = dword2<<1 | dword1>>63; |
| ptr->v0 = dword1<<1; |
| |
| } |
| |
| static void shiftRight1256M( struct uint256 *ptr ) |
| { |
| uint64_t dword1, dword2; |
| |
| dword1 = ptr->v64; |
| ptr->v0 = dword1<<63 | ptr->v0>>1; |
| dword2 = ptr->v128; |
| ptr->v64 = dword2<<63 | dword1>>1; |
| dword1 = ptr->v192; |
| ptr->v128 = dword1<<63 | dword2>>1; |
| ptr->v192 = dword1>>1; |
| |
| } |
| |
| static void shiftRight1Jam256M( struct uint256 *ptr ) |
| { |
| int extra; |
| |
| extra = ptr->v0 & 1; |
| shiftRight1256M( ptr ); |
| ptr->v0 |= extra; |
| |
| } |
| |
| static void neg256M( struct uint256 *ptr ) |
| { |
| uint64_t v64, v0, v128; |
| |
| v64 = ptr->v64; |
| v0 = ptr->v0; |
| if ( v64 | v0 ) { |
| ptr->v192 = ~ptr->v192; |
| ptr->v128 = ~ptr->v128; |
| if ( v0 ) { |
| ptr->v64 = ~v64; |
| ptr->v0 = -v0; |
| } else { |
| ptr->v64 = -v64; |
| } |
| } else { |
| v128 = ptr->v128; |
| if ( v128 ) { |
| ptr->v192 = ~ptr->v192; |
| ptr->v128 = -v128; |
| } else { |
| ptr->v192 = -ptr->v192; |
| } |
| } |
| |
| } |
| |
| static void add256M( struct uint256 *aPtr, const struct uint256 *bPtr ) |
| { |
| uint64_t dwordA, dwordZ; |
| unsigned int carry1, carry2; |
| |
| dwordA = aPtr->v0; |
| dwordZ = dwordA + bPtr->v0; |
| carry1 = (dwordZ < dwordA); |
| aPtr->v0 = dwordZ; |
| dwordA = aPtr->v64; |
| dwordZ = dwordA + bPtr->v64; |
| carry2 = (dwordZ < dwordA); |
| dwordZ += carry1; |
| carry2 += (dwordZ < carry1); |
| aPtr->v64 = dwordZ; |
| dwordA = aPtr->v128; |
| dwordZ = dwordA + bPtr->v128; |
| carry1 = (dwordZ < dwordA); |
| dwordZ += carry2; |
| carry1 += (dwordZ < carry2); |
| aPtr->v128 = dwordZ; |
| aPtr->v192 = aPtr->v192 + bPtr->v192 + carry1; |
| |
| } |
| |
| struct floatX256 { |
| bool isNaN; |
| bool isInf; |
| bool isZero; |
| bool sign; |
| int_fast32_t exp; |
| struct uint256 sig; |
| }; |
| |
| static const struct floatX256 floatX256NaN = |
| { true, false, false, false, 0, { 0, 0, 0, 0 } }; |
| static const struct floatX256 floatX256PositiveZero = |
| { false, false, true, false, 0, { 0, 0, 0, 0 } }; |
| static const struct floatX256 floatX256NegativeZero = |
| { false, false, true, true, 0, { 0, 0, 0, 0 } }; |
| |
| #ifdef FLOAT128 |
| |
| static void f128MToFloatX256( const float128_t *aPtr, struct floatX256 *xPtr ) |
| { |
| struct floatX x; |
| |
| f128MToFloatX( aPtr, &x ); |
| xPtr->isNaN = x.isNaN; |
| xPtr->isInf = x.isInf; |
| xPtr->isZero = x.isZero; |
| xPtr->sign = x.sign; |
| xPtr->exp = x.exp; |
| xPtr->sig.v192 = x.sig.v64; |
| xPtr->sig.v128 = x.sig.v0; |
| xPtr->sig.v64 = 0; |
| xPtr->sig.v0 = 0; |
| |
| } |
| |
| static void floatX256ToF128M( const struct floatX256 *xPtr, float128_t *zPtr ) |
| { |
| struct floatX x; |
| int_fast32_t expZ; |
| struct uint256 sig; |
| |
| x.isNaN = xPtr->isNaN; |
| x.isInf = xPtr->isInf; |
| x.isZero = xPtr->isZero; |
| x.sign = xPtr->sign; |
| if ( ! (x.isNaN | x.isInf | x.isZero) ) { |
| expZ = xPtr->exp; |
| sig = xPtr->sig; |
| while ( ! sig.v192 ) { |
| expZ -= 64; |
| sig.v192 = sig.v128; |
| sig.v128 = sig.v64; |
| sig.v64 = sig.v0; |
| sig.v0 = 0; |
| } |
| while ( sig.v192 < UINT64_C( 0x0100000000000000 ) ) { |
| --expZ; |
| shiftLeft1256M( &sig ); |
| } |
| x.exp = expZ; |
| x.sig.v64 = sig.v192; |
| x.sig.v0 = sig.v128 | ((sig.v64 | sig.v0) != 0); |
| } |
| floatXToF128M( &x, zPtr ); |
| |
| } |
| |
| #endif |
| |
| static void floatX256Invalid( struct floatX256 *xPtr ) |
| { |
| |
| slowfloat_exceptionFlags |= softfloat_flag_invalid; |
| *xPtr = floatX256NaN; |
| |
| } |
| |
| static |
| void floatX256Add( struct floatX256 *xPtr, const struct floatX256 *yPtr ) |
| { |
| int_fast32_t expX, expY, expDiff; |
| struct uint256 sigY; |
| |
| if ( xPtr->isNaN ) return; |
| if ( yPtr->isNaN ) goto copyY; |
| if ( xPtr->isInf && yPtr->isInf ) { |
| if ( xPtr->sign != yPtr->sign ) floatX256Invalid( xPtr ); |
| return; |
| } |
| if ( xPtr->isInf ) return; |
| if ( yPtr->isInf ) goto copyY; |
| if ( xPtr->isZero && yPtr->isZero ) { |
| if ( xPtr->sign == yPtr->sign ) return; |
| goto completeCancellation; |
| } |
| expX = xPtr->exp; |
| expY = yPtr->exp; |
| if ( |
| (xPtr->sign != yPtr->sign) && (expX == expY) |
| && eq256M( &xPtr->sig, &yPtr->sig ) |
| ) { |
| completeCancellation: |
| if (slowfloat_roundingMode == softfloat_round_min) { |
| *xPtr = floatX256NegativeZero; |
| } else { |
| *xPtr = floatX256PositiveZero; |
| } |
| return; |
| } |
| if ( xPtr->isZero ) goto copyY; |
| if ( yPtr->isZero ) return; |
| expDiff = expX - expY; |
| if ( expDiff < 0 ) { |
| xPtr->exp = expY; |
| if ( expDiff < -248 ) { |
| xPtr->sig.v192 = 0; |
| xPtr->sig.v128 = 0; |
| xPtr->sig.v64 = 0; |
| xPtr->sig.v0 = 1; |
| } else { |
| while ( expDiff < 0 ) { |
| ++expDiff; |
| shiftRight1Jam256M( &xPtr->sig ); |
| } |
| } |
| if ( xPtr->sign != yPtr->sign ) neg256M( &xPtr->sig ); |
| xPtr->sign = yPtr->sign; |
| add256M( &xPtr->sig, &yPtr->sig ); |
| } else { |
| sigY = yPtr->sig; |
| if ( 248 < expDiff ) { |
| sigY.v192 = 0; |
| sigY.v128 = 0; |
| sigY.v64 = 0; |
| sigY.v0 = 1; |
| } else { |
| while ( 0 < expDiff ) { |
| --expDiff; |
| shiftRight1Jam256M( &sigY ); |
| } |
| } |
| if ( xPtr->sign != yPtr->sign ) neg256M( &sigY ); |
| add256M( &xPtr->sig, &sigY ); |
| } |
| if ( xPtr->sig.v192 & UINT64_C( 0x8000000000000000 ) ) { |
| xPtr->sign = ! xPtr->sign; |
| neg256M( &xPtr->sig ); |
| } |
| return; |
| copyY: |
| *xPtr = *yPtr; |
| |
| } |
| |
| static |
| void floatX256Mul( struct floatX256 *xPtr, const struct floatX256 *yPtr ) |
| { |
| struct uint256 sig; |
| int bitNum; |
| |
| if ( xPtr->isNaN ) return; |
| if ( yPtr->isNaN ) { |
| xPtr->isNaN = true; |
| xPtr->isInf = false; |
| xPtr->isZero = false; |
| xPtr->sign = yPtr->sign; |
| return; |
| } |
| if ( yPtr->sign ) xPtr->sign = ! xPtr->sign; |
| if ( xPtr->isInf ) { |
| if ( yPtr->isZero ) floatX256Invalid( xPtr ); |
| return; |
| } |
| if ( yPtr->isInf ) { |
| if ( xPtr->isZero ) { |
| floatX256Invalid( xPtr ); |
| return; |
| } |
| xPtr->isInf = true; |
| return; |
| } |
| if ( xPtr->isZero || yPtr->isZero ) { |
| if ( xPtr->sign ) { |
| *xPtr = floatX256NegativeZero; |
| } else { |
| *xPtr = floatX256PositiveZero; |
| } |
| return; |
| } |
| xPtr->exp += yPtr->exp; |
| sig.v192 = 0; |
| sig.v128 = 0; |
| sig.v64 = 0; |
| sig.v0 = 0; |
| for ( bitNum = 0; bitNum < 248; ++bitNum ) { |
| shiftRight1Jam256M( &sig ); |
| if ( xPtr->sig.v0 & 1 ) add256M( &sig, &yPtr->sig ); |
| shiftRight1256M( &xPtr->sig ); |
| } |
| if ( UINT64_C( 0x0100000000000000 ) <= sig.v192 ) { |
| ++xPtr->exp; |
| shiftRight1Jam256M( &sig ); |
| } |
| xPtr->sig = sig; |
| |
| } |
| |
| #endif |
| |
| /*---------------------------------------------------------------------------- |
| *----------------------------------------------------------------------------*/ |
| |
| float32_t slow_ui32_to_f32( uint32_t a ) |
| { |
| struct floatX x; |
| |
| ui32ToFloatX( a, &x ); |
| return floatXToF32( &x ); |
| |
| } |
| |
| float64_t slow_ui32_to_f64( uint32_t a ) |
| { |
| struct floatX x; |
| |
| ui32ToFloatX( a, &x ); |
| return floatXToF64( &x ); |
| |
| } |
| |
| #ifdef EXTFLOAT80 |
| |
| void slow_ui32_to_extF80M( uint32_t a, extFloat80_t *zPtr ) |
| { |
| struct floatX x; |
| |
| ui32ToFloatX( a, &x ); |
| floatXToExtF80M( &x, zPtr ); |
| |
| } |
| |
| #endif |
| |
| #ifdef FLOAT128 |
| |
| void slow_ui32_to_f128M( uint32_t a, float128_t *zPtr ) |
| { |
| struct floatX x; |
| |
| ui32ToFloatX( a, &x ); |
| floatXToF128M( &x, zPtr ); |
| |
| } |
| |
| #endif |
| |
| float32_t slow_ui64_to_f32( uint64_t a ) |
| { |
| struct floatX x; |
| |
| ui64ToFloatX( a, &x ); |
| return floatXToF32( &x ); |
| |
| } |
| |
| float64_t slow_ui64_to_f64( uint64_t a ) |
| { |
| struct floatX x; |
| |
| ui64ToFloatX( a, &x ); |
| return floatXToF64( &x ); |
| |
| } |
| |
| #ifdef EXTFLOAT80 |
| |
| void slow_ui64_to_extF80M( uint64_t a, extFloat80_t *zPtr ) |
| { |
| struct floatX x; |
| |
| ui64ToFloatX( a, &x ); |
| floatXToExtF80M( &x, zPtr ); |
| |
| } |
| |
| #endif |
| |
| #ifdef FLOAT128 |
| |
| void slow_ui64_to_f128M( uint64_t a, float128_t *zPtr ) |
| { |
| struct floatX x; |
| |
| ui64ToFloatX( a, &x ); |
| floatXToF128M( &x, zPtr ); |
| |
| } |
| |
| #endif |
| |
| float32_t slow_i32_to_f32( int32_t a ) |
| { |
| struct floatX x; |
| |
| i32ToFloatX( a, &x ); |
| return floatXToF32( &x ); |
| |
| } |
| |
| float64_t slow_i32_to_f64( int32_t a ) |
| { |
| struct floatX x; |
| |
| i32ToFloatX( a, &x ); |
| return floatXToF64( &x ); |
| |
| } |
| |
| #ifdef EXTFLOAT80 |
| |
| void slow_i32_to_extF80M( int32_t a, extFloat80_t *zPtr ) |
| { |
| struct floatX x; |
| |
| i32ToFloatX( a, &x ); |
| floatXToExtF80M( &x, zPtr ); |
| |
| } |
| |
| #endif |
| |
| #ifdef FLOAT128 |
| |
| void slow_i32_to_f128M( int32_t a, float128_t *zPtr ) |
| { |
| struct floatX x; |
| |
| i32ToFloatX( a, &x ); |
| floatXToF128M( &x, zPtr ); |
| |
| } |
| |
| #endif |
| |
| float32_t slow_i64_to_f32( int64_t a ) |
| { |
| struct floatX x; |
| |
| i64ToFloatX( a, &x ); |
| return floatXToF32( &x ); |
| |
| } |
| |
| float64_t slow_i64_to_f64( int64_t a ) |
| { |
| struct floatX x; |
| |
| i64ToFloatX( a, &x ); |
| return floatXToF64( &x ); |
| |
| } |
| |
| #ifdef EXTFLOAT80 |
| |
| void slow_i64_to_extF80M( int64_t a, extFloat80_t *zPtr ) |
| { |
| struct floatX x; |
| |
| i64ToFloatX( a, &x ); |
| floatXToExtF80M( &x, zPtr ); |
| |
| } |
| |
| #endif |
| |
| #ifdef FLOAT128 |
| |
| void slow_i64_to_f128M( int64_t a, float128_t *zPtr ) |
| { |
| struct floatX x; |
| |
| i64ToFloatX( a, &x ); |
| floatXToF128M( &x, zPtr ); |
| |
| } |
| |
| #endif |
| |
| uint_fast32_t |
| slow_f32_to_ui32( float32_t a, uint_fast8_t roundingMode, bool exact ) |
| { |
| struct floatX x; |
| |
| f32ToFloatX( a, &x ); |
| return floatXToUI32( &x, roundingMode, exact ); |
| |
| } |
| |
| uint_fast64_t |
| slow_f32_to_ui64( float32_t a, uint_fast8_t roundingMode, bool exact ) |
| { |
| struct floatX x; |
| |
| f32ToFloatX( a, &x ); |
| return floatXToUI64( &x, roundingMode, exact ); |
| |
| } |
| |
| int_fast32_t |
| slow_f32_to_i32( float32_t a, uint_fast8_t roundingMode, bool exact ) |
| { |
| struct floatX x; |
| |
| f32ToFloatX( a, &x ); |
| return floatXToI32( &x, roundingMode, exact ); |
| |
| } |
| |
| int_fast64_t |
| slow_f32_to_i64( float32_t a, uint_fast8_t roundingMode, bool exact ) |
| { |
| struct floatX x; |
| |
| f32ToFloatX( a, &x ); |
| return floatXToI64( &x, roundingMode, exact ); |
| |
| } |
| |
| uint_fast32_t slow_f32_to_ui32_r_minMag( float32_t a, bool exact ) |
| { |
| struct floatX x; |
| |
| f32ToFloatX( a, &x ); |
| return floatXToUI32( &x, softfloat_round_minMag, exact ); |
| |
| } |
| |
| uint_fast64_t slow_f32_to_ui64_r_minMag( float32_t a, bool exact ) |
| { |
| struct floatX x; |
| |
| f32ToFloatX( a, &x ); |
| return floatXToUI64( &x, softfloat_round_minMag, exact ); |
| |
| } |
| |
| int_fast32_t slow_f32_to_i32_r_minMag( float32_t a, bool exact ) |
| { |
| struct floatX x; |
| |
| f32ToFloatX( a, &x ); |
| return floatXToI32( &x, softfloat_round_minMag, exact ); |
| |
| } |
| |
| int_fast64_t slow_f32_to_i64_r_minMag( float32_t a, bool exact ) |
| { |
| struct floatX x; |
| |
| f32ToFloatX( a, &x ); |
| return floatXToI64( &x, softfloat_round_minMag, exact ); |
| |
| } |
| |
| float64_t slow_f32_to_f64( float32_t a ) |
| { |
| struct floatX x; |
| |
| f32ToFloatX( a, &x ); |
| return floatXToF64( &x ); |
| |
| } |
| |
| #ifdef EXTFLOAT80 |
| |
| void slow_f32_to_extF80M( float32_t a, extFloat80_t *zPtr ) |
| { |
| struct floatX x; |
| |
| f32ToFloatX( a, &x ); |
| floatXToExtF80M( &x, zPtr ); |
| |
| } |
| |
| #endif |
| |
| #ifdef FLOAT128 |
| |
| void slow_f32_to_f128M( float32_t a, float128_t *zPtr ) |
| { |
| struct floatX x; |
| |
| f32ToFloatX( a, &x ); |
| floatXToF128M( &x, zPtr ); |
| |
| } |
| |
| #endif |
| |
| float32_t |
| slow_f32_roundToInt( float32_t a, uint_fast8_t roundingMode, bool exact ) |
| { |
| struct floatX x; |
| |
| f32ToFloatX( a, &x ); |
| floatXRoundToInt( &x, roundingMode, exact ); |
| return floatXToF32( &x ); |
| |
| } |
| |
| float32_t slow_f32_add( float32_t a, float32_t b ) |
| { |
| struct floatX x, y; |
| |
| f32ToFloatX( a, &x ); |
| f32ToFloatX( b, &y ); |
| floatXAdd( &x, &y ); |
| return floatXToF32( &x ); |
| |
| } |
| |
| float32_t slow_f32_sub( float32_t a, float32_t b ) |
| { |
| struct floatX x, y; |
| |
| f32ToFloatX( a, &x ); |
| f32ToFloatX( b, &y ); |
| y.sign = ! y.sign; |
| floatXAdd( &x, &y ); |
| return floatXToF32( &x ); |
| |
| |
| } |
| |
| float32_t slow_f32_mul( float32_t a, float32_t b ) |
| { |
| struct floatX x, y; |
| |
| f32ToFloatX( a, &x ); |
| f32ToFloatX( b, &y ); |
| floatXMul( &x, &y ); |
| return floatXToF32( &x ); |
| |
| } |
| |
| float32_t slow_f32_mulAdd( float32_t a, float32_t b, float32_t c ) |
| { |
| struct floatX x, y; |
| |
| f32ToFloatX( a, &x ); |
| f32ToFloatX( b, &y ); |
| floatXMul( &x, &y ); |
| f32ToFloatX( c, &y ); |
| floatXAdd( &x, &y ); |
| return floatXToF32( &x ); |
| |
| } |
| |
| float32_t slow_f32_div( float32_t a, float32_t b ) |
| { |
| struct floatX x, y; |
| |
| f32ToFloatX( a, &x ); |
| f32ToFloatX( b, &y ); |
| floatXDiv( &x, &y ); |
| return floatXToF32( &x ); |
| |
| } |
| |
| float32_t slow_f32_rem( float32_t a, float32_t b ) |
| { |
| struct floatX x, y; |
| |
| f32ToFloatX( a, &x ); |
| f32ToFloatX( b, &y ); |
| floatXRem( &x, &y ); |
| return floatXToF32( &x ); |
| |
| } |
| |
| float32_t slow_f32_sqrt( float32_t a ) |
| { |
| struct floatX x; |
| |
| f32ToFloatX( a, &x ); |
| floatXSqrt( &x ); |
| return floatXToF32( &x ); |
| |
| } |
| |
| bool slow_f32_eq( float32_t a, float32_t b ) |
| { |
| struct floatX x, y; |
| |
| f32ToFloatX( a, &x ); |
| f32ToFloatX( b, &y ); |
| return floatXEq( &x, &y ); |
| |
| } |
| |
| bool slow_f32_le( float32_t a, float32_t b ) |
| { |
| struct floatX x, y; |
| |
| f32ToFloatX( a, &x ); |
| f32ToFloatX( b, &y ); |
| if ( x.isNaN || y.isNaN ) { |
| slowfloat_exceptionFlags |= softfloat_flag_invalid; |
| } |
| return floatXLe( &x, &y ); |
| |
| } |
| |
| bool slow_f32_lt( float32_t a, float32_t b ) |
| { |
| struct floatX x, y; |
| |
| f32ToFloatX( a, &x ); |
| f32ToFloatX( b, &y ); |
| if ( x.isNaN || y.isNaN ) { |
| slowfloat_exceptionFlags |= softfloat_flag_invalid; |
| } |
| return floatXLt( &x, &y ); |
| |
| } |
| |
| bool slow_f32_eq_signaling( float32_t a, float32_t b ) |
| { |
| struct floatX x, y; |
| |
| f32ToFloatX( a, &x ); |
| f32ToFloatX( b, &y ); |
| if ( x.isNaN || y.isNaN ) { |
| slowfloat_exceptionFlags |= softfloat_flag_invalid; |
| } |
| return floatXEq( &x, &y ); |
| |
| } |
| |
| bool slow_f32_le_quiet( float32_t a, float32_t b ) |
| { |
| struct floatX x, y; |
| |
| f32ToFloatX( a, &x ); |
| f32ToFloatX( b, &y ); |
| return floatXLe( &x, &y ); |
| |
| } |
| |
| bool slow_f32_lt_quiet( float32_t a, float32_t b ) |
| { |
| struct floatX x, y; |
| |
| f32ToFloatX( a, &x ); |
| f32ToFloatX( b, &y ); |
| return floatXLt( &x, &y ); |
| |
| } |
| |
| uint_fast32_t |
| slow_f64_to_ui32( float64_t a, uint_fast8_t roundingMode, bool exact ) |
| { |
| struct floatX x; |
| |
| f64ToFloatX( a, &x ); |
| return floatXToUI32( &x, roundingMode, exact ); |
| |
| } |
| |
| uint_fast64_t |
| slow_f64_to_ui64( float64_t a, uint_fast8_t roundingMode, bool exact ) |
| { |
| struct floatX x; |
| |
| f64ToFloatX( a, &x ); |
| return floatXToUI64( &x, roundingMode, exact ); |
| |
| } |
| |
| int_fast32_t |
| slow_f64_to_i32( float64_t a, uint_fast8_t roundingMode, bool exact ) |
| { |
| struct floatX x; |
| |
| f64ToFloatX( a, &x ); |
| return floatXToI32( &x, roundingMode, exact ); |
| |
| } |
| |
| int_fast64_t |
| slow_f64_to_i64( float64_t a, uint_fast8_t roundingMode, bool exact ) |
| { |
| struct floatX x; |
| |
| f64ToFloatX( a, &x ); |
| return floatXToI64( &x, roundingMode, exact ); |
| |
| } |
| |
| uint_fast32_t slow_f64_to_ui32_r_minMag( float64_t a, bool exact ) |
| { |
| struct floatX x; |
| |
| f64ToFloatX( a, &x ); |
| return floatXToUI32( &x, softfloat_round_minMag, exact ); |
| |
| } |
| |
| uint_fast64_t slow_f64_to_ui64_r_minMag( float64_t a, bool exact ) |
| { |
| struct floatX x; |
| |
| f64ToFloatX( a, &x ); |
| return floatXToUI64( &x, softfloat_round_minMag, exact ); |
| |
| } |
| |
| int_fast32_t slow_f64_to_i32_r_minMag( float64_t a, bool exact ) |
| { |
| struct floatX x; |
| |
| f64ToFloatX( a, &x ); |
| return floatXToI32( &x, softfloat_round_minMag, exact ); |
| |
| } |
| |
| int_fast64_t slow_f64_to_i64_r_minMag( float64_t a, bool exact ) |
| { |
| struct floatX x; |
| |
| f64ToFloatX( a, &x ); |
| return floatXToI64( &x, softfloat_round_minMag, exact ); |
| |
| } |
| |
| float32_t slow_f64_to_f32( float64_t a ) |
| { |
| struct floatX x; |
| |
| f64ToFloatX( a, &x ); |
| return floatXToF32( &x ); |
| |
| } |
| |
| #ifdef EXTFLOAT80 |
| |
| void slow_f64_to_extF80M( float64_t a, extFloat80_t *zPtr ) |
| { |
| struct floatX x; |
| |
| f64ToFloatX( a, &x ); |
| floatXToExtF80M( &x, zPtr ); |
| |
| } |
| |
| #endif |
| |
| #ifdef FLOAT128 |
| |
| void slow_f64_to_f128M( float64_t a, float128_t *zPtr ) |
| { |
| struct floatX x; |
| |
| f64ToFloatX( a, &x ); |
| floatXToF128M( &x, zPtr ); |
| |
| } |
| |
| #endif |
| |
| float64_t |
| slow_f64_roundToInt( float64_t a, uint_fast8_t roundingMode, bool exact ) |
| { |
| struct floatX x; |
| |
| f64ToFloatX( a, &x ); |
| floatXRoundToInt( &x, roundingMode, exact ); |
| return floatXToF64( &x ); |
| |
| } |
| |
| float64_t slow_f64_add( float64_t a, float64_t b ) |
| { |
| struct floatX x, y; |
| |
| f64ToFloatX( a, &x ); |
| f64ToFloatX( b, &y ); |
| floatXAdd( &x, &y ); |
| return floatXToF64( &x ); |
| |
| } |
| |
| float64_t slow_f64_sub( float64_t a, float64_t b ) |
| { |
| struct floatX x, y; |
| |
| f64ToFloatX( a, &x ); |
| f64ToFloatX( b, &y ); |
| y.sign = ! y.sign; |
| floatXAdd( &x, &y ); |
| return floatXToF64( &x ); |
| |
| } |
| |
| float64_t slow_f64_mul( float64_t a, float64_t b ) |
| { |
| struct floatX x, y; |
| |
| f64ToFloatX( a, &x ); |
| f64ToFloatX( b, &y ); |
| floatXMul( &x, &y ); |
| return floatXToF64( &x ); |
| |
| } |
| |
| float64_t slow_f64_mulAdd( float64_t a, float64_t b, float64_t c ) |
| { |
| struct floatX x, y; |
| |
| f64ToFloatX( a, &x ); |
| f64ToFloatX( b, &y ); |
| floatXMul( &x, &y ); |
| f64ToFloatX( c, &y ); |
| floatXAdd( &x, &y ); |
| return floatXToF64( &x ); |
| |
| } |
| |
| float64_t slow_f64_div( float64_t a, float64_t b ) |
| { |
| struct floatX x, y; |
| |
| f64ToFloatX( a, &x ); |
| f64ToFloatX( b, &y ); |
| floatXDiv( &x, &y ); |
| return floatXToF64( &x ); |
| |
| } |
| |
| float64_t slow_f64_rem( float64_t a, float64_t b ) |
| { |
| struct floatX x, y; |
| |
| f64ToFloatX( a, &x ); |
| f64ToFloatX( b, &y ); |
| floatXRem( &x, &y ); |
| return floatXToF64( &x ); |
| |
| } |
| |
| float64_t slow_f64_sqrt( float64_t a ) |
| { |
| struct floatX x; |
| |
| f64ToFloatX( a, &x ); |
| floatXSqrt( &x ); |
| return floatXToF64( &x ); |
| |
| } |
| |
| bool slow_f64_eq( float64_t a, float64_t b ) |
| { |
| struct floatX x, y; |
| |
| f64ToFloatX( a, &x ); |
| f64ToFloatX( b, &y ); |
| return floatXEq( &x, &y ); |
| |
| } |
| |
| bool slow_f64_le( float64_t a, float64_t b ) |
| { |
| struct floatX x, y; |
| |
| f64ToFloatX( a, &x ); |
| f64ToFloatX( b, &y ); |
| if ( x.isNaN || y.isNaN ) { |
| slowfloat_exceptionFlags |= softfloat_flag_invalid; |
| } |
| return floatXLe( &x, &y ); |
| |
| } |
| |
| bool slow_f64_lt( float64_t a, float64_t b ) |
| { |
| struct floatX x, y; |
| |
| f64ToFloatX( a, &x ); |
| f64ToFloatX( b, &y ); |
| if ( x.isNaN || y.isNaN ) { |
| slowfloat_exceptionFlags |= softfloat_flag_invalid; |
| } |
| return floatXLt( &x, &y ); |
| |
| } |
| |
| bool slow_f64_eq_signaling( float64_t a, float64_t b ) |
| { |
| struct floatX x, y; |
| |
| f64ToFloatX( a, &x ); |
| f64ToFloatX( b, &y ); |
| if ( x.isNaN || y.isNaN ) { |
| slowfloat_exceptionFlags |= softfloat_flag_invalid; |
| } |
| return floatXEq( &x, &y ); |
| |
| } |
| |
| bool slow_f64_le_quiet( float64_t a, float64_t b ) |
| { |
| struct floatX x, y; |
| |
| f64ToFloatX( a, &x ); |
| f64ToFloatX( b, &y ); |
| return floatXLe( &x, &y ); |
| |
| } |
| |
| bool slow_f64_lt_quiet( float64_t a, float64_t b ) |
| { |
| struct floatX x, y; |
| |
| f64ToFloatX( a, &x ); |
| f64ToFloatX( b, &y ); |
| return floatXLt( &x, &y ); |
| |
| } |
| |
| #ifdef EXTFLOAT80 |
| |
| uint_fast32_t |
| slow_extF80M_to_ui32( |
| const extFloat80_t *aPtr, uint_fast8_t roundingMode, bool exact ) |
| { |
| struct floatX x; |
| |
| extF80MToFloatX( aPtr, &x ); |
| return floatXToUI32( &x, roundingMode, exact ); |
| |
| } |
| |
| uint_fast64_t |
| slow_extF80M_to_ui64( |
| const extFloat80_t *aPtr, uint_fast8_t roundingMode, bool exact ) |
| { |
| struct floatX x; |
| |
| extF80MToFloatX( aPtr, &x ); |
| return floatXToUI64( &x, roundingMode, exact ); |
| |
| } |
| |
| int_fast32_t |
| slow_extF80M_to_i32( |
| const extFloat80_t *aPtr, uint_fast8_t roundingMode, bool exact ) |
| { |
| struct floatX x; |
| |
| extF80MToFloatX( aPtr, &x ); |
| return floatXToI32( &x, roundingMode, exact ); |
| |
| } |
| |
| int_fast64_t |
| slow_extF80M_to_i64( |
| const extFloat80_t *aPtr, uint_fast8_t roundingMode, bool exact ) |
| { |
| struct floatX x; |
| |
| extF80MToFloatX( aPtr, &x ); |
| return floatXToI64( &x, roundingMode, exact ); |
| |
| } |
| |
| uint_fast32_t |
| slow_extF80M_to_ui32_r_minMag( const extFloat80_t *aPtr, bool exact ) |
| { |
| struct floatX x; |
| |
| extF80MToFloatX( aPtr, &x ); |
| return floatXToUI32( &x, softfloat_round_minMag, exact ); |
| |
| } |
| |
| uint_fast64_t |
| slow_extF80M_to_ui64_r_minMag( const extFloat80_t *aPtr, bool exact ) |
| { |
| struct floatX x; |
| |
| extF80MToFloatX( aPtr, &x ); |
| return floatXToUI64( &x, softfloat_round_minMag, exact ); |
| |
| } |
| |
| int_fast32_t |
| slow_extF80M_to_i32_r_minMag( const extFloat80_t *aPtr, bool exact ) |
| { |
| struct floatX x; |
| |
| extF80MToFloatX( aPtr, &x ); |
| return floatXToI32( &x, softfloat_round_minMag, exact ); |
| |
| } |
| |
| int_fast64_t |
| slow_extF80M_to_i64_r_minMag( const extFloat80_t *aPtr, bool exact ) |
| { |
| struct floatX x; |
| |
| extF80MToFloatX( aPtr, &x ); |
| return floatXToI64( &x, softfloat_round_minMag, exact ); |
| |
| } |
| |
| float32_t slow_extF80M_to_f32( const extFloat80_t *aPtr ) |
| { |
| struct floatX x; |
| |
| extF80MToFloatX( aPtr, &x ); |
| return floatXToF32( &x ); |
| |
| } |
| |
| float64_t slow_extF80M_to_f64( const extFloat80_t *aPtr ) |
| { |
| struct floatX x; |
| |
| extF80MToFloatX( aPtr, &x ); |
| return floatXToF64( &x ); |
| |
| } |
| |
| #ifdef FLOAT128 |
| |
| void slow_extF80M_to_f128M( const extFloat80_t *aPtr, float128_t *zPtr ) |
| { |
| struct floatX x; |
| |
| extF80MToFloatX( aPtr, &x ); |
| floatXToF128M( &x, zPtr ); |
| |
| } |
| |
| #endif |
| |
| void |
| slow_extF80M_roundToInt( |
| const extFloat80_t *aPtr, |
| uint_fast8_t roundingMode, |
| bool exact, |
| extFloat80_t *zPtr |
| ) |
| { |
| struct floatX x; |
| |
| extF80MToFloatX( aPtr, &x ); |
| floatXRoundToInt( &x, roundingMode, exact ); |
| floatXToExtF80M( &x, zPtr ); |
| |
| } |
| |
| void |
| slow_extF80M_add( |
| const extFloat80_t *aPtr, const extFloat80_t *bPtr, extFloat80_t *zPtr ) |
| { |
| struct floatX x, y; |
| |
| extF80MToFloatX( aPtr, &x ); |
| extF80MToFloatX( bPtr, &y ); |
| floatXAdd( &x, &y ); |
| floatXToExtF80M( &x, zPtr ); |
| |
| } |
| |
| void |
| slow_extF80M_sub( |
| const extFloat80_t *aPtr, const extFloat80_t *bPtr, extFloat80_t *zPtr ) |
| { |
| struct floatX x, y; |
| |
| extF80MToFloatX( aPtr, &x ); |
| extF80MToFloatX( bPtr, &y ); |
| y.sign = ! y.sign; |
| floatXAdd( &x, &y ); |
| floatXToExtF80M( &x, zPtr ); |
| |
| } |
| |
| void |
| slow_extF80M_mul( |
| const extFloat80_t *aPtr, const extFloat80_t *bPtr, extFloat80_t *zPtr ) |
| { |
| struct floatX x, y; |
| |
| extF80MToFloatX( aPtr, &x ); |
| extF80MToFloatX( bPtr, &y ); |
| floatXMul( &x, &y ); |
| floatXToExtF80M( &x, zPtr ); |
| |
| } |
| |
| void |
| slow_extF80M_div( |
| const extFloat80_t *aPtr, const extFloat80_t *bPtr, extFloat80_t *zPtr ) |
| { |
| struct floatX x, y; |
| |
| extF80MToFloatX( aPtr, &x ); |
| extF80MToFloatX( bPtr, &y ); |
| floatXDiv( &x, &y ); |
| floatXToExtF80M( &x, zPtr ); |
| |
| } |
| |
| void |
| slow_extF80M_rem( |
| const extFloat80_t *aPtr, const extFloat80_t *bPtr, extFloat80_t *zPtr ) |
| { |
| struct floatX x, y; |
| |
| extF80MToFloatX( aPtr, &x ); |
| extF80MToFloatX( bPtr, &y ); |
| floatXRem( &x, &y ); |
| floatXToExtF80M( &x, zPtr ); |
| |
| } |
| |
| void slow_extF80M_sqrt( const extFloat80_t *aPtr, extFloat80_t *zPtr ) |
| { |
| struct floatX x; |
| |
| extF80MToFloatX( aPtr, &x ); |
| floatXSqrt( &x ); |
| floatXToExtF80M( &x, zPtr ); |
| |
| } |
| |
| bool slow_extF80M_eq( const extFloat80_t *aPtr, const extFloat80_t *bPtr ) |
| { |
| struct floatX x, y; |
| |
| extF80MToFloatX( aPtr, &x ); |
| extF80MToFloatX( bPtr, &y ); |
| return floatXEq( &x, &y ); |
| |
| } |
| |
| bool slow_extF80M_le( const extFloat80_t *aPtr, const extFloat80_t *bPtr ) |
| { |
| struct floatX x, y; |
| |
| extF80MToFloatX( aPtr, &x ); |
| extF80MToFloatX( bPtr, &y ); |
| if ( x.isNaN || y.isNaN ) { |
| slowfloat_exceptionFlags |= softfloat_flag_invalid; |
| } |
| return floatXLe( &x, &y ); |
| |
| } |
| |
| bool slow_extF80M_lt( const extFloat80_t *aPtr, const extFloat80_t *bPtr ) |
| { |
| struct floatX x, y; |
| |
| extF80MToFloatX( aPtr, &x ); |
| extF80MToFloatX( bPtr, &y ); |
| if ( x.isNaN || y.isNaN ) { |
| slowfloat_exceptionFlags |= softfloat_flag_invalid; |
| } |
| return floatXLt( &x, &y ); |
| |
| } |
| |
| bool |
| slow_extF80M_eq_signaling( |
| const extFloat80_t *aPtr, const extFloat80_t *bPtr ) |
| { |
| struct floatX x, y; |
| |
| extF80MToFloatX( aPtr, &x ); |
| extF80MToFloatX( bPtr, &y ); |
| if ( x.isNaN || y.isNaN ) { |
| slowfloat_exceptionFlags |= softfloat_flag_invalid; |
| } |
| return floatXEq( &x, &y ); |
| |
| } |
| |
| bool slow_extF80M_le_quiet( const extFloat80_t *aPtr, const extFloat80_t *bPtr ) |
| { |
| struct floatX x, y; |
| |
| extF80MToFloatX( aPtr, &x ); |
| extF80MToFloatX( bPtr, &y ); |
| return floatXLe( &x, &y ); |
| |
| } |
| |
| bool slow_extF80M_lt_quiet( const extFloat80_t *aPtr, const extFloat80_t *bPtr ) |
| { |
| struct floatX x, y; |
| |
| extF80MToFloatX( aPtr, &x ); |
| extF80MToFloatX( bPtr, &y ); |
| return floatXLt( &x, &y ); |
| |
| } |
| |
| #endif |
| |
| #ifdef FLOAT128 |
| |
| uint_fast32_t |
| slow_f128M_to_ui32( |
| const float128_t *aPtr, uint_fast8_t roundingMode, bool exact ) |
| { |
| struct floatX x; |
| |
| f128MToFloatX( aPtr, &x ); |
| return floatXToUI32( &x, roundingMode, exact ); |
| |
| } |
| |
| uint_fast64_t |
| slow_f128M_to_ui64( |
| const float128_t *aPtr, uint_fast8_t roundingMode, bool exact ) |
| { |
| struct floatX x; |
| |
| f128MToFloatX( aPtr, &x ); |
| return floatXToUI64( &x, roundingMode, exact ); |
| |
| } |
| |
| int_fast32_t |
| slow_f128M_to_i32( |
| const float128_t *aPtr, uint_fast8_t roundingMode, bool exact ) |
| { |
| struct floatX x; |
| |
| f128MToFloatX( aPtr, &x ); |
| return floatXToI32( &x, roundingMode, exact ); |
| |
| } |
| |
| int_fast64_t |
| slow_f128M_to_i64( |
| const float128_t *aPtr, uint_fast8_t roundingMode, bool exact ) |
| { |
| struct floatX x; |
| |
| f128MToFloatX( aPtr, &x ); |
| return floatXToI64( &x, roundingMode, exact ); |
| |
| } |
| |
| uint_fast32_t slow_f128M_to_ui32_r_minMag( const float128_t *aPtr, bool exact ) |
| { |
| struct floatX x; |
| |
| f128MToFloatX( aPtr, &x ); |
| return floatXToUI32( &x, softfloat_round_minMag, exact ); |
| |
| } |
| |
| uint_fast64_t slow_f128M_to_ui64_r_minMag( const float128_t *aPtr, bool exact ) |
| { |
| struct floatX x; |
| |
| f128MToFloatX( aPtr, &x ); |
| return floatXToUI64( &x, softfloat_round_minMag, exact ); |
| |
| } |
| |
| int_fast32_t slow_f128M_to_i32_r_minMag( const float128_t *aPtr, bool exact ) |
| { |
| struct floatX x; |
| |
| f128MToFloatX( aPtr, &x ); |
| return floatXToI32( &x, softfloat_round_minMag, exact ); |
| |
| } |
| |
| int_fast64_t slow_f128M_to_i64_r_minMag( const float128_t *aPtr, bool exact ) |
| { |
| struct floatX x; |
| |
| f128MToFloatX( aPtr, &x ); |
| return floatXToI64( &x, softfloat_round_minMag, exact ); |
| |
| } |
| |
| float32_t slow_f128M_to_f32( const float128_t *aPtr ) |
| { |
| struct floatX x; |
| |
| f128MToFloatX( aPtr, &x ); |
| return floatXToF32( &x ); |
| |
| } |
| |
| float64_t slow_f128M_to_f64( const float128_t *aPtr ) |
| { |
| struct floatX x; |
| |
| f128MToFloatX( aPtr, &x ); |
| return floatXToF64( &x ); |
| |
| } |
| |
| #ifdef EXTFLOAT80 |
| |
| void slow_f128M_to_extF80M( const float128_t *aPtr, extFloat80_t *zPtr ) |
| { |
| struct floatX x; |
| |
| f128MToFloatX( aPtr, &x ); |
| floatXToExtF80M( &x, zPtr ); |
| |
| } |
| |
| #endif |
| |
| void |
| slow_f128M_roundToInt( |
| const float128_t *aPtr, |
| uint_fast8_t roundingMode, |
| bool exact, |
| float128_t *zPtr |
| ) |
| { |
| struct floatX x; |
| |
| f128MToFloatX( aPtr, &x ); |
| floatXRoundToInt( &x, roundingMode, exact ); |
| floatXToF128M( &x, zPtr ); |
| |
| } |
| |
| void |
| slow_f128M_add( |
| const float128_t *aPtr, const float128_t *bPtr, float128_t *zPtr ) |
| { |
| struct floatX x, y; |
| |
| f128MToFloatX( aPtr, &x ); |
| f128MToFloatX( bPtr, &y ); |
| floatXAdd( &x, &y ); |
| floatXToF128M( &x, zPtr ); |
| |
| } |
| |
| void |
| slow_f128M_sub( |
| const float128_t *aPtr, const float128_t *bPtr, float128_t *zPtr ) |
| { |
| struct floatX x, y; |
| |
| f128MToFloatX( aPtr, &x ); |
| f128MToFloatX( bPtr, &y ); |
| y.sign = ! y.sign; |
| floatXAdd( &x, &y ); |
| floatXToF128M( &x, zPtr ); |
| |
| } |
| |
| void |
| slow_f128M_mul( |
| const float128_t *aPtr, const float128_t *bPtr, float128_t *zPtr ) |
| { |
| struct floatX x, y; |
| |
| f128MToFloatX( aPtr, &x ); |
| f128MToFloatX( bPtr, &y ); |
| floatXMul( &x, &y ); |
| floatXToF128M( &x, zPtr ); |
| |
| } |
| |
| void |
| slow_f128M_mulAdd( |
| const float128_t *aPtr, |
| const float128_t *bPtr, |
| const float128_t *cPtr, |
| float128_t *zPtr |
| ) |
| { |
| struct floatX256 x, y; |
| |
| f128MToFloatX256( aPtr, &x ); |
| f128MToFloatX256( bPtr, &y ); |
| floatX256Mul( &x, &y ); |
| f128MToFloatX256( cPtr, &y ); |
| floatX256Add( &x, &y ); |
| floatX256ToF128M( &x, zPtr ); |
| |
| } |
| |
| void |
| slow_f128M_div( |
| const float128_t *aPtr, const float128_t *bPtr, float128_t *zPtr ) |
| { |
| struct floatX x, y; |
| |
| f128MToFloatX( aPtr, &x ); |
| f128MToFloatX( bPtr, &y ); |
| floatXDiv( &x, &y ); |
| floatXToF128M( &x, zPtr ); |
| |
| } |
| |
| void |
| slow_f128M_rem( |
| const float128_t *aPtr, const float128_t *bPtr, float128_t *zPtr ) |
| { |
| struct floatX x, y; |
| |
| f128MToFloatX( aPtr, &x ); |
| f128MToFloatX( bPtr, &y ); |
| floatXRem( &x, &y ); |
| floatXToF128M( &x, zPtr ); |
| |
| } |
| |
| void slow_f128M_sqrt( const float128_t *aPtr, float128_t *zPtr ) |
| { |
| struct floatX x; |
| |
| f128MToFloatX( aPtr, &x ); |
| floatXSqrt( &x ); |
| floatXToF128M( &x, zPtr ); |
| |
| } |
| |
| bool slow_f128M_eq( const float128_t *aPtr, const float128_t *bPtr ) |
| { |
| struct floatX x, y; |
| |
| f128MToFloatX( aPtr, &x ); |
| f128MToFloatX( bPtr, &y ); |
| return floatXEq( &x, &y ); |
| |
| } |
| |
| bool slow_f128M_le( const float128_t *aPtr, const float128_t *bPtr ) |
| { |
| struct floatX x, y; |
| |
| f128MToFloatX( aPtr, &x ); |
| f128MToFloatX( bPtr, &y ); |
| if ( x.isNaN || y.isNaN ) { |
| slowfloat_exceptionFlags |= softfloat_flag_invalid; |
| } |
| return floatXLe( &x, &y ); |
| |
| } |
| |
| bool slow_f128M_lt( const float128_t *aPtr, const float128_t *bPtr ) |
| { |
| struct floatX x, y; |
| |
| f128MToFloatX( aPtr, &x ); |
| f128MToFloatX( bPtr, &y ); |
| if ( x.isNaN || y.isNaN ) { |
| slowfloat_exceptionFlags |= softfloat_flag_invalid; |
| } |
| return floatXLt( &x, &y ); |
| |
| } |
| |
| bool slow_f128M_eq_signaling( const float128_t *aPtr, const float128_t *bPtr ) |
| { |
| struct floatX x, y; |
| |
| f128MToFloatX( aPtr, &x ); |
| f128MToFloatX( bPtr, &y ); |
| if ( x.isNaN || y.isNaN ) { |
| slowfloat_exceptionFlags |= softfloat_flag_invalid; |
| } |
| return floatXEq( &x, &y ); |
| |
| } |
| |
| bool slow_f128M_le_quiet( const float128_t *aPtr, const float128_t *bPtr ) |
| { |
| struct floatX x, y; |
| |
| f128MToFloatX( aPtr, &x ); |
| f128MToFloatX( bPtr, &y ); |
| return floatXLe( &x, &y ); |
| |
| } |
| |
| bool slow_f128M_lt_quiet( const float128_t *aPtr, const float128_t *bPtr ) |
| { |
| struct floatX x, y; |
| |
| f128MToFloatX( aPtr, &x ); |
| f128MToFloatX( bPtr, &y ); |
| return floatXLt( &x, &y ); |
| |
| } |
| |
| #endif |
| |