ieee754.c

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

C
650
字号
/****************************************************************************
*
*                            Open Watcom Project
*
*    Portions Copyright (c) 1983-2002 Sybase, Inc. All Rights Reserved.
*
*  ========================================================================
*
*    This file contains Original Code and/or Modifications of Original
*    Code as defined in and that are subject to the Sybase Open Watcom
*    Public License version 1.0 (the 'License'). You may not use this file
*    except in compliance with the License. BY USING THIS FILE YOU AGREE TO
*    ALL TERMS AND CONDITIONS OF THE LICENSE. A copy of the License is
*    provided with the Original Code and Modifications, and is also
*    available at www.sybase.com/developer/opensource.
*
*    The Original Code and all software distributed under the License are
*    distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
*    EXPRESS OR IMPLIED, AND SYBASE AND ALL CONTRIBUTORS HEREBY DISCLAIM
*    ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF
*    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR
*    NON-INFRINGEMENT. Please see the License for the specific language
*    governing rights and limitations under the License.
*
*  ========================================================================
*
* Description:  WHEN YOU FIGURE OUT WHAT THIS FILE DOES, PLEASE
*               DESCRIBE IT HERE!
*
****************************************************************************/


#include header

#include <string.h>
#include <stdio.h>
#include "watcom.h"
#include "cfloat.h"
#include "ieee754.h"
#include "xfloat.h"

cfloat *PosInf = NULL;
cfloat *NegInf = NULL;
cfloat *NaN = NULL;
cfloat *MaxPosIEEE32 = NULL;
cfloat *MinPosIEEE32 = NULL;
cfloat *MaxNegIEEE32 = NULL;
cfloat *MinNegIEEE32 = NULL;

cfloat *MaxPosIEEE64 = NULL;
cfloat *MinPosIEEE64 = NULL;
cfloat *MaxNegIEEE64 = NULL;
cfloat *MinNegIEEE64 = NULL;

#define MAX_TRIES 4

// Float.MAX_VALUE = 3.40282347e+38f
// mant: 340282347
// exp: 39 (ie. think of this as 0.340282347 exp 39
static struct STRUCT_cfloat( 18 )     MaxIEEE32 = {
                        39,             /* exponent base ten */
                        9,              /* mantissa length base ten */
                        0,              /* allocation length */
                        1,              /* sign: positive */
                        {'3','4','0','2','8','2','3','4','7',0 }
                        };

// public static final float MIN_VALUE = 1.40129846e-45f;
static struct STRUCT_cfloat( 19 )     MinIEEE32 = {
                        -44,            /* exponent base ten */
                        9,              /* mantissa length base ten */
                        0,              /* allocation length */
                        1,              /* sign: positive */
                        {'1','4','0','1','2','9','8','4','6', 0 }
                        };

// Double.MAX_VALUE = 1.79769313486231570e+308
static struct STRUCT_cfloat( 18 )     MaxIEEE64 = {
                        309,            /* exponent base ten */
                        17,             /* mantissa length base ten */
                        0,              /* allocation length */
                        1,              /* sign: positive */
                        { '1','7','9','7','6','9','3','1','3','4','8','6','2','3','1','5','7',0 }
                        };

//  public static final double MIN_VALUE = 4.94065645841246544e-324;
static struct STRUCT_cfloat( 19 )     MinIEEE64 = {
                        -323,           /* exponent base ten */
                        18,             /* mantissa length base ten */
                        0,              /* allocation length */
                        1,              /* sign: positive */
                        { '4','9','4','0','6','5','6','4','5','8','4','1','2','4','6','5','4','4',0}
                        };

cfloat *IEEECFToCFNotSpecial
/**************************/
    ( cfloat *cf
    , CF_PRECISION prec )
{
    // could be too much precision
    cfloat *new_cf;
    if( prec == CF_32 ) {
        char buffer[64];
        volatile float f = CFToF( cf );
        sprintf( buffer, "%.15e", f );
        new_cf = CFCnvSF( (char *)buffer, (char *)(buffer + strlen(buffer)) );
    } else {
        int num_tries;
        double d, d2;
        unsigned __int64 u, u2;

        char buffer[64];
        d = CFToF( cf ); // precision: infinite->64 bits
        sprintf( buffer, "%.15e", d );
        new_cf = CFCnvSF( (char *)buffer, (char *)(buffer + strlen(buffer)) );

        // check if it converts back to what we wanted
        d2 = CFToF( new_cf );

        u = *(unsigned __int64 *)&d;
        u2 = *(unsigned __int64 *)&d2;

        for( num_tries = 0;
             ( u != u2 ) &&
             ( num_tries < MAX_TRIES ) &&
             ( cf->len > new_cf->len);
             num_tries++ ) {
            // didn't convert back just right
            cfloat      *newer;

            // add another digit
            newer = CFAlloc( new_cf->len + 1 );
            memcpy( newer, new_cf, offsetof( cfloat, mant ) + new_cf->len + 1 );
            CFDeposit( newer, new_cf->len -1, CFAccess( cf, new_cf->len-1 ) );
            CFDeposit( newer, new_cf->len, CFAccess( cf, new_cf->len ) );
            newer->len++;
            newer->mant[newer->len] = '\0';
            CFFree( new_cf );
            new_cf = newer;
            newer = NULL;

            d2 = CFToF( new_cf );
            u2 = *(unsigned __int64 *)&d2;
        }
    }
    if( CFCompare( new_cf, cf ) != 0 ) {
        if( ( cf->len == ( new_cf->len + 1 ) ) && ( prec == CF_64 ) ) {
            // if we just shaved off one digit, don't bother taking the
            // new one for doubles (need this extra digit for proper
            // arithmetic in outer ranges of doubles
            CFFree( new_cf );
        } else {
            CFFree( cf );
            cf = new_cf;
        }
    } else {
        // they are the same, so no truncation was really needed
        CFFree( new_cf );
    }
    return( cf );
}

#if 0
// need special code to get value for MinPosIEEE64
// it's hard to get anything other than zero for this
cfloat *getMinPos()
{
    char buffer[64];
    unsigned_64 u64;
    double d;

    u64.u._64[0] = 0x80000000L;
    d = *(double *)&u64;
    sprintf( buffer, "%.15e", d );
    return( CFCnvSF( (char *)buffer, (char *)(buffer + strlen(buffer)) ) );
}
#endif

void IEEEInit
/***********/
    ( void )
{
    PosInf = CFCnvI32F( 1 );    // so it has correct sign
    NegInf = CFCnvI32F( -1 );   // so it has correct sign
    NaN = CFCnvI32F( 0 );

    // if we do IEEECFToCFNotSpecial on MaxPosIEEE32, we get back too many
    // digits of precision
    MaxPosIEEE32 = CFCopy( (cfloat *)&MaxIEEE32 );
    MinPosIEEE32 = IEEECFToCFNotSpecial( CFCopy( (cfloat *)&MinIEEE32 ), CF_32 );
    MaxPosIEEE64 = IEEECFToCFNotSpecial( CFCopy( (cfloat *)&MaxIEEE64 ), CF_64 );

    MinPosIEEE64 = CFCopy( (cfloat *)&MinIEEE64 );
#if 0
    MinPosIEEE64 = IEEECFToCFNotSpecial( getMinPos(), CF_64 );
#endif


    MaxNegIEEE32 = IEEECFToCFNotSpecial( CFCopyNegate( MaxPosIEEE32 ), CF_32 );
    MinNegIEEE32 = IEEECFToCFNotSpecial( CFCopyNegate( MinPosIEEE32 ), CF_32 );
    MaxNegIEEE64 = IEEECFToCFNotSpecial( CFCopyNegate( MaxPosIEEE64 ), CF_64 );
    MinNegIEEE64 = IEEECFToCFNotSpecial( CFCopyNegate( MinPosIEEE64 ), CF_64 );

}

void IEEEFini
/***********/
    ( void )
{
    CFFree( PosInf );
    CFFree( NegInf );
    CFFree( NaN );

    CFFree( MaxPosIEEE32 );
    CFFree( MaxPosIEEE64 );
    CFFree( MinPosIEEE32 );
    CFFree( MinPosIEEE64 );

    CFFree( MaxNegIEEE32 );
    CFFree( MaxNegIEEE64 );
    CFFree( MinNegIEEE32 );
    CFFree( MinNegIEEE64 );

    PosInf = NULL;
    NegInf = NULL;
    NaN = NULL;
}

cfloat *IEEEGetPosInf
/******************/
    (void)
{
    return PosInf;
}

cfloat *IEEEGetNegInf
/*******************/
    (void)
{
    return NegInf;
}

cfloat *IEEEGetNaN
/****************/
    (void)
{
    return NaN;
}

cf_bool IEEEIsSpecialValue
/************************/
    (cfloat *f)
{
    if( (f == NegInf) || (f == PosInf) || (f == NaN) ) {
        return( CF_TRUE );
    } else {
        return( CF_FALSE );
    }
}

static cf_bool IEEEIsInf
/************************/
    (cfloat *f)
{
    if( (f == NegInf) || (f == PosInf) ) {
        return( CF_TRUE );
    } else {
        return( CF_FALSE );
    }
}

void IEEECFFree                 // FREE CFLOAT (UNLESS SPECIAL VALUE)
/**************/
    ( cfloat * cf )
{
    if( IEEEIsSpecialValue( cf ) != CF_TRUE ) {
//      CFFree( cf );
    }
}

cfloat *IEEECheckRange
/********************/
    ( cfloat *cf
    , CF_PRECISION prec )
{
    cfloat *minpos;
    cfloat *minneg;
    cfloat *maxpos;
    cfloat *maxneg;

    if( prec == CF_32 ) {
        maxpos = MaxPosIEEE32;
        maxneg = MaxNegIEEE32;
        minpos = MinPosIEEE32;
        minneg = MinNegIEEE32;
    } else {
        maxpos = MaxPosIEEE64;
        maxneg = MaxNegIEEE64;
        minpos = MinPosIEEE64;
        minneg = MinNegIEEE64;
    }
    if( CFGetSign( cf ) > 0 ) { // cf positive
        if( CFCompare( cf, maxpos ) > 0 ) { // cf > maxpos
            IEEECFFree( cf );
            return( IEEEGetPosInf() );
        }
        if( CFCompare( cf, minpos ) < 0 ) { // cf < minpos
            IEEECFFree( cf );
            return( CFCnvI32F( 0 ) );       // positive zero
        }
    } else if( CFGetSign( cf ) < 0 ) {    // cf is negative
        if( CFCompare( cf, maxneg ) < 0 ) { // cf < maxneg
            IEEECFFree( cf );
            return( IEEEGetNegInf() );
        }
        if( CFCompare( cf, minneg ) > 0 ) { // cf > minneg
            IEEECFFree( cf );
            return( CFNegate( CFCnvI32F( 0 ) ) );       // negative zero
        }
    }
    return( cf );
}

// assumtions: cf will not be NaN, but may be greater than
// infinity or less than negative infinity of the given precision

⌨️ 快捷键说明

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