floatingdecimal.java
来自「This is a resource based on j2me embedde」· Java 代码 · 共 2,301 行 · 第 1/5 页
JAVA
2,301 行
/* * @(#)FloatingDecimal.java 1.35 06/10/10 * * Copyright 1990-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License version * 2 only, as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License version 2 for more details (a copy is * included at /legal/license.txt). * * You should have received a copy of the GNU General Public License * version 2 along with this work; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA * * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa * Clara, CA 95054 or visit www.sun.com if you need additional * information or have any questions. * */package java.lang;class FloatingDecimal{ boolean isExceptional; boolean isNegative; int decExponent; char digits[]; int nDigits; int bigIntExp; int bigIntNBits; boolean mustSetRoundDir = false; int roundDir; // set by doubleValue 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 int maxDecimalDigits = 15; static final int maxDecimalExponent = 308; static final int minDecimalExponent = -324; static final int bigDecimalExponent = 324; // i.e. abs(minDecimalExponent) 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; static final int singleMaxDecimalDigits = 7; static final int singleMaxDecimalExponent = 38; static final int singleMinDecimalExponent = -45; static final int intDecimalDigits = 9; /* * 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. // 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 synchronized FDBigInt big5pow( int p ){ if (sun.misc.BuildFlags.qAssertsEnabled) assert p >= 0 : p; // 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 value. // 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 ) ); } } } // // a common operation // private static FDBigInt multPow52( FDBigInt v, int p5, int p2 ){ if ( p5 != 0 ){ if ( p5 < small5pow.length ){ v = v.mult( small5pow[p5] ); } else { v = v.mult( big5pow( p5 ) ); } } if ( p2 != 0 ){ v.lshiftMe( p2 ); } return v; } // // another common operation // private static FDBigInt constructPow52( int p5, int p2 ){ FDBigInt v = new FDBigInt( big5pow( p5 ) ); if ( p2 != 0 ){ v.lshiftMe( p2 ); } return v; } /* * Make a floating double into a FDBigInt. * This could also be structured as a FDBigInt * constructor, but we'd have to build a lot of knowledge * about floating-point representation into it, and we don't want to. * * AS A SIDE EFFECT, THIS METHOD WILL SET THE INSTANCE VARIABLES * bigIntExp and bigIntNBits * */ private FDBigInt doubleToBigInt( double dval ){ long lbits = Double.doubleToLongBits( dval ) & ~signMask; int binexp = (int)(lbits >>> expShift); lbits &= fractMask; if ( binexp > 0 ){ lbits |= fractHOB; } else { if (sun.misc.BuildFlags.qAssertsEnabled) assert lbits != 0L : lbits; // doubleToBigInt(0.0) binexp +=1; while ( (lbits & fractHOB ) == 0L){ lbits <<= 1; binexp -= 1; } } binexp -= expBias; int nbits = countBits( lbits ); /* * We now know where the high-order 1 bit is, * and we know how many there are. */ int lowOrderZeros = expShift+1-nbits; lbits >>>= lowOrderZeros; bigIntExp = binexp+1-nbits; bigIntNBits = nbits; return new FDBigInt( lbits ); } /* * Compute a number that is the ULP of the given value, * for purposes of addition/subtraction. Generally easy. * More difficult if subtracting and the argument * is a normalized a power of 2, as the ULP changes at these points. */ private static double ulp( double dval, boolean subtracting ){ long lbits = Double.doubleToLongBits( dval ) & ~signMask; int binexp = (int)(lbits >>> expShift); double ulpval; if ( subtracting && ( binexp >= expShift ) && ((lbits&fractMask) == 0L) ){ // for subtraction from normalized, powers of 2, // use next-smaller exponent binexp -= 1; } if ( binexp > expShift ){ ulpval = Double.longBitsToDouble( ((long)(binexp-expShift))<<expShift ); } else if ( binexp == 0 ){ ulpval = Double.MIN_VALUE; } else { ulpval = Double.longBitsToDouble( 1L<<(binexp-1) ); } if ( subtracting ) ulpval = - ulpval; return ulpval; } /* * Round a double to a float. * In addition to the fraction bits of the double, * look at the class instance variable roundDir, * which should help us avoid double-rounding error. * roundDir was set in hardValueOf if the estimate was * close enough, but not exact. It tells us which direction * of rounding is preferred. */ float stickyRound( double dval ){ long lbits = Double.doubleToLongBits( dval ); long binexp = lbits & expMask; if ( binexp == 0L || binexp == expMask ){ // what we have here is special. // don't worry, the right thing will happen. return (float) dval; } lbits += (long)roundDir; return (float)Double.longBitsToDouble( lbits ); } /* * 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 (sun.misc.BuildFlags.qAssertsEnabled) assert lvalue > 0L : lvalue; // lvalue <= 0 // even easier subcase! // can do int arithmetic rather than long! int ivalue = (int)lvalue; ndigits = 10; digits = (char[])(perThreadBuffer.get()); 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. ndigits = 20; digits = (char[])(perThreadBuffer.get()); 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; 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 +1; // 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 ); } /*
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?