asciifp.c

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

C
568
字号
    int low, high;
    int index = 0;

    if( type != FLOAT && type != DOUBLE && type != EXTENDED ) return -1;

    if( type == FLOAT ) {
        parseFloat( *(float*)src, &temp, &e );
        p = float_precision;
    } else if( type == DOUBLE ) {
        parseDouble( *(double*)src, &temp, &e );
        p = double_precision;
    } else {
        parseExtended( src, &temp, &e );
        p = extended_precision;
    }
    e++;
    mp_init( &f, temp );
    mp_init( &R, 0 );
    mp_init( &S, 1 );
    mp_init( &Mp, 0 );
    mp_init( &Mn, 1 );
    mp_init( &U, 0 );
    mp_init( &mptemp, 1 );
    mp_init( &mptemp2, 0 );
    /* f * 2^(e-p) = src */

    mp_shiftleft( &R, &f, max( e-p, 0 ) );
    mp_shiftleft( &S, &S, max( 0, -(e-p) ) );
    /* assert R/S = f * 2^(e-p) = src */
    mp_shiftleft( &Mn, &Mn, max( e-p, 0 ) );
    mp_copy( &Mp, &Mn );

    mp_shiftleft( &mptemp, &mptemp, p - 1 );
    if( mp_eq( &f, &mptemp ) ) {
        /* border case: src is a power of 2 */
        mp_shiftleft( &Mp, &Mp, 1 );
        mp_shiftleft( &R, &R, 1 );
        mp_shiftleft( &S, &S, 1 );
    }
    for(;;) {
        mp_divsc( &mptemp, &S, 10, CEILING );
        if( mp_gte( &R, &mptemp ) ) break;
        k--;
        mp_mulsc( &R, &R, 10 );
        mp_mulsc( &Mn, &Mn, 10 );
        mp_mulsc( &Mp, &Mp, 10 );
    }
    /* assert  k = min( 0, 1 + floor( logv ) ) */
    mp_mulsc( &mptemp, &R, 2 );
    mp_add( &mptemp, &mptemp, &Mp );
    for(;;) {
        mp_mulsc( &mptemp2, &S, 2 );
        if( mp_lt( &mptemp, &mptemp2 ) ) break;
        mp_mulsc( &S, &S, 10 );
        k++;
    }
    *H = k - 1;
    for(;;) {
        k--;
        mp_mulsc( &R, &R, 10 );
        mp_div( &U, &R, &R, &S );
        mp_mulsc( &Mn, &Mn, 10 );
        mp_mulsc( &Mp, &Mp, 10 );
        mp_mulsc( &mptemp, &R, 2 );
        mp_mulsc( &mptemp2, &S, 2 );
        mp_sub( &mptemp2, &mptemp2, &Mp );
        low = mp_lt( &mptemp, &Mn );
        high = mp_gt( &mptemp, &mptemp2 );
        if( high || low ) break;
        D[index++] = U.num[0] + '0';
    }
    if( low && high ) {
        mp_mulsc( &mptemp, &R, 2 );
        if( mp_lte( &mptemp, &S ) ) {
            D[index++] = U.num[0] + '0';
        } else {
            D[index++] = U.num[0] + '1';
        }
    } else if( low ) {
        D[index++] = U.num[0] + '0';
    } else if( high ) {
        D[index++] = U.num[0] + '1';
    }
    D[index] = '\0';
    *N = k;
    mp_free( &f );
    mp_free( &R );
    mp_free( &S );
    mp_free( &Mn );
    mp_free( &Mp );
    mp_free( &U );
    mp_free( &mptemp );
    mp_free( &mptemp2 );
    return 0;
}

/* This function will round the decimal string at the given location and then
 * set the character after the location to NULL.
 * Return 1 when a number like "99999" rounds to "1". (Most significant bit
 * is in a new location.)
 */
int RoundString( char *str, int loc )
{
    int cur = loc + 1;
    int round = 0;

    if( str[cur] > '5' ) {
        round = 1;  /* round up */
    } else if( str[cur] < '5' ) {
        round = -1; /* round down */
    } else {
        cur++;
        while( str[cur] != '\0' ) {
            if( str[cur] > '0' ) {
                round = 1; /* round up */
                break;
            }
            cur++;
        }
        if( round == 0 ) {
            if( (str[loc] - '0') % 2 == 0 ) {
                round = -1; /* round down */
            } else {
                round = 1; /* round up */
            }
        }
    }
    cur = loc;
    if( round == 1 ) {
        while( cur >= 0 && str[cur] == '9' ) {
            str[cur] = '0';
            cur--;
        }
        if( cur == -1 ) {
            str[0] = '1';
            str[1] = '\0';
            return 1;
        }
        str[cur] = str[cur] + 1;
    }
    str[cur+1] = '\0';

    return 0;
}

/* This function formats a string generated by the GenerateString function.
 * The formated string will use E notation of the number is between 1e+10
 * and 1e-4 and will just output the decimal number in normal notation
 * otherwise.  If there isn't enough room to fit the full mantissa and the
 * exponent, it rounds the mantissa.
 * Returns -1 if maxlen is too small to display a rounded mantissa and
 * exponent in E notation.
 */
int FormatString( char *dst, char *src, int least, int most, int maxlen )
{
    int i, j, src_index = 0, dst_index = 0, exp_size;

    if( most > 9 || most < -3 || most - least >= maxlen ) {
        /* use E notation */
        char buf[10];

        /* determine size of exponent part */
        if( most > 99 || most < -99 ) {
            exp_size = 5;
        } else if( most > 9 || most < -9 ) {
            exp_size = 4;
        } else {
            exp_size = 3;
        }
        if( maxlen < exp_size + 3 ) return -1; /* not enough room */

        if( most - least + exp_size >= maxlen ) {
            /* need to round */
            if( RoundString( src, maxlen - exp_size - 3 ) == 1 ) {
                most++;
            }
        }

        dst[dst_index++] = src[src_index++];
        if( most - least > 0 ) dst[dst_index++] = '.';
        for( i = most - 1; i >= least; i-- ) {
            if( src[src_index] == '\0' ) break;
            dst[dst_index++] = src[src_index++];
        }
        dst[dst_index++] = 'E';
        if( most > 0 ) dst[dst_index++] = '+';
        itoa( most, buf, 10 );
        i = 0;
        while( buf[i] != '\0' ) {
            dst[dst_index++] = buf[i++];
        }
    } else {
        i = most;
        j = least;
        if( i < 0 ) i = 0;
        if( j > 0 ) j = 0;
        for( ; i >= j; i-- ) {
            if( i > most ) {
                if( i == -1 ) dst[dst_index++] = '.';
                dst[dst_index++] = '0';
            } else if( i < least ) {
                dst[dst_index++] = '0';
            } else {
                if( i == -1 ) dst[dst_index++] = '.';
                dst[dst_index++] = src[src_index++];
            }
        }
    }
    dst[dst_index] = '\0';
    return 0;
}

/* Convert a binary floating-point number to a string */
int r2a( char *dst, void *src, int type, int maxlen )
{
    int rc;
    int N, H;
    char str[20];

    rc = GenerateString( str, src, type, &N, &H );
    rc = FormatString( dst, str, N, H, maxlen );

    return rc;
}

int e2a( char *ascii, char *ext, int maxlen )
{
    /* NYI */
    return( r2a( ascii, ext, EXTENDED, maxlen ) );
}

int d2a( char *ascii, double *dbl, int maxlen )
{
    /* first check special cases */
    if( *(uint64*)dbl == DOUBLE_POS_ZERO ) {
        strcpy( ascii, ASCII_POS_ZERO );
    } else if( *(uint64*)dbl == DOUBLE_NEG_ZERO ) {
        strcpy( ascii, ASCII_NEG_ZERO );
    } else if( *(uint64*)dbl == DOUBLE_POS_INF ) {
        strcpy( ascii, ASCII_POS_INF );
    } else if( *(uint64*)dbl == DOUBLE_NEG_INF ) {
        strcpy( ascii, ASCII_NEG_INF );
    } else if( d_isNan( dbl ) ) {
        strcpy( ascii, ASCII_NAN );
    } else {
        /* handle negative sign */
        if( d_isNeg( dbl ) ) {
            *ascii = '-';
            ascii++;
            dneg( dbl, dbl );
            maxlen--;
        }
        return( r2a( ascii, dbl, DOUBLE, maxlen ) );
    }
    return 0;
}

int f2a( char *ascii, float *flt, int maxlen )
{
    /* first check special cases */
    if( *(uint32*)flt == FLOAT_POS_ZERO ) {
        strcpy( ascii, ASCII_POS_ZERO );
    } else if( *(uint32*)flt == FLOAT_NEG_ZERO ) {
        strcpy( ascii, ASCII_NEG_ZERO );
    } else if( *(uint32*)flt == FLOAT_POS_INF ) {
        strcpy( ascii, ASCII_POS_INF );
    } else if( *(uint32*)flt == FLOAT_NEG_INF ) {
        strcpy( ascii, ASCII_NEG_INF );
    } else if( f_isNan( flt ) ) {
        strcpy( ascii, ASCII_NAN );
    } else {
        /* handle negative sign */
        if( f_isNeg( flt ) ) {
            *ascii = '-';
            ascii++;
            fneg( flt, flt );
            maxlen--;
        }
        return( r2a( ascii, flt, FLOAT, maxlen ) );
    }
    return 0;
}

⌨️ 快捷键说明

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