digitlist.java
来自「《移动Agent技术》一书的所有章节源代码。」· Java 代码 · 共 537 行 · 第 1/2 页
JAVA
537 行
// The negative of the exponent represents the number of leading
// zeros between the decimal and the first non-zero digit, for
// a value < 0.1 (e.g., for 0.00123, -decimalAt == 2). If this
// is more than the maximum fraction digits, then we have an underflow
// for the printed representation. We recognize this here and set
// the DigitList representation to zero in this situation.
if (-decimalAt >= maximumDigits) count = 0;
}
// Eliminate trailing zeros.
while (count > 1 && digits[count - 1] == '0')
--count;
if (DEBUG)
{
System.out.print("Before rounding 0.");
for (int i=0; i<count; ++i) System.out.print((char)digits[i]);
System.out.println("x10^" + decimalAt);
}
// Eliminate digits beyond maximum digits to be displayed.
// Round up if appropriate.
round(fixedPoint ? (maximumDigits + decimalAt) : maximumDigits);
if (DEBUG)
{
System.out.print("After rounding 0.");
for (int i=0; i<count; ++i) System.out.print((char)digits[i]);
System.out.println("x10^" + decimalAt);
}
// The following method also works, and does not rely on the specific
// format generated by Double.toString(). However, it introduces significant
// errors in the least-significant digits, which cause round-trip parse and
// format operations to fail. We retain this code for future reference;
// the compiler will ignore it.
if (false)
{
// Find the exponent for this value. Our convention is 0.mmmm * 10^decimalAt,
// so we need to add one.
decimalAt = log10(source) + 1;
// Compute the number of digits to generate based on the maximum fraction
// digits and the exponent. For example, if the exponent is -95 and the
// maximum fraction digits is 100, then we'll have 95 leading zeros and only
// 5 significant digits.
count = maximumDigits + decimalAt;
if (count > DBL_DIG) count = DBL_DIG;
if (count < 0) count = 0;
if (count == 0) return; // Return if we've underflowed to zero
// Put the mantissa into a long. We create a mantissa value in the
// range 10^n-1 <= mantissa < 10^n, where n is the desired number of
// digits. If this is a small number << 1, decimalAt may be negative,
// indicating leading zeros between the decimal point an digits[0]. A
// decimalAt value of 0 indicates that the decimal point is before
// digits[0].
//System.out.println("d = " + source + " log = " + (Math.log(source) / LOG10));
//System.out.println("d == 0.1 " + (source == 0.1));
long mantissa = Math.round(source * Math.pow(10, count - decimalAt));
String longRep = Long.toString(mantissa);
// At this point we have a representation of exactly maxDecimalCount
// characters.
// FOLLOWING LINE FOR DEBUGGING ONLY. THIS catches problems with log10 computation.
if (longRep.length() != count)
throw new Error("Rep=" + longRep + " rep.length=" + longRep.length() +
" exp.len=" + count + " " +
"val=" + source + " mant=" + mantissa +
" decimalAt=" + decimalAt);
// Eliminate trailing zeros.
while (count > 1 && longRep.charAt(count - 1) == '0')
--count;
// Copy digits over
for (int i=0; i<count; ++i)
digits[i] = (byte)longRep.charAt(i);
}
}
/**
* Round the representation to the given number of digits.
* @param maximumDigits The maximum number of digits to be shown.
* Upon return, count will be less than or equal to maximumDigits.
*/
private final void round(int maximumDigits)
{
// Eliminate digits beyond maximum digits to be displayed.
// Round up if appropriate.
if (maximumDigits >= 0 && maximumDigits < count)
{
// Check for round to the nearest even. HShih
if (digits[maximumDigits] == '5' && digits[maximumDigits-1] != '9' &&
(maximumDigits+1 >= count || digits[maximumDigits+1] == '0')) {
if (digits[maximumDigits-1] % 2 != 0)
++digits[maximumDigits-1];
} else if (digits[maximumDigits] >= '5')
{
// Rounding up involved incrementing digits from LSD to MSD.
// In most cases this is simple, but in a worst case situation
// (9999..99) we have to adjust the decimalAt value.
for (;;)
{
--maximumDigits;
if (maximumDigits < 0)
{
// We have all 9's, so we increment to a single digit
// of one and adjust the exponent.
digits[0] = '1';
++decimalAt;
maximumDigits = 0; // Adjust the count
break;
}
++digits[maximumDigits];
if (digits[maximumDigits] <= '9') break;
// digits[maximumDigits] = '0'; // Unnecessary since we'll truncate this
}
++maximumDigits; // Increment for use as count
}
count = maximumDigits;
}
}
/**
* Utility routine to set the value of the digit list from a long
*/
public final void set(long source)
{
set(source, 0);
}
/**
* Set the digit list to a representation of the given long value.
* @param source Value to be converted; must be >= 0 or ==
* Long.MIN_VALUE.
* @param maximumDigits The most digits which should be converted.
* If maximumDigits is lower than the number of significant digits
* in source, the representation will be rounded. Ignored if <= 0.
*/
public final void set(long source, int maximumDigits)
{
// for now, simple implementation; later, do proper IEEE stuff
// String stringDigits = Long.toString(source);
String stringDigits = Long.toString(source);
// This method does not expect a negative number. However,
// "source" can be a Long.MIN_VALUE (-9223372036854775808),
// if the number being formatted is a Long.MIN_VALUE. In that
// case, it will be formatted as -Long.MIN_VALUE, a number
// which is outside the legal range of a long, but which can
// be represented by DigitList.
if (stringDigits.charAt(0) == '-') stringDigits = stringDigits.substring(1);
count = decimalAt = stringDigits.length();
// Don't copy trailing zeros
while (count > 1 && stringDigits.charAt(count - 1) == '0') --count;
for (int i = 0; i < count; ++i)
digits[i] = (byte) stringDigits.charAt(i);
if (maximumDigits > 0) round(maximumDigits);
}
/**
* equality test between two digit lists.
*/
public boolean equals(Object obj) {
if (this == obj) // quick check
return true;
if (!(obj instanceof DigitList)) // (1) same object?
return false;
DigitList other = (DigitList) obj;
if (count != other.count ||
decimalAt != other.decimalAt)
return false;
for (int i = 0; i < count; i++)
if (digits[i] != other.digits[i])
return false;
return true;
}
/**
* Generates the hash code for the digit list.
*/
public int hashCode() {
int hashcode = decimalAt;
for (int i = 0; i < count; i++)
hashcode = hashcode * 37 + digits[i];
return hashcode;
}
/**
* Returns true if this DigitList represents Long.MIN_VALUE;
* false, otherwise. This is required so that getLong() works.
*/
private boolean isLongMIN_VALUE()
{
if (decimalAt != count || count != MAX_COUNT)
return false;
for (int i = 0; i < count; ++i)
{
if (digits[i] != LONG_MIN_REP[i]) return false;
}
return true;
}
private static byte[] LONG_MIN_REP;
static
{
// Store the representation of LONG_MIN without the leading '-'
String s = Long.toString(Long.MIN_VALUE);
LONG_MIN_REP = new byte[MAX_COUNT];
for (int i=0; i < MAX_COUNT; ++i)
{
LONG_MIN_REP[i] = (byte)s.charAt(i + 1);
}
}
/**
* Return the floor of the log base 10 of a given double.
* This method compensates for inaccuracies which arise naturally when
* computing logs, and always give the correct value. The parameter
* must be positive and finite.
*/
private static final int log10(double d)
{
// The reason this routine is needed is that simply taking the
// log and dividing by log10 yields a result which may be off
// by 1 due to rounding errors. For example, the naive log10
// of 1.0e300 taken this way is 299, rather than 300.
double log10 = Math.log(d) / LOG10;
int ilog10 = (int)Math.floor(log10);
// Positive logs could be too small, e.g. 0.99 instead of 1.0
if (log10 > 0 && d >= Math.pow(10, ilog10 + 1))
{
++ilog10;
}
// Negative logs could be too big, e.g. -0.99 instead of -1.0
else if (log10 < 0 && d < Math.pow(10, ilog10))
{
--ilog10;
}
return ilog10;
}
private static final double LOG10 = Math.log(10.0);
public String toString()
{
if (isZero()) return "0";
StringBuffer buf = new StringBuffer("0.");
for (int i=0; i<count; ++i) buf.append((char)digits[i]);
buf.append("x10^");
buf.append(decimalAt);
return buf.toString();
}
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?