asciifp.c
来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 568 行 · 第 1/2 页
C
568 行
/****************************************************************************
*
* 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!
*
****************************************************************************/
/* This module defines functions for converting between floating point numbers
* and ascii strings. It uses multiply precions integers to get accurate
* results.
*/
#include <stdio.h>
#include <malloc.h>
#include <string.h>
#include <stdlib.h>
#include "mp.h"
#include "fp.h"
/* real number types */
#define FLOAT 1
#define DOUBLE 2
#define EXTENDED 3
#define max_exp 32768
#define ASCII_POS_ZERO "0"
#define ASCII_NEG_ZERO "0"
#define ASCII_POS_INF "Infinity"
#define ASCII_NEG_INF "-Infinity"
#define ASCII_NAN "NaN"
/* Remove trailing zeroes at the end of the mantissa part of the number to
* speed up the calculations. */
int RemoveTrailingZeros( char *ascii )
{
int i;
for( i = 0; ; i++ ) {
if( ascii[i] == 'e' || ascii[i] == 'E' || ascii[i] == '\0' ) break;
}
for( i--; i > 0; i-- ) {
if( ascii[i] == '0' ) {
ascii[i] = '_';
} else if( ascii[i] != '.' ) {
break;
}
}
return 0;
}
/* parse ascii string into the mantissa f and the exponent e */
/* note: this function assumes a positive value */
int ParseAscii( char *ascii, mpnum *f, long *e )
{
int readingExponent = FALSE;
int expIsNeg = FALSE;
int behindDecimal = FALSE;
uint32 digitsBehindDecimal = 0;
int rc;
int sigexp = 0;
*e = 0;
mp_zero( f );
RemoveTrailingZeros( ascii );
for( ; *ascii != '\0'; ascii++ ) {
if( *ascii == '.' ) {
/* decimal point */
behindDecimal = TRUE;
} else if( *ascii == 'e' || *ascii == 'E' ) {
/* exponent */
if( ascii[1] == '-' ) {
expIsNeg = TRUE;
ascii++;
} else if( ascii[1] == '+' ) {
ascii++;
}
readingExponent = TRUE;
} else if( *ascii >= '0' && *ascii <= '9' ) {
if( readingExponent ) {
if( *e <= max_exp ) {
*e = *e * 10 + (long)(*ascii - '0');
}
} else {
/* number */
rc = mp_mulsc( f, f, 10 );
if( rc != MP_NO_ERR ) return rc;
rc = mp_addsc( f, f, (uint32)(*ascii - '0') );
if( rc != MP_NO_ERR ) return rc;
if( behindDecimal ) {
digitsBehindDecimal++;
}
}
} else if( *ascii == '_' ) {
*ascii = '0';
if( !behindDecimal ) {
sigexp++;
}
} else {
/* unrecognized character */
}
}
if( expIsNeg ) *e = -*e;
*e -= digitsBehindDecimal;
*e += sigexp;
return 0;
}
/* convert ascii string to a real number of type type */
int a2r( void *dst, char *ascii, int type )
{
int isNeg = FALSE;
char exp_real[10];
mpnum f;
mpnum exp;
long e = 0;
int rc;
mpnum zero;
int isZero;
if( type != FLOAT && type != DOUBLE && type != EXTENDED ) return -1;
/* check for sign */
if( *ascii == '-' ) {
isNeg = TRUE;
ascii++;
} else if( *ascii == '+' ) {
ascii++;
}
rc = mp_init( &f, 0 );
if( rc != MP_NO_ERR ) return rc;
rc = mp_init( &exp, 10 );
if( rc != MP_NO_ERR ) return rc;
rc = mp_init( &zero, 0 );
if( rc != MP_NO_ERR ) return rc;
/* parse ascii into significand and exponent */
ParseAscii( ascii, &f, &e );
isZero = mp_eq( &f, &zero );
mp_free( &zero );
/* calculate 10^abs(e) */
if( e > 0 ) {
rc = mp_pow( &exp, &exp, (uint32)e );
} else if( e < 0 ) {
rc = mp_pow( &exp, &exp, (uint32)(-e) );
}
if( rc != MP_NO_ERR ) return rc;
/* combine significand and exponent as reals */
if( type == FLOAT ) {
if( e > 0 ) {
mp_mul( &f, &f, &exp );
mp_tofloat( dst, &f );
} else if( e < 0 ) {
char temp[10];
mp_toextended( temp, &f );
mp_toextended( exp_real, &exp );
ediv( temp, temp, exp_real );
e2f( dst, temp );
} else {
mp_tofloat( dst, &f );
}
} else if( type == DOUBLE ) {
if( e > 0 ) {
mp_mul( &f, &f, &exp );
mp_todouble( dst, &f );
} else if( e < 0 ) {
char temp[10];
mp_toextended( temp, &f );
mp_toextended( exp_real, &exp );
ediv( temp, temp, exp_real );
e2d( dst, temp );
} else {
mp_todouble( dst, &f );
}
} else {
mp_toextended( dst, &f );
mp_toextended( exp_real, &exp );
if( e > 0 ) {
emul( dst, dst, exp_real );
} else if( e < 0 ) {
ediv( dst, dst, exp_real );
}
}
/* add sign */
if( isNeg ) {
if( type == FLOAT ) fneg( dst, dst );
else if( type == DOUBLE ) dneg( dst, dst );
else eneg( dst, dst );
}
mp_free( &f );
mp_free( &exp );
/* check if numbers are too large or too small */
if( type == FLOAT ) {
if( !isZero && ( f_isPosZero(dst) || f_isNegZero(dst) ) ) {
return VALUE_TOO_SMALL;
}
if( f_isPosInf(dst) || f_isNegInf(dst) ) {
return VALUE_TOO_LARGE;
}
} else if( type == DOUBLE ) {
if( !isZero && ( d_isPosZero(dst) || d_isNegZero(dst) ) ) {
return VALUE_TOO_SMALL;
}
if( d_isPosInf(dst) || d_isNegInf(dst) ) {
return VALUE_TOO_LARGE;
}
}
return 0;
}
int a2e( char *ext, char *ascii )
{
return( a2r( ext, ascii, EXTENDED ) );
}
int a2d( double *dbl, char *ascii )
{
return( a2r( dbl, ascii, DOUBLE ) );
}
int a2f( float *flt, char *ascii )
{
return( a2r( flt, ascii, FLOAT ) );
}
/* Generate String
*
* This function uses an algorithm found in an essay entitled "How to Print
* Floating Point Numbers Accurately" by Guy L. Steele Jr and Jon L White.
* It takes as input a binary floating point number and generates a string
* of decimal digits which represent the most significant bits of a decimal
* representation of the number. H represents the power of ten of the most
* significant digit, and N represents the power of ten of the least signi-
* ficant digit. For example, for string "123456", H = 1, N = -4, the
* decimal number is 12.3456.
*
* The resulting decimal number is not the closest possible representation
* of the binary number. Instead, it is the number of minimal length such
* that converting the number to a binary floating point yields the original
* binary value. One advantage of this is that the algorithm will return
* "1.3" for 1.3 instead of something like "1.299999952316284". (1.3 cannot
* be stored exactly in binary form.)
*
* Note: D is assumed to be large enough to hold the whole string. In the
* worst case for a double, it will require 18 bytes.
*/
int GenerateString( char *D, void *src, int type, int *N, int *H )
{
uint64 temp;
int e;
mpnum f, R, S, Mp, Mn, U, mptemp, mptemp2;
int k = 0, p;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?