ieee754.c

来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 650 行 · 第 1/2 页

C
650
字号
cfloat *IEEECFToCF
/****************/
    ( cfloat *cf
    , CF_PRECISION prec )
{
    cfloat *new_cf = IEEECheckRange( cf, prec );
    if( new_cf == cf ) {
        new_cf = IEEECFToCFNotSpecial( cf, prec );
    }
    return( new_cf );
}

cfloat * IEEECFDiv
/****************/
    ( cfloat *left
    , cfloat *right
    , CF_PRECISION prec )
{
    cfloat *new_val;

    if( IEEEIsSpecialValue( left  ) || IEEEIsSpecialValue( right ) ) {
        // at least one is Nan, PosInf, or NegInf
        if( left == IEEEGetNaN() || right == IEEEGetNaN() ) {
            return IEEEGetNaN();        // NaN / float = float / NaN = NaN
        } else {
            // if neither was NaN, at least one must be inf
            cfloat *inf;
            cfloat *other;
            if( IEEEIsInf( left ) ) {
                inf = left;
                other = right;
            } else {
                DbgAssert( IEEEIsInf( right ) );
                inf = right;
                other = left;
            }
            if( IEEEIsInf( other ) ) {
                return IEEEGetNaN();    // inf / inf = NaN
            }
            // only one infinity
            if( left == inf ) {
                // left is infinity, right is not
                if( CFGetPosNeg( left ) * CFGetPosNeg( right ) < 0 ) {
                    return( IEEEGetNegInf() ); // inf / -ve or -inf / +ve = -inf
                } else {
                    return( IEEEGetPosInf() ); // inf / +ve or -inf / -ve = +inf
                }
            } else {
                DbgAssert( right == inf );
                // right is infinity
                if( CFGetPosNeg( left ) * CFGetPosNeg( right ) < 0 ) {
                    // -ve/inf or +ve/-inf = -0
                    return( CFNegate( CFCnvI32F( 0 ) ) );
                } else {
                    return( CFCnvI32F( 0 ) );   // +ve/inf or -ve/-inf = 0
                }
            }
        }
    } else if( CFTest( right ) ) {
        // right is not zero
        if( CFTest( left ) ) {
            // left is not zero
            new_val = IEEECFToCF( CFDiv( left, right ), prec );
        } else {
            // left is zero (-0.0 or 0.0)
            new_val = IEEECFToCF( CFCopy( left ), prec );
        }
    } else {
        // right is zero
        if( CFTest( left ) ) {
            // left not zero
            if( ( CFTest( left ) * CFGetZeroSign( right ) ) > 0 ) {
                // zero or two positives: positive infinity
                new_val = IEEEGetPosInf();
            } else {
                // one negative: negative infinity
                new_val = IEEEGetNegInf();
            }
        } else {
            // both are zero: NaN
            new_val = IEEEGetNaN();
        }
    }
    return( new_val );
}

cfloat * IEEECFMod              // IEEE MODULUS
/****************/
    ( cfloat *left
    , cfloat *right
    , CF_PRECISION prec )

{
    cfloat *retn = NULL;

    if( IEEEIsSpecialValue( left  ) || IEEEIsSpecialValue( right ) ) {
        if( IEEEIsSpecialValue( left )  // NaN%float=inf%float=-inf%float=NaN
         || right == IEEEGetNaN()       // float % NaN = Nan
         || CFTest( right ) == 0 ) {    // float % 0 = Nan
            retn = IEEEGetNaN();
        } else if( IEEEIsInf( right ) ) {
            // finite / inf = finite
            retn = left;
        }
    } else if( CFTest( left ) == 0 ) {
        retn = left;    // 0 % finite = 0
    } else if( CFTest( right ) == 0 ) {
        // x % 0 = NaN
        retn = IEEEGetNaN();
    } else {
        // left / right = result;
        // left % right = ( left - (right * result ) );
        cfloat *result;
        result = CFTrunc( CFDiv( left, right ) );
        retn = IEEECFToCF( CFSub( left, CFMul( right, result ) ), prec );
    }
    DbgAssert( retn != NULL );
    return( retn );
}

cfloat * IEEECFMul                      // IEEE MULTIPLY
/****************/
    ( cfloat *left
    , cfloat *right
    , CF_PRECISION prec )
{
    if( IEEEIsSpecialValue( left  ) || IEEEIsSpecialValue( right ) ) {
        // JLS 15.16.1
        if( left == IEEEGetNaN() || right == IEEEGetNaN() ) {
            return IEEEGetNaN();        // NaN * float = float* NaN = NaN
        } else {
            // if neither was NaN, at least one must be inf
            cfloat *inf;
            cfloat *other;
            if( IEEEIsInf( left ) ) {
                inf = left;
                other = right;
            } else {
                DbgAssert( IEEEIsInf( right ) );
                inf = right;
                other = left;
            }
            if( CFGetSign( other ) == 0 ) {
                return( IEEEGetNaN() ); // inf * zero = zero * inf = NaN
            } else {
                // num * inf = inf * num = inf
                // sign of result is determined by signs of inf and num
                if( ( CFGetSign( inf ) * CFGetSign( other ) ) > 0 ) {
                    return IEEEGetPosInf();
                } else {
                    return IEEEGetNegInf();
                }
            }
        }
    } else {
        return( IEEECFToCF( CFMul( left, right ), prec ) );
    }
}

cfloat * IEEECFNegate
/*******************/
    ( cfloat *f
    , CF_PRECISION prec )
{
    if( f == PosInf ) {
        return NegInf;
    } else if( f == NegInf ) {
        return PosInf;
    } else if( f == NaN ) {
        return f;
    } else {
        // CFNegate doesn't make a copy so we have to call CFCopyNegate
        // as upper layers expect to be able to discard operands after
        // result of operation is returned
        return( CFCopyNegate( f ) );
    }
}

cfloat * IEEECFAdd              // IEEE ADDITION
/****************/
    ( cfloat *left
    , cfloat *right
    , CF_PRECISION prec )
{
    cfloat *retn = NULL;

    if( IEEEIsSpecialValue( left  ) || IEEEIsSpecialValue( right ) ) {
        // JLS 15.17.2
        if( left == IEEEGetNaN() || right == IEEEGetNaN() ) {
            retn = IEEEGetNaN();        // NaN + float = float + NaN = NaN
        } else {
            cfloat *inf;
            cfloat *other;
            // one or both are infinity;
            if( IEEEIsInf( left ) ) {
                inf = left;
                other = right;
            } else {
                inf = right;
                other = left;
            }
            if( IEEEIsInf( other ) ) {
                // both are infinite
                if( CFGetPosNeg( inf ) * CFGetPosNeg( other ) < 0 ) {
                    // inf + -inf = -inf + inf = NaN
                    retn = IEEEGetNaN();
                } else {
                    // both inf, same sign:
                    // -inf + -inf = -inf
                    // inf + inf = inf
                    retn = left;
                }
            } else {
                // one infinite, one finite
                // float + inf = inf
                retn = inf;
            }
        }
    } else {
        // not a special value
        if( CFTest( left ) * CFTest( right ) == 0 ) {
            // one or both is zero
            if( CFTest( left ) != 0 ) {
                retn = left;    // float + 0 = float
            } else if( CFTest( right ) != 0 ) {
                retn = right;   // 0 + float = float
            } else {
                //both zero
                if( CFGetZeroSign( left ) * CFGetZeroSign( right ) < 0 ) {
                    // opposite sign, return +ve zero
                    if( CFGetZeroSign( left ) > 0 ) {
                        retn = left;
                    } else {
                        retn = right;
                    }
                } else {
                    // same sign, return either
                    retn = left;
                }
            }
        } else {
            // neither is zero
            retn = CFAdd( left, right );
            if( CFTest( retn ) == 0 ) {
                // a zero result should be +ve zero
                CFSetZeroSign( retn, 1 );
            } else {
                retn = IEEECFToCF( retn, prec );
            }
        }
    }
    DbgAssert( retn != NULL );
    return retn;
}
//---------------------- comparison functions ---------------------

static int compareInf
    ( cfloat *left
    , cfloat *right )
{
    if( left == right ) {       //  inf cmp  inf or
        return 0;               // -inf cmp -inf
    } else {
        if( left == IEEEGetNegInf() ) { // -inf cmp num  or
            return( -1 );               // -inf cmp inf
        } else if( right == IEEEGetPosInf() ) { //  num cmp inf or
            return( -1 );                       // -inf cmp inf
        } else {
            return( 1 );        // inf cmp num
                                // num cmp -inf
        }
    }
}

cf_bool IEEECFCmp               // IEEE COMPARISON
/***************/
    ( cfloat *left
    , cfloat *right
    , CF_COMPARE cmp )
{
    cf_bool retn = -2;
    int result;
    if( IEEEIsSpecialValue( left  ) || IEEEIsSpecialValue( right ) ) {
        if( left == IEEEGetNaN() || right == IEEEGetNaN() ) {
            if( cmp == CF_CMP_NE ) {     // val != NaN = val != NaN = true
                return( CF_TRUE );       // n.b. NaN != NaN = true
            } else {
                // at least one NaN
                return( CF_FALSE );
            }
        } else {
            // at least one must be infinite
            result = compareInf( left, right );
        }
    } else {
        result = CFCompare( left, right );
    }
    DbgAssert( result == -1 || result == 1 || result == 0 );
    switch( cmp  ) {
    case CF_CMP_NONE :
        DbgNever();
        break;
    case CF_CMP_LT :
        retn = ( result < 0 );
        break;
    case CF_CMP_LE :
        retn = ( result <= 0 );
        break;
    case CF_CMP_GT :
        retn = ( result > 0 );
        break;
    case CF_CMP_GE :
        retn = ( result >= 0 );
        break;
    case CF_CMP_EQ :
        retn = ( result == 0 );
        break;
    case CF_CMP_NE :
        retn = ( result != 0 );
        break;
    }
    return( retn );
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?