floatingdecimal.java

来自「《移动Agent技术》一书的所有章节源代码。」· Java 代码 · 共 1,376 行 · 第 1/3 页

JAVA
1,376
字号
/*
 * @(#)FloatingDecimal.java	1.9 97/01/22
 * 
 * Copyright (c) 1995, 1996 Sun Microsystems, Inc. All Rights Reserved.
 * 
 * This software is the confidential and proprietary information of Sun
 * Microsystems, Inc. ("Confidential Information").  You shall not
 * disclose such Confidential Information and shall use it only in
 * accordance with the terms of the license agreement you entered into
 * with Sun.
 * 
 * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
 * SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
 * PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES
 * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING
 * THIS SOFTWARE OR ITS DERIVATIVES.
 * 
 * CopyrightVersion 1.1_beta
 * 
 */

package java.lang;

class FloatingDecimal{
    boolean	isExceptional;
    boolean	isNegative;
    int		decExponent;
    char	digits[];
    int		nDigits;

    private	FloatingDecimal( boolean negSign, int decExponent, char []digits, int n,  boolean e )
    {
	isNegative = negSign;
	isExceptional = e;
	this.decExponent = decExponent;
	this.digits = digits;
	this.nDigits = n;
    }

    /*
     * Constants of the implementation
     * Most are IEEE-754 related.
     * (There are more really boring constants at the end.)
     */
    static final long	signMask = 0x8000000000000000L;
    static final long	expMask  = 0x7ff0000000000000L;
    static final long	fractMask= ~(signMask|expMask);
    static final int	expShift = 52;
    static final int	expBias  = 1023;
    static final long	fractHOB = ( 1L<<expShift ); // assumed High-Order bit
    static final long	expOne	 = ((long)expBias)<<expShift; // exponent of 1.0
    static final int	maxSmallBinExp = 62;
    static final int	minSmallBinExp = -( 63 / 3 );

    static final long	highbyte = 0xff00000000000000L;
    static final long	highbit  = 0x8000000000000000L;
    static final long	lowbytes = ~highbyte;

    static final int	singleSignMask =    0x80000000;
    static final int	singleExpMask  =    0x7f800000;
    static final int	singleFractMask =   ~(singleSignMask|singleExpMask);
    static final int	singleExpShift	=   23;
    static final int	singleFractHOB	=   1<<singleExpShift;
    static final int	singleExpBias	=   127;

    /*
     * count number of bits from high-order 1 bit to low-order 1 bit,
     * inclusive.
     */
    private static int
    countBits( long v ){
	// 
	// the strategy is to shift until we get a non-zero sign bit
	// then shift until we have no bits left, counting the difference.
	// we do byte shifting as a hack. Hope it helps.
	//
	if ( v == 0L ) return 0;

	while ( ( v & highbyte ) == 0L ){
	    v <<= 8;
	}
	while ( v > 0L ) { // i.e. while ((v&highbit) == 0L )
	    v <<= 1;
	}

	int n = 0;
	while (( v & lowbytes ) != 0L ){
	    v <<= 8;
	    n += 8;
	}
	while ( v != 0L ){
	    v <<= 1;
	    n += 1;
	}
	return n;
    }

    /*
     * Keep big powers of 5 handy for future reference.
     */
    private static FDBigInt b5p[];

    private static FDBigInt
    big5pow( int p ){
	if ( p < 0 )
	    throw new RuntimeException( "Assertion botch: negative power of 5");
	if ( b5p == null ){
	    b5p = new FDBigInt[ p+1 ];
	}else if (b5p.length <= p ){
	    FDBigInt t[] = new FDBigInt[ p+1 ];
	    System.arraycopy( b5p, 0, t, 0, b5p.length );
	    b5p = t;
	}
	if ( b5p[p] != null )
	    return b5p[p];
	else if ( p < small5pow.length )
	    return b5p[p] = new FDBigInt( small5pow[p] );
	else if ( p < long5pow.length )
	    return b5p[p] = new FDBigInt( long5pow[p] );
	else {
	    // construct the damn thing.
	    // recursively.
	    int q, r;
	    // in order to compute 5^p,
	    // compute its square root, 5^(p/2) and square.
	    // or, let q = p / 2, r = p -q, then
	    // 5^p = 5^(q+r) = 5^q * 5^r
	    q = p >> 1;
	    r = p - q;
	    FDBigInt bigq =  b5p[q];
	    if ( bigq == null ) 
		bigq = big5pow ( q );
	    if ( r < small5pow.length ){
		return (b5p[p] = bigq.mult( small5pow[r] ) );
	    }else{
		FDBigInt bigr = b5p[ r ];
		if ( bigr == null ) 
		    bigr = big5pow( r );
		return (b5p[p] = bigq.mult( bigr ) );
	    }
	}
    }

    /*
     * This is the easy subcase -- 
     * all the significant bits, after scaling, are held in lvalue.
     * negSign and decExponent tell us what processing and scaling
     * has already been done. Exceptional cases have already been
     * stripped out. 
     * In particular:
     * lvalue is a finite number (not Inf, nor NaN)
     * lvalue > 0L (not zero, nor negative).
     *
     * The only reason that we develop the digits here, rather than
     * calling on Long.toString() is that we can do it a little faster,
     * and besides want to treat trailing 0s specially. If Long.toString
     * changes, we should re-evaluate this strategy!
     */
    private void
    developLongDigits( int decExponent, long lvalue, long insignificant ){
	char digits[];
	int  ndigits;
	int  digitno;
	int  c;
	//
	// Discard non-significant low-order bits, while rounding,
	// up to insignificant value.
	int i;
	for ( i = 0; insignificant >= 10L; i++ )
	    insignificant /= 10L;
	if ( i != 0 ){
	    long pow10 = long5pow[i] << i; // 10^i == 5^i * 2^i;
	    long residue = lvalue % pow10;
	    lvalue /= pow10;
	    decExponent += i;
	    if ( residue >= (pow10>>1) ){
		// round up based on the low-order bits we're discarding
		lvalue++;
	    }
	}
	if ( lvalue <= Integer.MAX_VALUE ){
	    if ( lvalue <= 0L )
		throw new RuntimeException("Assertion botch: value "+lvalue+" <= 0");

	    // even easier subcase!
	    // can do int arithmetic rather than long!
	    int  ivalue = (int)lvalue;
	    digits = new char[ ndigits=10 ];
	    digitno = ndigits-1;
	    c = ivalue%10;
	    ivalue /= 10;
	    while ( c == 0 ){
		decExponent++;
		c = ivalue%10;
		ivalue /= 10;
	    }
	    while ( ivalue != 0){
		digits[digitno--] = (char)(c+'0');
		decExponent++;
		c = ivalue%10;
		ivalue /= 10;
	    }
	    digits[digitno] = (char)(c+'0');
	} else {
	    // same algorithm as above (same bugs, too )
	    // but using long arithmetic.
	    digits = new char[ ndigits=20 ];
	    digitno = ndigits-1;
	    c = (int)(lvalue%10L);
	    lvalue /= 10L;
	    while ( c == 0 ){
		decExponent++;
		c = (int)(lvalue%10L);
		lvalue /= 10L;
	    }
	    while ( lvalue != 0L ){
		digits[digitno--] = (char)(c+'0');
		decExponent++;
		c = (int)(lvalue%10L);
		lvalue /= 10;
	    }
	    digits[digitno] = (char)(c+'0');
	}
	char result [];
	ndigits -= digitno;
	if ( digitno == 0 )
	    result = digits;
	else {
	    result = new char[ ndigits ];
	    System.arraycopy( digits, digitno, result, 0, ndigits );
	}
	this.digits = result;
	this.decExponent = decExponent+1;
	this.nDigits = ndigits;
    }

    //
    // add one to the least significant digit.
    // in the unlikely event there is a carry out,
    // deal with it.
    // assert that this will only happen where there
    // is only one digit, e.g. (float)1e-44 seems to do it.
    //
    private void
    roundup(){
	int i;
	int q = digits[ i = (nDigits-1)];
	if ( q == '9' ){
	    while ( q == '9' && i > 0 ){
		digits[i] = '0';
		q = digits[--i];
	    }
	    if ( q == '9' ){
		// carryout! High-order 1, rest 0s, larger exp.
		decExponent += 1;
		digits[0] = '1';
		return;
	    }
	    // else fall through.
	}
	digits[i] = (char)(q+1);
    }

    /*
     * FIRST IMPORTANT CONSTRUCTOR: DOUBLE
     */
    public FloatingDecimal( double d )
    {
	long	dBits = Double.doubleToLongBits( d );
	long	fractBits;
	int	binExp;
	int	nSignificantBits;

	// discover and delete sign
	if ( (dBits&signMask) != 0 ){
	    isNegative = true;
	    dBits ^= signMask;
	} else {
	    isNegative = false;
	}
	// Begin to unpack
	// Discover obvious special cases of NaN and Infinity.
	binExp = (int)( (dBits&expMask) >> expShift );
	fractBits = dBits&fractMask;
	if ( binExp == (int)(expMask>>expShift) ) {
	    isExceptional = true;
	    if ( fractBits == 0L ){
		digits =  infinity;
	    } else {
		digits = notANumber;
		isNegative = false; // NaN has no sign!
	    }
	    nDigits = digits.length;
	    return;
	}
	isExceptional = false;
	// Finish unpacking
	// Normalize denormalized numbers.
	// Insert assumed high-order bit for normalized numbers.
	// Subtract exponent bias.
	if ( binExp == 0 ){
	    if ( fractBits == 0L ){
		// not a denorm, just a 0!
		decExponent = 0;
		digits = zero;
		nDigits = 1;
		return;
	    }
	    while ( (fractBits&fractHOB) == 0L ){
		fractBits <<= 1;
		binExp -= 1;
	    }
	    nSignificantBits = expShift + binExp; // recall binExp is  - shift count.
	    binExp += 1;
	} else {
	    fractBits |= fractHOB;
	    nSignificantBits = expShift+1;
	}
	binExp -= expBias;
	// call the routine that actually does all the hard work.
	dtoa( binExp, fractBits, nSignificantBits );
    }

    /*
     * SECOND IMPORTANT CONSTRUCTOR: SINGLE
     */
    public FloatingDecimal( float f )
    {
	int	fBits = Float.floatToIntBits( f );
	int	fractBits;
	int	binExp;
	int	nSignificantBits;

	// discover and delete sign
	if ( (fBits&singleSignMask) != 0 ){
	    isNegative = true;
	    fBits ^= singleSignMask;
	} else {
	    isNegative = false;
	}
	// Begin to unpack
	// Discover obvious special cases of NaN and Infinity.
	binExp = (int)( (fBits&singleExpMask) >> singleExpShift );
	fractBits = fBits&singleFractMask;
	if ( binExp == (int)(singleExpMask>>singleExpShift) ) {
	    isExceptional = true;
	    if ( fractBits == 0L ){
		digits =  infinity;
	    } else {
		digits = notANumber;
		isNegative = false; // NaN has no sign!
	    }
	    nDigits = digits.length;
	    return;
	}
	isExceptional = false;
	// Finish unpacking
	// Normalize denormalized numbers.
	// Insert assumed high-order bit for normalized numbers.
	// Subtract exponent bias.
	if ( binExp == 0 ){
	    if ( fractBits == 0 ){
		// not a denorm, just a 0!
		decExponent = 0;
		digits = zero;
		nDigits = 1;
		return;
	    }
	    while ( (fractBits&singleFractHOB) == 0 ){
		fractBits <<= 1;
		binExp -= 1;
	    }
	    nSignificantBits = singleExpShift + binExp; // recall binExp is  - shift count.
	    binExp += 1;
	} else {
	    fractBits |= singleFractHOB;
	    nSignificantBits = singleExpShift+1;
	}
	binExp -= singleExpBias;
	// call the routine that actually does all the hard work.
	dtoa( binExp, ((long)fractBits)<<(expShift-singleExpShift), nSignificantBits );
    }

    private void
    dtoa( int binExp, long fractBits, int nSignificantBits )
    {
	int	nFractBits; // number of significant bits of fractBits;
	int	nTinyBits;  // number of these to the right of the point.
	int	decExp;

	// Examine number. Determine if it is an easy case,
	// which we can do pretty trivially using float/long conversion,
	// or whether we must do real work.
	nFractBits = countBits( fractBits );
	nTinyBits = Math.max( 0, nFractBits - binExp - 1 );
	if ( binExp <= maxSmallBinExp && binExp >= minSmallBinExp ){
	    // Look more closely at the number to decide if,
	    // with scaling by 10^nTinyBits, the result will fit in
	    // a long.
	    if ( (nTinyBits < long5pow.length) && ((nFractBits + n5bits[nTinyBits]) < 64 ) ){
		/*
		 * We can do this:
		 * take the fraction bits, which are normalized.
		 * (a) nTinyBits == 0: Shift left or right appropriately
		 *     to align the binary point at the extreme right, i.e.
		 *     where a long int point is expected to be. The integer
		 *     result is easily converted to a string.
		 * (b) nTinyBits > 0: Shift right by expShift-nFractBits,
		 *     which effectively converts to long and scales by
		 *     2^nTinyBits. Then multiply by 5^nTinyBits to
		 *     complete the scaling. We know this won't overflow
		 *     because we just counted the number of bits necessary
		 *     in the result. The integer you get from this can
		 *     then be converted to a string pretty easily.
		 */
		long halfULP;
		if ( nTinyBits == 0 ) {
		    if ( binExp > nSignificantBits ){
			halfULP = 1L << ( binExp-nSignificantBits-1);
		    } else {
			halfULP = 0L;
		    }
		    if ( binExp >= expShift ){
			fractBits <<= (binExp-expShift);
		    } else {
			fractBits >>>= (expShift-binExp) ;
		    }
		    developLongDigits( 0, fractBits, halfULP );
		    return;
		}
		/*
		 * The following causes excess digits to be printed
		 * out in the single-float case. Our manipulation of
		 * halfULP here is apparently not correct. If we
		 * better understand how this works, perhaps we can
		 * use this special case again. But for the time being,
		 * we do not.
		 * else {
		 *     fractBits >>>= expShift+1-nFractBits;
		 *     fractBits *= long5pow[ nTinyBits ];
		 *     halfULP = long5pow[ nTinyBits ] >> (1+nSignificantBits-nFractBits);
		 *     developLongDigits( -nTinyBits, fractBits, halfULP );
		 *     return;
		 * }
		 */
	    }
	}
	/*
	 * This is the hard case. We are going to compute large positive
	 * integers B and S and integer decExp, s.t.
	 *	d = ( B / S ) * 10^decExp
	 *	1 <= B / S < 10
	 * Obvious choices are:
	 *	decExp = floor( log10(d) )
	 * 	B      = d * 2^nTinyBits * 10^max( 0, -decExp )
	 *	S      = 10^max( 0, decExp) * 2^nTinyBits
	 * (noting that nTinyBits has already been forced to non-negative)
	 * I am also going to compute a large positive integer

⌨️ 快捷键说明

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