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 + -
显示快捷键?