com.scudata.util.FloatingDecimal Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of esproc Show documentation
Show all versions of esproc Show documentation
SPL(Structured Process Language) A programming language specially for structured data computing.
package com.scudata.util;
/**
* ??java??FloatingDecimal?????ģ???ʽ?????Ƿ???null?????׳??쳣??
* ???ڴ????????????ͽ????׳??쳣Ӱ?????ܡ?
*/
public 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.
// 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 synchronized 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 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 (lbits == 0L)
throw new RuntimeException(
"Assertion botch: 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; // hack-o-matic.
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 (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 + 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);
}
/*
* 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 + 1; // 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
* M = (1/2^nSignificantBits) * 2^nTinyBits * 10^max( 0, -decExp )
* i.e. M is (1/2) of the ULP of d, scaled like B.
* When we iterate through dividing B/S and picking off the
* quotient bits, we will know when to stop when the remainder
* is <= M.
*
* We keep track of powers of 2 and powers of 5.
*/
/*
* Estimate decimal exponent. (If it is small-ish,
* we could double-check.)
*
* First, scale the mantissa bits such that 1 <= d2 < 2.
* We are then going to estimate
* log10(d2) ~=~ (d2-1.5)/1.5 + log(1.5)
* and so we can estimate
* log10(d) ~=~ log10(d2) + binExp * log10(2)
* take the floor and call it decExp.
* FIXME -- use more precise constants here. It costs no more.
*/
double d2 = Double.longBitsToDouble(
expOne | (fractBits & ~fractHOB));
decExp = (int)Math.floor(
(d2 - 1.5D) * 0.289529654D + 0.176091259 +
(double)binExp * 0.301029995663981);
int B2, B5; // powers of 2 and powers of 5, respectively, in B
int S2, S5; // powers of 2 and powers of 5, respectively, in S
int M2, M5; // powers of 2 and powers of 5, respectively, in M
int Bbits; // binary digits needed to represent B, approx.
int tenSbits; // binary digits needed to represent 10*S, approx.
FDBigInt Sval, Bval, Mval;
B5 = Math.max(0, -decExp);
B2 = B5 + nTinyBits + binExp;
S5 = Math.max(0, decExp);
S2 = S5 + nTinyBits;
M5 = B5;
M2 = B2 - nSignificantBits;
/*
* the long integer fractBits contains the (nFractBits) interesting
* bits from the mantissa of d ( hidden 1 added if necessary) followed
* by (expShift+1-nFractBits) zeros. In the interest of compactness,
* I will shift out those zeros before turning fractBits into a
* FDBigInt. The resulting whole number will be
* d * 2^(nFractBits-1-binExp).
*/
fractBits >>>= (expShift + 1 - nFractBits);
B2 -= nFractBits - 1;
int common2factor = Math.min(B2, S2);
B2 -= common2factor;
S2 -= common2factor;
M2 -= common2factor;
/*
* HACK!! For exact powers of two, the next smallest number
* is only half as far away as we think (because the meaning of
* ULP changes at power-of-two bounds) for this reason, we
* hack M2. Hope this works.
*/
if (nFractBits == 1)
M2 -= 1;
if (M2 < 0) {
// oops.
// since we cannot scale M down far enough,
// we must scale the other values up.
B2 -= M2;
S2 -= M2;
M2 = 0;
}
/*
* Construct, Scale, iterate.
* Some day, we'll write a stopping test that takes
* account of the assymetry of the spacing of floating-point
* numbers below perfect powers of 2
* 26 Sept 96 is not that day.
* So we use a symmetric test.
*/
char digits[] = this.digits = new char[18];
int ndigit = 0;
boolean low, high;
long lowDigitDifference;
int q;
/*
* Detect the special cases where all the numbers we are about
* to compute will fit in int or long integers.
* In these cases, we will avoid doing FDBigInt arithmetic.
* We use the same algorithms, except that we "normalize"
* our FDBigInts before iterating. This is to make division easier,
* as it makes our fist guess (quotient of high-order words)
* more accurate!
*
* Some day, we'll write a stopping test that takes
* account of the assymetry of the spacing of floating-point
* numbers below perfect powers of 2
* 26 Sept 96 is not that day.
* So we use a symmetric test.
*/
Bbits = nFractBits + B2 + ((B5 < n5bits.length) ? n5bits[B5] : (B5 * 3));
tenSbits = S2 + 1 +
(((S5 + 1) < n5bits.length) ? n5bits[(S5 + 1)] : ((S5 + 1) * 3));
if (Bbits < 64 && tenSbits < 64) {
if (Bbits < 32 && tenSbits < 32) {
// wa-hoo! They're all ints!
int b = ((int)fractBits * small5pow[B5]) << B2;
int s = small5pow[S5] << S2;
int m = small5pow[M5] << M2;
int tens = s * 10;
/*
* Unroll the first iteration. If our decExp estimate
* was too high, our first quotient will be zero. In this
* case, we discard it and decrement decExp.
*/
ndigit = 0;
q = (int)(b / s);
b = 10 * (b % s);
m *= 10;
low = (b < m);
high = (b + m > tens);
if (q >= 10) {
// bummer, dude
throw new RuntimeException(
"Assertion botch: excessivly large digit " + q);
} else if ((q == 0) && !high) {
// oops. Usually ignore leading zero.
decExp--;
} else {
digits[ndigit++] = (char)('0' + q);
}
/*
* HACK! Java spec sez that we always have at least
* one digit after the . in either F- or E-form output.
* Thus we will need more than one digit if we're using
* E-form
*/
if (decExp <= -3 || decExp >= 8) {
high = low = false;
} while (!low && !high) {
q = (int)(b / s);
b = 10 * (b % s);
m *= 10;
if (q >= 10) {
// bummer, dude
throw new RuntimeException(
"Assertion botch: excessivly large digit " + q);
}
if (m > 0L) {
low = (b < m);
high = (b + m > tens);
} else {
// hack -- m might overflow!
// in this case, it is certainly > b,
// which won't
// and b+m > tens, too, since that has overflowed
// either!
low = true;
high = true;
}
digits[ndigit++] = (char)('0' + q);
}
lowDigitDifference = (b << 1) - tens;
} else {
// still good! they're all longs!
long b = (fractBits * long5pow[B5]) << B2;
long s = long5pow[S5] << S2;
long m = long5pow[M5] << M2;
long tens = s * 10L;
/*
* Unroll the first iteration. If our decExp estimate
* was too high, our first quotient will be zero. In this
* case, we discard it and decrement decExp.
*/
ndigit = 0;
q = (int)(b / s);
b = 10L * (b % s);
m *= 10L;
low = (b < m);
high = (b + m > tens);
if (q >= 10) {
// bummer, dude
throw new RuntimeException(
"Assertion botch: excessivly large digit " + q);
} else if ((q == 0) && !high) {
// oops. Usually ignore leading zero.
decExp--;
} else {
digits[ndigit++] = (char)('0' + q);
}
/*
* HACK! Java spec sez that we always have at least
* one digit after the . in either F- or E-form output.
* Thus we will need more than one digit if we're using
* E-form
*/
if (decExp <= -3 || decExp >= 8) {
high = low = false;
} while (!low && !high) {
q = (int)(b / s);
b = 10 * (b % s);
m *= 10;
if (q >= 10) {
// bummer, dude
throw new RuntimeException(
"Assertion botch: excessivly large digit " + q);
}
if (m > 0L) {
low = (b < m);
high = (b + m > tens);
} else {
// hack -- m might overflow!
// in this case, it is certainly > b,
// which won't
// and b+m > tens, too, since that has overflowed
// either!
low = true;
high = true;
}
digits[ndigit++] = (char)('0' + q);
}
lowDigitDifference = (b << 1) - tens;
}
} else {
FDBigInt tenSval;
int shiftBias;
/*
* We really must do FDBigInt arithmetic.
* Fist, construct our FDBigInt initial values.
*/
Bval = multPow52(new FDBigInt(fractBits), B5, B2);
Sval = constructPow52(S5, S2);
Mval = constructPow52(M5, M2);
// normalize so that division works better
Bval.lshiftMe(shiftBias = Sval.normalizeMe());
Mval.lshiftMe(shiftBias);
tenSval = Sval.mult(10);
/*
* Unroll the first iteration. If our decExp estimate
* was too high, our first quotient will be zero. In this
* case, we discard it and decrement decExp.
*/
ndigit = 0;
q = Bval.quoRemIteration(Sval);
Mval = Mval.mult(10);
low = (Bval.cmp(Mval) < 0);
high = (Bval.add(Mval).cmp(tenSval) > 0);
if (q >= 10) {
// bummer, dude
throw new RuntimeException(
"Assertion botch: excessivly large digit " + q);
} else if ((q == 0) && !high) {
// oops. Usually ignore leading zero.
decExp--;
} else {
digits[ndigit++] = (char)('0' + q);
}
/*
* HACK! Java spec sez that we always have at least
* one digit after the . in either F- or E-form output.
* Thus we will need more than one digit if we're using
* E-form
*/
if (decExp <= -3 || decExp >= 8) {
high = low = false;
} while (!low && !high) {
q = Bval.quoRemIteration(Sval);
Mval = Mval.mult(10);
if (q >= 10) {
// bummer, dude
throw new RuntimeException(
"Assertion botch: excessivly large digit " + q);
}
low = (Bval.cmp(Mval) < 0);
high = (Bval.add(Mval).cmp(tenSval) > 0);
digits[ndigit++] = (char)('0' + q);
}
if (high && low) {
Bval.lshiftMe(1);
lowDigitDifference = Bval.cmp(tenSval);
} else
lowDigitDifference = 0L; // this here only for flow analysis!
}
this.decExponent = decExp + 1;
this.digits = digits;
this.nDigits = ndigit;
/*
* Last digit gets rounded based on stopping condition.
*/
if (high) {
if (low) {
if (lowDigitDifference == 0L) {
// it's a tie!
// choose based on which digits we like.
if ((digits[nDigits - 1] & 1) != 0)roundup();
} else if (lowDigitDifference > 0) {
roundup();
}
} else {
roundup();
}
}
}
public String
toString() {
// most brain-dead version
StringBuffer result = new StringBuffer(nDigits + 8);
if (isNegative) {result.append('-');
}
if (isExceptional) {
result.append(digits, 0, nDigits);
} else {
result.append("0.");
result.append(digits, 0, nDigits);
result.append('e');
result.append(decExponent);
}
return new String(result);
}
public String
toJavaFormatString() {
char result[] = new char[nDigits + 10];
int i = 0;
if (isNegative) {result[0] = '-';
i = 1;
}
if (isExceptional) {
System.arraycopy(digits, 0, result, i, nDigits);
i += nDigits;
} else {
if (decExponent > 0 && decExponent < 8) {
// print digits.digits.
int charLength = Math.min(nDigits, decExponent);
System.arraycopy(digits, 0, result, i, charLength);
i += charLength;
if (charLength < decExponent) {
charLength = decExponent - charLength;
System.arraycopy(zero, 0, result, i, charLength);
i += charLength;
result[i++] = '.';
result[i++] = '0';
} else {
result[i++] = '.';
if (charLength < nDigits) {
int t = nDigits - charLength;
System.arraycopy(digits, charLength, result, i, t);
i += t;
} else {
result[i++] = '0';
}
}
} else if (decExponent <= 0 && decExponent > -3) {
result[i++] = '0';
result[i++] = '.';
if (decExponent != 0) {
System.arraycopy(zero, 0, result, i, -decExponent);
i -= decExponent;
}
System.arraycopy(digits, 0, result, i, nDigits);
i += nDigits;
} else {
result[i++] = digits[0];
result[i++] = '.';
if (nDigits > 1) {
System.arraycopy(digits, 1, result, i, nDigits - 1);
i += nDigits - 1;
} else {
result[i++] = '0';
}
result[i++] = 'E';
int e;
if (decExponent <= 0) {
result[i++] = '-';
e = -decExponent + 1;
} else {
e = decExponent - 1;
}
// decExponent has 1, 2, or 3, digits
if (e <= 9) {
result[i++] = (char)(e + '0');
} else if (e <= 99) {
result[i++] = (char)(e / 10 + '0');
result[i++] = (char)(e % 10 + '0');
} else {
result[i++] = (char)(e / 100 + '0');
e %= 100;
result[i++] = (char)(e / 10 + '0');
result[i++] = (char)(e % 10 + '0');
}
}
}
return new String(result, 0, i);
}
public static FloatingDecimal
readJavaFormatString(String in) {
boolean isNegative = false;
boolean signSeen = false;
int decExp;
char c;
parseNumber:
try {
in = in.trim(); // don't fool around with white space.
// throws NullPointerException if null
int l = in.length();
if (l == 0)throw new NumberFormatException("empty String");
int i = 0;
switch (c = in.charAt(i)) {
case '-':
isNegative = true;
//FALLTHROUGH
case '+':
i++;
signSeen = true;
}
// Check for NaN and Infinity strings
c = in.charAt(i);
if (c == 'N' || c == 'I') { // possible NaN or infinity
boolean potentialNaN = false;
char targetChars[] = null; // char arrary of "NaN" or "Infinity"
if (c == 'N') {
targetChars = notANumber;
potentialNaN = true;
} else {
targetChars = infinity;
}
// assert(targetChars != null)
// compare Input string to "NaN" or "Infinity"
int j = 0;
while (i < l && j < targetChars.length) {
if (in.charAt(i) == targetChars[j]) {
i++;
j++;
} else // something is amiss, throw exception
break parseNumber;
}
// For the candidate string to be a NaN or infinity,
// all characters in input string and target char[]
// must be matched ==> j must equal targetChars.length
// and i must equal l
if ((j == targetChars.length) && (i == l)) { // return NaN or infinity
return (potentialNaN ? new FloatingDecimal(Double.NaN) // NaN has no sign
: new FloatingDecimal(isNegative ?
Double.NEGATIVE_INFINITY :
Double.POSITIVE_INFINITY));
} else { // something went wrong, throw exception
break parseNumber;
}
} // else carry on with original code as before
char[] digits = new char[l];
int nDigits = 0;
boolean decSeen = false;
int decPt = 0;
int nLeadZero = 0;
int nTrailZero = 0;
digitLoop:while (i < l) {
switch (c = in.charAt(i)) {
case '0':
if (nDigits > 0) {
nTrailZero += 1;
} else {
nLeadZero += 1;
}
break; // out of switch.
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
while (nTrailZero > 0) {
digits[nDigits++] = '0';
nTrailZero -= 1;
}
digits[nDigits++] = c;
break; // out of switch.
case '.':
if (decSeen) {
// already saw one ., this is the 2nd.
throw new NumberFormatException("multiple points");
}
decPt = i;
if (signSeen) {
decPt -= 1;
}
decSeen = true;
break; // out of switch.
default:
break digitLoop;
}
i++;
}
/*
* At this point, we've scanned all the digits and decimal
* point we're going to see. Trim off leading and trailing
* zeros, which will just confuse us later, and adjust
* our initial decimal exponent accordingly.
* To review:
* we have seen i total characters.
* nLeadZero of them were zeros before any other digits.
* nTrailZero of them were zeros after any other digits.
* if ( decSeen ), then a . was seen after decPt characters
* ( including leading zeros which have been discarded )
* nDigits characters were neither lead nor trailing
* zeros, nor point
*/
/*
* special hack: if we saw no non-zero digits, then the
* answer is zero!
* Unfortunately, we feel honor-bound to keep parsing!
*/
if (nDigits == 0) {
digits = zero;
nDigits = 1;
if (nLeadZero == 0) {
// we saw NO DIGITS AT ALL,
// not even a crummy 0!
// this is not allowed.
break parseNumber; // go throw exception
}
}
/* Our initial exponent is decPt, adjusted by the number of
* discarded zeros. Or, if there was no decPt,
* then its just nDigits adjusted by discarded trailing zeros.
*/
if (decSeen) {
decExp = decPt - nLeadZero;
} else {
decExp = nDigits + nTrailZero;
}
/*
* Look for 'e' or 'E' and an optionally signed integer.
*/
if ((i < l) && ((c = in.charAt(i)) == 'e') || (c == 'E')) {
int expSign = 1;
int expVal = 0;
int reallyBig = Integer.MAX_VALUE / 10;
boolean expOverflow = false;
switch (in.charAt(++i)) {
case '-':
expSign = -1;
//FALLTHROUGH
case '+':
i++;
}
int expAt = i;
expLoop:while (i < l) {
if (expVal >= reallyBig) {
// the next character will cause integer
// overflow.
expOverflow = true;
}
switch (c = in.charAt(i++)) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
expVal = expVal * 10 + ((int)c - (int)'0');
continue;
default:
i--; // back up.
break expLoop; // stop parsing exponent.
}
}
int expLimit = bigDecimalExponent + nDigits + nTrailZero;
if (expOverflow || (expVal > expLimit)) {
//
// The intent here is to end up with
// infinity or zero, as appropriate.
// The reason for yielding such a small decExponent,
// rather than something intuitive such as
// expSign*Integer.MAX_VALUE, is that this value
// is subject to further manipulation in
// doubleValue() and floatValue(), and I don't want
// it to be able to cause overflow there!
// (The only way we can get into trouble here is for
// really outrageous nDigits+nTrailZero, such as 2 billion. )
//
decExp = expSign * expLimit;
} else {
// this should not overflow, since we tested
// for expVal > (MAX+N), where N >= abs(decExp)
decExp = decExp + expSign * expVal;
}
// if we saw something not a digit ( or end of string )
// after the [Ee][+-], without seeing any digits at all
// this is certainly an error. If we saw some digits,
// but then some trailing garbage, that might be ok.
// so we just fall through in that case.
// HUMBUG
if (i == expAt)
break parseNumber; // certainly bad
}
/*
* We parsed everything we could.
* If there are leftovers, then this is not good input!
*/
if (i < l &&
((i != l - 1) ||
(in.charAt(i) != 'f' &&
in.charAt(i) != 'F' &&
in.charAt(i) != 'd' &&
in.charAt(i) != 'D'))) {
break parseNumber; // go throw exception
}
return new FloatingDecimal(isNegative, decExp, digits, nDigits, false);
} catch (StringIndexOutOfBoundsException e) {}
return null;
}
public static FloatingDecimal readJavaFormatString(byte []in, int i, int end) {
int start = i;
boolean isNegative = false;
boolean signSeen = false;
int decExp;
char c;
parseNumber:
try {
// throws NullPointerException if null
switch (c = (char)in[i]) {
case '-':
isNegative = true;
//FALLTHROUGH
case '+':
i++;
signSeen = true;
}
// Check for NaN and Infinity strings
c = (char)in[i];
if (c == 'N' || c == 'I') { // possible NaN or infinity
boolean potentialNaN = false;
char targetChars[] = null; // char arrary of "NaN" or "Infinity"
if (c == 'N') {
targetChars = notANumber;
potentialNaN = true;
} else {
targetChars = infinity;
}
// assert(targetChars != null)
// compare Input string to "NaN" or "Infinity"
int j = 0;
while (i < end && j < targetChars.length) {
if (in[i] == targetChars[j]) {
i++;
j++;
} else // something is amiss, throw exception
break parseNumber;
}
// For the candidate string to be a NaN or infinity,
// all characters in input string and target char[]
// must be matched ==> j must equal targetChars.length
// and i must equal l
if ((j == targetChars.length) && (i == end)) { // return NaN or infinity
return (potentialNaN ? new FloatingDecimal(Double.NaN) // NaN has no sign
: new FloatingDecimal(isNegative ?
Double.NEGATIVE_INFINITY :
Double.POSITIVE_INFINITY));
} else { // something went wrong, throw exception
break parseNumber;
}
} // else carry on with original code as before
char[] digits = new char[end - i];
int nDigits = 0;
boolean decSeen = false;
int decPt = 0;
int nLeadZero = 0;
int nTrailZero = 0;
digitLoop:
while (i < end) {
switch (c = (char)in[i]) {
case '0':
if (nDigits > 0) {
nTrailZero += 1;
} else {
nLeadZero += 1;
}
break; // out of switch.
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
while (nTrailZero > 0) {
digits[nDigits++] = '0';
nTrailZero -= 1;
}
digits[nDigits++] = c;
break; // out of switch.
case '.':
if (decSeen) {
// already saw one ., this is the 2nd.
throw new NumberFormatException("multiple points");
}
decPt = i - start;
if (signSeen) {
decPt -= 1;
}
decSeen = true;
break; // out of switch.
default:
break digitLoop;
}
i++;
}
/*
* At this point, we've scanned all the digits and decimal
* point we're going to see. Trim off leading and trailing
* zeros, which will just confuse us later, and adjust
* our initial decimal exponent accordingly.
* To review:
* we have seen i total characters.
* nLeadZero of them were zeros before any other digits.
* nTrailZero of them were zeros after any other digits.
* if ( decSeen ), then a . was seen after decPt characters
* ( including leading zeros which have been discarded )
* nDigits characters were neither lead nor trailing
* zeros, nor point
*/
/*
* special hack: if we saw no non-zero digits, then the
* answer is zero!
* Unfortunately, we feel honor-bound to keep parsing!
*/
if (nDigits == 0) {
digits = zero;
nDigits = 1;
if (nLeadZero == 0) {
// we saw NO DIGITS AT ALL,
// not even a crummy 0!
// this is not allowed.
break parseNumber; // go throw exception
}
}
/* Our initial exponent is decPt, adjusted by the number of
* discarded zeros. Or, if there was no decPt,
* then its just nDigits adjusted by discarded trailing zeros.
*/
if (decSeen) {
decExp = decPt - nLeadZero;
} else {
decExp = nDigits + nTrailZero;
}
/*
* Look for 'e' or 'E' and an optionally signed integer.
*/
if ((i < end) && ((c = (char)in[i]) == 'e') || (c == 'E')) {
int expSign = 1;
int expVal = 0;
int reallyBig = Integer.MAX_VALUE / 10;
boolean expOverflow = false;
switch (in[++i]) {
case '-':
expSign = -1;
//FALLTHROUGH
case '+':
i++;
}
int expAt = i;
expLoop:
while (i < end) {
if (expVal >= reallyBig) {
// the next character will cause integer
// overflow.
expOverflow = true;
}
switch (c = (char)in[i++]) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
expVal = expVal * 10 + ((int)c - (int)'0');
continue;
default:
i--; // back up.
break expLoop; // stop parsing exponent.
}
}
int expLimit = bigDecimalExponent + nDigits + nTrailZero;
if (expOverflow || (expVal > expLimit)) {
//
// The intent here is to end up with
// infinity or zero, as appropriate.
// The reason for yielding such a small decExponent,
// rather than something intuitive such as
// expSign*Integer.MAX_VALUE, is that this value
// is subject to further manipulation in
// doubleValue() and floatValue(), and I don't want
// it to be able to cause overflow there!
// (The only way we can get into trouble here is for
// really outrageous nDigits+nTrailZero, such as 2 billion. )
//
decExp = expSign * expLimit;
} else {
// this should not overflow, since we tested
// for expVal > (MAX+N), where N >= abs(decExp)
decExp = decExp + expSign * expVal;
}
// if we saw something not a digit ( or end of string )
// after the [Ee][+-], without seeing any digits at all
// this is certainly an error. If we saw some digits,
// but then some trailing garbage, that might be ok.
// so we just fall through in that case.
// HUMBUG
if (i == expAt)
break parseNumber; // certainly bad
}
/*
* We parsed everything we could.
* If there are leftovers, then this is not good input!
*/
if (i < end &&
((i != end - 1) ||
(in[i] != 'f' &&
in[i] != 'F' &&
in[i] != 'd' &&
in[i] != 'D'))) {
break parseNumber; // go throw exception
}
return new FloatingDecimal(isNegative, decExp, digits, nDigits, false);
} catch (StringIndexOutOfBoundsException e) {}
return null;
}
/*
* Take a FloatingDecimal, which we presumably just scanned in,
* and find out what its value is, as a double.
*
* AS A SIDE EFFECT, SET roundDir TO INDICATE PREFERRED
* ROUNDING DIRECTION in case the result is really destined
* for a single-precision float.
*/
public double
doubleValue() {
int kDigits = Math.min(nDigits, maxDecimalDigits + 1);
long lValue;
double dValue;
double rValue, tValue;
// First, check for NaN and Infinity values
if (digits == infinity || digits == notANumber) {
if (digits == notANumber)
return Double.NaN;
else
return (isNegative ? Double.NEGATIVE_INFINITY :
Double.POSITIVE_INFINITY);
} else {
roundDir = 0;
/*
* convert the lead kDigits to a long integer.
*/
// (special performance hack: start to do it using int)
int iValue = (int)digits[0] - (int)'0';
int iDigits = Math.min(kDigits, intDecimalDigits);
for (int i = 1; i < iDigits; i++) {
iValue = iValue * 10 + (int)digits[i] - (int)'0';
}
lValue = (long)iValue;
for (int i = iDigits; i < kDigits; i++) {
lValue = lValue * 10L + (long)((int)digits[i] - (int)'0');
}
dValue = (double)lValue;
int exp = decExponent - kDigits;
/*
* lValue now contains a long integer with the value of
* the first kDigits digits of the number.
* dValue contains the (double) of the same.
*/
if (nDigits <= maxDecimalDigits) {
/*
* possibly an easy case.
* We know that the digits can be represented
* exactly. And if the exponent isn't too outrageous,
* the whole thing can be done with one operation,
* thus one rounding error.
* Note that all our constructors trim all leading and
* trailing zeros, so simple values (including zero)
* will always end up here
*/
if (exp == 0 || dValue == 0.0)
return (isNegative) ? -dValue : dValue; // small floating integer
else if (exp >= 0) {
if (exp <= maxSmallTen) {
/*
* Can get the answer with one operation,
* thus one roundoff.
*/
rValue = dValue * small10pow[exp];
if (mustSetRoundDir) {
tValue = rValue / small10pow[exp];
roundDir = (tValue == dValue) ? 0
: (tValue < dValue) ? 1
: -1;
}
return (isNegative) ? -rValue : rValue;
}
int slop = maxDecimalDigits - kDigits;
if (exp <= maxSmallTen + slop) {
/*
* We can multiply dValue by 10^(slop)
* and it is still "small" and exact.
* Then we can multiply by 10^(exp-slop)
* with one rounding.
*/
dValue *= small10pow[slop];
rValue = dValue * small10pow[exp - slop];
if (mustSetRoundDir) {
tValue = rValue / small10pow[exp - slop];
roundDir = (tValue == dValue) ? 0
: (tValue < dValue) ? 1
: -1;
}
return (isNegative) ? -rValue : rValue;
}
/*
* Else we have a hard case with a positive exp.
*/
} else {
if (exp >= -maxSmallTen) {
/*
* Can get the answer in one division.
*/
rValue = dValue / small10pow[ -exp];
tValue = rValue * small10pow[ -exp];
if (mustSetRoundDir) {
roundDir = (tValue == dValue) ? 0
: (tValue < dValue) ? 1
: -1;
}
return (isNegative) ? -rValue : rValue;
}
/*
* Else we have a hard case with a negative exp.
*/
}
}
/*
* Harder cases:
* The sum of digits plus exponent is greater than
* what we think we can do with one error.
*
* Start by approximating the right answer by,
* naively, scaling by powers of 10.
*/
if (exp > 0) {
if (decExponent > maxDecimalExponent + 1) {
/*
* Lets face it. This is going to be
* Infinity. Cut to the chase.
*/
return (isNegative) ? Double.NEGATIVE_INFINITY :
Double.POSITIVE_INFINITY;
}
if ((exp & 15) != 0) {
dValue *= small10pow[exp & 15];
}
if ((exp >>= 4) != 0) {
int j;
for (j = 0; exp > 1; j++, exp >>= 1) {
if ((exp & 1) != 0)
dValue *= big10pow[j];
}
/*
* The reason for the weird exp > 1 condition
* in the above loop was so that the last multiply
* would get unrolled. We handle it here.
* It could overflow.
*/
double t = dValue * big10pow[j];
if (Double.isInfinite(t)) {
/*
* It did overflow.
* Look more closely at the result.
* If the exponent is just one too large,
* then use the maximum finite as our estimate
* value. Else call the result infinity
* and punt it.
* ( I presume this could happen because
* rounding forces the result here to be
* an ULP or two larger than
* Double.MAX_VALUE ).
*/
t = dValue / 2.0;
t *= big10pow[j];
if (Double.isInfinite(t)) {
return (isNegative) ? Double.NEGATIVE_INFINITY :
Double.POSITIVE_INFINITY;
}
t = Double.MAX_VALUE;
}
dValue = t;
}
} else if (exp < 0) {
exp = -exp;
if (decExponent < minDecimalExponent - 1) {
/*
* Lets face it. This is going to be
* zero. Cut to the chase.
*/
return (isNegative) ? -0.0 : 0.0;
}
if ((exp & 15) != 0) {
dValue /= small10pow[exp & 15];
}
if ((exp >>= 4) != 0) {
int j;
for (j = 0; exp > 1; j++, exp >>= 1) {
if ((exp & 1) != 0)
dValue *= tiny10pow[j];
}
/*
* The reason for the weird exp > 1 condition
* in the above loop was so that the last multiply
* would get unrolled. We handle it here.
* It could underflow.
*/
double t = dValue * tiny10pow[j];
if (t == 0.0) {
/*
* It did underflow.
* Look more closely at the result.
* If the exponent is just one too small,
* then use the minimum finite as our estimate
* value. Else call the result 0.0
* and punt it.
* ( I presume this could happen because
* rounding forces the result here to be
* an ULP or two less than
* Double.MIN_VALUE ).
*/
t = dValue * 2.0;
t *= tiny10pow[j];
if (t == 0.0) {
return (isNegative) ? -0.0 : 0.0;
}
t = Double.MIN_VALUE;
}
dValue = t;
}
}
/*
* dValue is now approximately the result.
* The hard part is adjusting it, by comparison
* with FDBigInt arithmetic.
* Formulate the EXACT big-number result as
* bigD0 * 10^exp
*/
FDBigInt bigD0 = new FDBigInt(lValue, digits, kDigits, nDigits);
exp = decExponent - nDigits;
correctionLoop:while (true) {
/* AS A SIDE EFFECT, THIS METHOD WILL SET THE INSTANCE VARIABLES
* bigIntExp and bigIntNBits
*/
FDBigInt bigB = doubleToBigInt(dValue);
/*
* Scale bigD, bigB appropriately for
* big-integer operations.
* Naively, we multipy by powers of ten
* and powers of two. What we actually do
* is keep track of the powers of 5 and
* powers of 2 we would use, then factor out
* common divisors before doing the work.
*/
int B2, B5; // powers of 2, 5 in bigB
int D2, D5; // powers of 2, 5 in bigD
int Ulp2; // powers of 2 in halfUlp.
if (exp >= 0) {
B2 = B5 = 0;
D2 = D5 = exp;
} else {
B2 = B5 = -exp;
D2 = D5 = 0;
}
if (bigIntExp >= 0) {
B2 += bigIntExp;
} else {
D2 -= bigIntExp;
}
Ulp2 = B2;
// shift bigB and bigD left by a number s. t.
// halfUlp is still an integer.
int hulpbias;
if (bigIntExp + bigIntNBits <= -expBias + 1) {
// This is going to be a denormalized number
// (if not actually zero).
// half an ULP is at 2^-(expBias+expShift+1)
hulpbias = bigIntExp + expBias + expShift;
} else {
hulpbias = expShift + 2 - bigIntNBits;
}
B2 += hulpbias;
D2 += hulpbias;
// if there are common factors of 2, we might just as well
// factor them out, as they add nothing useful.
int common2 = Math.min(B2, Math.min(D2, Ulp2));
B2 -= common2;
D2 -= common2;
Ulp2 -= common2;
// do multiplications by powers of 5 and 2
bigB = multPow52(bigB, B5, B2);
FDBigInt bigD = multPow52(new FDBigInt(bigD0), D5, D2);
//
// to recap:
// bigB is the scaled-big-int version of our floating-point
// candidate.
// bigD is the scaled-big-int version of the exact value
// as we understand it.
// halfUlp is 1/2 an ulp of bigB, except for special cases
// of exact powers of 2
//
// the plan is to compare bigB with bigD, and if the difference
// is less than halfUlp, then we're satisfied. Otherwise,
// use the ratio of difference to halfUlp to calculate a fudge
// factor to add to the floating value, then go 'round again.
//
FDBigInt diff;
int cmpResult;
boolean overvalue;
if ((cmpResult = bigB.cmp(bigD)) > 0) {
overvalue = true; // our candidate is too big.
diff = bigB.sub(bigD);
if ((bigIntNBits == 1) && (bigIntExp > -expBias)) {
// candidate is a normalized exact power of 2 and
// is too big. We will be subtracting.
// For our purposes, ulp is the ulp of the
// next smaller range.
Ulp2 -= 1;
if (Ulp2 < 0) {
// rats. Cannot de-scale ulp this far.
// must scale diff in other direction.
Ulp2 = 0;
diff.lshiftMe(1);
}
}
} else if (cmpResult < 0) {
overvalue = false; // our candidate is too small.
diff = bigD.sub(bigB);
} else {
// the candidate is exactly right!
// this happens with surprising fequency
break correctionLoop;
}
FDBigInt halfUlp = constructPow52(B5, Ulp2);
if ((cmpResult = diff.cmp(halfUlp)) < 0) {
// difference is small.
// this is close enough
roundDir = overvalue ? -1 : 1;
break correctionLoop;
} else if (cmpResult == 0) {
// difference is exactly half an ULP
// round to some other value maybe, then finish
dValue += 0.5 * ulp(dValue, overvalue);
// should check for bigIntNBits == 1 here??
roundDir = overvalue ? -1 : 1;
break correctionLoop;
} else {
// difference is non-trivial.
// could scale addend by ratio of difference to
// halfUlp here, if we bothered to compute that difference.
// Most of the time ( I hope ) it is about 1 anyway.
dValue += ulp(dValue, overvalue);
if (dValue == 0.0 || dValue == Double.POSITIVE_INFINITY)
break correctionLoop; // oops. Fell off end of range.
continue; // try again.
}
}
return (isNegative) ? -dValue : dValue;
}
}
/*
* Take a FloatingDecimal, which we presumably just scanned in,
* and find out what its value is, as a float.
* This is distinct from doubleValue() to avoid the extremely
* unlikely case of a double rounding error, wherein the converstion
* to double has one rounding error, and the conversion of that double
* to a float has another rounding error, IN THE WRONG DIRECTION,
* ( because of the preference to a zero low-order bit ).
*/
public float
floatValue() {
int kDigits = Math.min(nDigits, singleMaxDecimalDigits + 1);
int iValue;
float fValue;
// First, check for NaN and Infinity values
if (digits == infinity || digits == notANumber) {
if (digits == notANumber)
return Float.NaN;
else
return (isNegative ? Float.NEGATIVE_INFINITY :
Float.POSITIVE_INFINITY);
} else {
/*
* convert the lead kDigits to an integer.
*/
iValue = (int)digits[0] - (int)'0';
for (int i = 1; i < kDigits; i++) {
iValue = iValue * 10 + (int)digits[i] - (int)'0';
}
fValue = (float)iValue;
int exp = decExponent - kDigits;
/*
* iValue now contains an integer with the value of
* the first kDigits digits of the number.
* fValue contains the (float) of the same.
*/
if (nDigits <= singleMaxDecimalDigits) {
/*
* possibly an easy case.
* We know that the digits can be represented
* exactly. And if the exponent isn't too outrageous,
* the whole thing can be done with one operation,
* thus one rounding error.
* Note that all our constructors trim all leading and
* trailing zeros, so simple values (including zero)
* will always end up here.
*/
if (exp == 0 || fValue == 0.0f)
return (isNegative) ? -fValue : fValue; // small floating integer
else if (exp >= 0) {
if (exp <= singleMaxSmallTen) {
/*
* Can get the answer with one operation,
* thus one roundoff.
*/
fValue *= singleSmall10pow[exp];
return (isNegative) ? -fValue : fValue;
}
int slop = singleMaxDecimalDigits - kDigits;
if (exp <= singleMaxSmallTen + slop) {
/*
* We can multiply dValue by 10^(slop)
* and it is still "small" and exact.
* Then we can multiply by 10^(exp-slop)
* with one rounding.
*/
fValue *= singleSmall10pow[slop];
fValue *= singleSmall10pow[exp - slop];
return (isNegative) ? -fValue : fValue;
}
/*
* Else we have a hard case with a positive exp.
*/
} else {
if (exp >= -singleMaxSmallTen) {
/*
* Can get the answer in one division.
*/
fValue /= singleSmall10pow[ -exp];
return (isNegative) ? -fValue : fValue;
}
/*
* Else we have a hard case with a negative exp.
*/
}
} else if ((decExponent >= nDigits) &&
(nDigits + decExponent <= maxDecimalDigits)) {
/*
* In double-precision, this is an exact floating integer.
* So we can compute to double, then shorten to float
* with one round, and get the right answer.
*
* First, finish accumulating digits.
* Then convert that integer to a double, multiply
* by the appropriate power of ten, and convert to float.
*/
long lValue = (long)iValue;
for (int i = kDigits; i < nDigits; i++) {
lValue = lValue * 10L + (long)((int)digits[i] - (int)'0');
}
double dValue = (double)lValue;
exp = decExponent - nDigits;
dValue *= small10pow[exp];
fValue = (float)dValue;
return (isNegative) ? -fValue : fValue;
}
/*
* Harder cases:
* The sum of digits plus exponent is greater than
* what we think we can do with one error.
*
* Start by weeding out obviously out-of-range
* results, then convert to double and go to
* common hard-case code.
*/
if (decExponent > singleMaxDecimalExponent + 1) {
/*
* Lets face it. This is going to be
* Infinity. Cut to the chase.
*/
return (isNegative) ? Float.NEGATIVE_INFINITY :
Float.POSITIVE_INFINITY;
} else if (decExponent < singleMinDecimalExponent - 1) {
/*
* Lets face it. This is going to be
* zero. Cut to the chase.
*/
return (isNegative) ? -0.0f : 0.0f;
}
/*
* Here, we do 'way too much work, but throwing away
* our partial results, and going and doing the whole
* thing as double, then throwing away half the bits that computes
* when we convert back to float.
*
* The alternative is to reproduce the whole multiple-precision
* algorythm for float precision, or to try to parameterize it
* for common usage. The former will take about 400 lines of code,
* and the latter I tried without success. Thus the semi-hack
* answer here.
*/
mustSetRoundDir = true;
double dValue = doubleValue();
return stickyRound(dValue);
}
}
/*
* All the positive powers of 10 that can be
* represented exactly in double/float.
*/
private static final double small10pow[] = {
1.0e0,
1.0e1, 1.0e2, 1.0e3, 1.0e4, 1.0e5,
1.0e6, 1.0e7, 1.0e8, 1.0e9, 1.0e10,
1.0e11, 1.0e12, 1.0e13, 1.0e14, 1.0e15,
1.0e16, 1.0e17, 1.0e18, 1.0e19, 1.0e20,
1.0e21, 1.0e22
};
private static final float singleSmall10pow[] = {
1.0e0f,
1.0e1f, 1.0e2f, 1.0e3f, 1.0e4f, 1.0e5f,
1.0e6f, 1.0e7f, 1.0e8f, 1.0e9f, 1.0e10f
};
private static final double big10pow[] = {
1e16, 1e32, 1e64, 1e128, 1e256};
private static final double tiny10pow[] = {
1e-16, 1e-32, 1e-64, 1e-128, 1e-256};
private static final int maxSmallTen = small10pow.length - 1;
private static final int singleMaxSmallTen = singleSmall10pow.length - 1;
private static final int small5pow[] = {
1,
5,
5 * 5,
5 * 5 * 5,
5 * 5 * 5 * 5,
5 * 5 * 5 * 5 * 5,
5 * 5 * 5 * 5 * 5 * 5,
5 * 5 * 5 * 5 * 5 * 5 * 5,
5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5
};
private static final long long5pow[] = {
1L,
5L,
5L * 5,
5L * 5 * 5,
5L * 5 * 5 * 5,
5L * 5 * 5 * 5 * 5,
5L * 5 * 5 * 5 * 5 * 5,
5L * 5 * 5 * 5 * 5 * 5 * 5,
5L * 5 * 5 * 5 * 5 * 5 * 5 * 5,
5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 *
5,
5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 *
5 * 5,
5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 *
5 * 5 * 5,
5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 *
5 * 5 * 5 * 5,
5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 *
5 * 5 * 5 * 5 * 5,
5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 *
5 * 5 * 5 * 5 * 5 * 5,
5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 *
5 * 5 * 5 * 5 * 5 * 5 * 5,
5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 *
5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
};
// approximately ceil( log2( long5pow[i] ) )
private static final int n5bits[] = {
0,
3,
5,
7,
10,
12,
14,
17,
19,
21,
24,
26,
28,
31,
33,
35,
38,
40,
42,
45,
47,
49,
52,
54,
56,
59,
61,
};
private static final char infinity[] = {'I', 'n', 'f', 'i', 'n', 'i', 't',
'y'};
private static final char notANumber[] = {'N', 'a', 'N'};
private static final char zero[] = {'0', '0', '0', '0', '0', '0', '0', '0'};
}
/*
* A really, really simple bigint package
* tailored to the needs of floating base conversion.
*/
class FDBigInt {
int nWords; // number of words used
int data[]; // value: data[0] is least significant
public FDBigInt(int v) {
nWords = 1;
data = new int[1];
data[0] = v;
}
public FDBigInt(long v) {
data = new int[2];
data[0] = (int)v;
data[1] = (int)(v >>> 32);
nWords = (data[1] == 0) ? 1 : 2;
}
public FDBigInt(FDBigInt other) {
data = new int[nWords = other.nWords];
System.arraycopy(other.data, 0, data, 0, nWords);
}
private FDBigInt(int[] d, int n) {
data = d;
nWords = n;
}
public FDBigInt(long seed, char digit[], int nd0, int nd) {
int n = (nd + 8) / 9; // estimate size needed.
if (n < 2)n = 2;
data = new int[n]; // allocate enough space
data[0] = (int)seed; // starting value
data[1] = (int)(seed >>> 32);
nWords = (data[1] == 0) ? 1 : 2;
int i = nd0;
int limit = nd - 5; // slurp digits 5 at a time.
int v;
while (i < limit) {
int ilim = i + 5;
v = (int)digit[i++] - (int)'0';
while (i < ilim) {
v = 10 * v + (int)digit[i++] - (int)'0';
}
multaddMe(100000, v); // ... where 100000 is 10^5.
}
int factor = 1;
v = 0;
while (i < nd) {
v = 10 * v + (int)digit[i++] - (int)'0';
factor *= 10;
}
if (factor != 1) {
multaddMe(factor, v);
}
}
/*
* Left shift by c bits.
* Shifts this in place.
*/
public void
lshiftMe(int c) throws IllegalArgumentException {
if (c <= 0) {
if (c == 0)
return; // silly.
else
throw new IllegalArgumentException("negative shift count");
}
int wordcount = c >> 5;
int bitcount = c & 0x1f;
int anticount = 32 - bitcount;
int t[] = data;
int s[] = data;
if (nWords + wordcount + 1 > t.length) {
// reallocate.
t = new int[nWords + wordcount + 1];
}
int target = nWords + wordcount;
int src = nWords - 1;
if (bitcount == 0) {
// special hack, since an anticount of 32 won't go!
System.arraycopy(s, 0, t, wordcount, nWords);
target = wordcount - 1;
} else {
t[target--] = s[src] >>> anticount;
while (src >= 1) {
t[target--] = (s[src] << bitcount) | (s[--src] >>> anticount);
}
t[target--] = s[src] << bitcount;
} while (target >= 0) {
t[target--] = 0;
}
data = t;
nWords += wordcount + 1;
// may have constructed high-order word of 0.
// if so, trim it
while (nWords > 1 && data[nWords - 1] == 0)
nWords--;
}
/*
* normalize this number by shifting until
* the MSB of the number is at 0x08000000.
* This is in preparation for quoRemIteration, below.
* The idea is that, to make division easier, we want the
* divisor to be "normalized" -- usually this means shifting
* the MSB into the high words sign bit. But because we know that
* the quotient will be 0 < q < 10, we would like to arrange that
* the dividend not span up into another word of precision.
* (This needs to be explained more clearly!)
*/
public int
normalizeMe() throws IllegalArgumentException {
int src;
int wordcount = 0;
int bitcount = 0;
int v = 0;
for (src = nWords - 1; src >= 0 && (v = data[src]) == 0; src--) {
wordcount += 1;
}
if (src < 0) {
// oops. Value is zero. Cannot normalize it!
throw new IllegalArgumentException("zero value");
}
/*
* In most cases, we assume that wordcount is zero. This only
* makes sense, as we try not to maintain any high-order
* words full of zeros. In fact, if there are zeros, we will
* simply SHORTEN our number at this point. Watch closely...
*/
nWords -= wordcount;
/*
* Compute how far left we have to shift v s.t. its highest-
* order bit is in the right place. Then call lshiftMe to
* do the work.
*/
if ((v & 0xf0000000) != 0) {
// will have to shift up into the next word.
// too bad.
for (bitcount = 32; (v & 0xf0000000) != 0; bitcount--)
v >>>= 1;
} else {
while (v <= 0x000fffff) {
// hack: byte-at-a-time shifting
v <<= 8;
bitcount += 8;
} while (v <= 0x07ffffff) {
v <<= 1;
bitcount += 1;
}
}
if (bitcount != 0)
lshiftMe(bitcount);
return bitcount;
}
/*
* Multiply a FDBigInt by an int.
* Result is a new FDBigInt.
*/
public FDBigInt
mult(int iv) {
long v = iv;
int r[];
long p;
// guess adequate size of r.
r = new int[(v * ((long)data[nWords - 1] & 0xffffffffL) > 0xfffffffL) ?
nWords + 1 : nWords];
p = 0L;
for (int i = 0; i < nWords; i++) {
p += v * ((long)data[i] & 0xffffffffL);
r[i] = (int)p;
p >>>= 32;
}
if (p == 0L) {
return new FDBigInt(r, nWords);
} else {
r[nWords] = (int)p;
return new FDBigInt(r, nWords + 1);
}
}
/*
* Multiply a FDBigInt by an int and add another int.
* Result is computed in place.
* Hope it fits!
*/
public void
multaddMe(int iv, int addend) {
long v = iv;
long p;
// unroll 0th iteration, doing addition.
p = v * ((long)data[0] & 0xffffffffL) + ((long)addend & 0xffffffffL);
data[0] = (int)p;
p >>>= 32;
for (int i = 1; i < nWords; i++) {
p += v * ((long)data[i] & 0xffffffffL);
data[i] = (int)p;
p >>>= 32;
}
if (p != 0L) {
data[nWords] = (int)p; // will fail noisily if illegal!
nWords++;
}
}
/*
* Multiply a FDBigInt by another FDBigInt.
* Result is a new FDBigInt.
*/
public FDBigInt
mult(FDBigInt other) {
// crudely guess adequate size for r
int r[] = new int[nWords + other.nWords];
int i;
// I think I am promised zeros...
for (i = 0; i < this.nWords; i++) {
long v = (long)this.data[i] & 0xffffffffL; // UNSIGNED CONVERSION
long p = 0L;
int j;
for (j = 0; j < other.nWords; j++) {
p += ((long)r[i + j] & 0xffffffffL) +
v * ((long)other.data[j] & 0xffffffffL); // UNSIGNED CONVERSIONS ALL 'ROUND.
r[i + j] = (int)p;
p >>>= 32;
}
r[i + j] = (int)p;
}
// compute how much of r we actually needed for all that.
for (i = r.length - 1; i > 0; i--)
if (r[i] != 0)
break;
return new FDBigInt(r, i + 1);
}
/*
* Add one FDBigInt to another. Return a FDBigInt
*/
public FDBigInt
add(FDBigInt other) {
int i;
int a[], b[];
int n, m;
long c = 0L;
// arrange such that a.nWords >= b.nWords;
// n = a.nWords, m = b.nWords
if (this.nWords >= other.nWords) {
a = this.data;
n = this.nWords;
b = other.data;
m = other.nWords;
} else {
a = other.data;
n = other.nWords;
b = this.data;
m = this.nWords;
}
int r[] = new int[n];
for (i = 0; i < n; i++) {
c += (long)a[i] & 0xffffffffL;
if (i < m) {
c += (long)b[i] & 0xffffffffL;
}
r[i] = (int)c;
c >>= 32; // signed shift.
}
if (c != 0L) {
// oops -- carry out -- need longer result.
int s[] = new int[r.length + 1];
System.arraycopy(r, 0, s, 0, r.length);
s[i++] = (int)c;
return new FDBigInt(s, i);
}
return new FDBigInt(r, i);
}
/*
* Subtract one FDBigInt from another. Return a FDBigInt
* Assert that the result is positive.
*/
public FDBigInt
sub(FDBigInt other) {
int r[] = new int[this.nWords];
int i;
int n = this.nWords;
int m = other.nWords;
int nzeros = 0;
long c = 0L;
for (i = 0; i < n; i++) {
c += (long)this.data[i] & 0xffffffffL;
if (i < m) {
c -= (long)other.data[i] & 0xffffffffL;
}
if ((r[i] = (int)c) == 0)
nzeros++;
else
nzeros = 0;
c >>= 32; // signed shift.
}
if (c != 0L)
throw new RuntimeException(
"Assertion botch: borrow out of subtract");
while (i < m)
if (other.data[i++] != 0)
throw new RuntimeException(
"Assertion botch: negative result of subtract");
return new FDBigInt(r, n - nzeros);
}
/*
* Compare FDBigInt with another FDBigInt. Return an integer
* >0: this > other
* 0: this == other
* <0: this < other
*/
public int
cmp(FDBigInt other) {
int i;
if (this.nWords > other.nWords) {
// if any of my high-order words is non-zero,
// then the answer is evident
int j = other.nWords - 1;
for (i = this.nWords - 1; i > j; i--)
if (this.data[i] != 0)return 1;
} else if (this.nWords < other.nWords) {
// if any of other's high-order words is non-zero,
// then the answer is evident
int j = this.nWords - 1;
for (i = other.nWords - 1; i > j; i--)
if (other.data[i] != 0)return -1;
} else {
i = this.nWords - 1;
}
for (; i > 0; i--)
if (this.data[i] != other.data[i])
break;
// careful! want unsigned compare!
// use brute force here.
int a = this.data[i];
int b = other.data[i];
if (a < 0) {
// a is really big, unsigned
if (b < 0) {
return a - b; // both big, negative
} else {
return 1; // b not big, answer is obvious;
}
} else {
// a is not really big
if (b < 0) {
// but b is really big
return -1;
} else {
return a - b;
}
}
}
/*
* Compute
* q = (int)( this / S )
* this = 10 * ( this mod S )
* Return q.
* This is the iteration step of digit development for output.
* We assume that S has been normalized, as above, and that
* "this" has been lshift'ed accordingly.
* Also assume, of course, that the result, q, can be expressed
* as an integer, 0 <= q < 10.
*/
public int
quoRemIteration(FDBigInt S) throws IllegalArgumentException {
// ensure that this and S have the same number of
// digits. If S is properly normalized and q < 10 then
// this must be so.
if (nWords != S.nWords) {
throw new IllegalArgumentException("disparate values");
}
// estimate q the obvious way. We will usually be
// right. If not, then we're only off by a little and
// will re-add.
int n = nWords - 1;
long q = ((long)data[n] & 0xffffffffL) / (long)S.data[n];
long diff = 0L;
for (int i = 0; i <= n; i++) {
diff += ((long)data[i] & 0xffffffffL) -
q * ((long)S.data[i] & 0xffffffffL);
data[i] = (int)diff;
diff >>= 32; // N.B. SIGNED shift.
}
if (diff != 0L) {
// damn, damn, damn. q is too big.
// add S back in until this turns +. This should
// not be very many times!
long sum = 0L;
while (sum == 0L) {
sum = 0L;
for (int i = 0; i <= n; i++) {
sum += ((long)data[i] & 0xffffffffL) +
((long)S.data[i] & 0xffffffffL);
data[i] = (int)sum;
sum >>= 32; // Signed or unsigned, answer is 0 or 1
}
/*
* Originally the following line read
* "if ( sum !=0 && sum != -1 )"
* but that would be wrong, because of the
* treatment of the two values as entirely unsigned,
* it would be impossible for a carry-out to be interpreted
* as -1 -- it would have to be a single-bit carry-out, or
* +1.
*/
if (sum != 0 && sum != 1)
throw new RuntimeException("Assertion botch: " + sum +
" carry out of division correction");
q -= 1;
}
}
// finally, we can multiply this by 10.
// it cannot overflow, right, as the high-order word has
// at least 4 high-order zeros!
long p = 0L;
for (int i = 0; i <= n; i++) {
p += 10 * ((long)data[i] & 0xffffffffL);
data[i] = (int)p;
p >>= 32; // SIGNED shift.
}
if (p != 0L)
throw new RuntimeException("Assertion botch: carry out of *10");
return (int)q;
}
public long
longValue() {
// if this can be represented as a long,
// return the value
int i;
for (i = this.nWords - 1; i > 1; i--) {
if (data[i] != 0) {
throw new RuntimeException("Assertion botch: value too big");
}
}
switch (i) {
case 1:
if (data[1] < 0)
throw new RuntimeException("Assertion botch: value too big");
return ((long)(data[1]) << 32) | ((long)data[0] & 0xffffffffL);
case 0:
return ((long)data[0] & 0xffffffffL);
default:
throw new RuntimeException("Assertion botch: longValue confused");
}
}
public String
toString() {
StringBuffer r = new StringBuffer(30);
r.append('[');
int i = Math.min(nWords - 1, data.length - 1);
if (nWords > data.length) {
r.append("(" + data.length + "<" + nWords + "!)");
}
for (; i > 0; i--) {
r.append(Integer.toHexString(data[i]));
r.append((char)' ');
}
r.append(Integer.toHexString(data[0]));
r.append((char)']');
return new String(r);
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy