org.codehaus.plexus.util.TypeFormat Maven / Gradle / Ivy
Show all versions of virtdata-lib-curves4 Show documentation
/*
* J.A.D.E. Java(TM) Addition to Default Environment.
* Latest release available at http://jade.dautelle.com/
* This class is public domain (not copyrighted).
*/
package org.codehaus.plexus.util;
/**
* This class provides utility methods to parse CharSequence
* into primitive types and to format primitive types into
* StringBuffer
.
*
* Methods from this utility class do not create temporary objects
* and are typically faster than standard library methods (e.g {@link
* #parseDouble} is up to 15x faster than Double.parseDouble
).
*
*
* For class instances, formatting is typically performed using specialized
* java.text.Format
(Locale
sensitive)
* and/or using conventional methods (class sensitive). For example:
* public class Foo {
* public static Foo valueOf(CharSequence chars) {...} // Parses.
* public StringBuffer appendTo(StringBuffer sb) {...} // Formats.
* public String toString() {
* return appendTo(new StringBuffer()).toString();
* }
* }
*
* This class is public domain (not copyrighted).
*
* @author Jean-Marie Dautelle
* @version 4.6, June 22, 2003
*/
public final class TypeFormat {
/**
* Holds the characters used to represent numbers.
*/
private final static char[] DIGITS = {
'0' , '1' , '2' , '3' , '4' , '5' , '6' , '7' , '8' , '9' ,
'a' , 'b' , 'c' , 'd' , 'e' , 'f' , 'g' , 'h' , 'i' , 'j' ,
'k' , 'l' , 'm' , 'n' , 'o' , 'p' , 'q' , 'r' , 's' , 't' ,
'u' , 'v' , 'w' , 'x' , 'y' , 'z' };
/**
* Default constructor (forbids derivation).
*/
private TypeFormat() {}
/**
* Searches for a particular sequence within a character sequence
* (general purpose parsing function).
*
* @param pattern the character sequence to search for.
* @param chars the character sequence being searched.
* @param fromIndex the index in chars
to start the search
* from.
* @return the index in the range
* [fromIndex, chars.length()-pattern.length()]
* or -1
if the character sequence is not found.
*/
public static int indexOf(CharSequence pattern, CharSequence chars,
int fromIndex) {
int patternLength = pattern.length();
fromIndex = Math.max(0, fromIndex);
if (patternLength != 0) { // At least one character to search for.
char firstChar = pattern.charAt(0);
int last = chars.length() - patternLength;
for (int i=fromIndex; i <= last; i++) {
if (chars.charAt(i) == firstChar) {
boolean match = true;
for (int j=1; j < patternLength; j++) {
if (chars.charAt(i+j) != pattern.charAt(j)) {
match = false;
break;
}
}
if (match) {
return i;
}
}
}
return -1;
} else {
return Math.min(0, fromIndex);
}
}
/**
* Parses the specified CharSequence
as a boolean
.
*
* @param chars the character sequence to parse.
* @return the corresponding boolean
.
*/
public static boolean parseBoolean(CharSequence chars) {
return (chars.length() == 4) &&
(chars.charAt(0) == 't' || chars.charAt(0) == 'T') &&
(chars.charAt(1) == 'r' || chars.charAt(1) == 'R') &&
(chars.charAt(2) == 'u' || chars.charAt(2) == 'U') &&
(chars.charAt(3) == 'e' || chars.charAt(3) == 'E');
}
/**
* Parses the specified CharSequence
as a signed decimal
* short
.
*
* @param chars the character sequence to parse.
* @return parseShort(chars, 10)
* @throws NumberFormatException if the specified character sequence
* does not contain a parsable short
.
* @see #parseShort(CharSequence, int)
*/
public static short parseShort(CharSequence chars) {
return parseShort(chars, 10);
}
/**
* Parses the specified CharSequence
as a signed
* short
in the specified radix. The characters in the string
* must all be digits of the specified radix, except the first character
* which may be a plus sign '+'
or a minus sign
* '-'
.
*
* @param chars the character sequence to parse.
* @param radix the radix to be used while parsing.
* @return the corresponding short
.
* @throws NumberFormatException if the specified character sequence
* does not contain a parsable short
.
*/
public static short parseShort(CharSequence chars, int radix) {
try {
boolean isNegative = (chars.charAt(0) == '-') ? true : false;
int result = 0;
int limit = (isNegative) ? Short.MIN_VALUE : -Short.MAX_VALUE;
int multmin = limit / radix;
int length = chars.length();
int i = (isNegative || (chars.charAt(0) == '+')) ? 1 : 0;
while (true) {
int digit = Character.digit(chars.charAt(i), radix);
int tmp = result * radix;
if ((digit < 0) || (result < multmin) ||
(tmp < limit + digit)) { // Overflow.
throw new NumberFormatException(
"For input characters: \"" + chars.toString() + "\"");
}
// Accumulates negatively.
result = tmp - digit;
if (++i >= length) {
break;
}
}
return (short) (isNegative ? result : -result);
} catch (IndexOutOfBoundsException e) {
throw new NumberFormatException(
"For input characters: \"" + chars.toString() + "\"");
}
}
/**
* Parses the specified CharSequence
as a signed decimal
* int
.
*
* @param chars the character sequence to parse.
* @return parseInt(chars, 10)
* @throws NumberFormatException if the specified character sequence
* does not contain a parsable int
.
* @see #parseInt(CharSequence, int)
*/
public static int parseInt(CharSequence chars) {
return parseInt(chars, 10);
}
/**
* Parses the specified CharSequence
as a signed
* int
in the specified radix. The characters in the string
* must all be digits of the specified radix, except the first character
* which may be a plus sign '+'
or a minus sign
* '-'
.
*
* @param chars the character sequence to parse.
* @param radix the radix to be used while parsing.
* @return the corresponding int
.
* @throws NumberFormatException if the specified character sequence
* does not contain a parsable int
.
*/
public static int parseInt(CharSequence chars, int radix) {
try {
boolean isNegative = (chars.charAt(0) == '-') ? true : false;
int result = 0;
int limit = (isNegative) ? Integer.MIN_VALUE : -Integer.MAX_VALUE;
int multmin = limit / radix;
int length = chars.length();
int i = (isNegative || (chars.charAt(0) == '+')) ? 1 : 0;
while (true) {
int digit = Character.digit(chars.charAt(i), radix);
int tmp = result * radix;
if ((digit < 0) || (result < multmin) ||
(tmp < limit + digit)) { // Overflow.
throw new NumberFormatException(
"For input characters: \"" + chars.toString() + "\"");
}
// Accumulates negatively to avoid surprises near MAX_VALUE
result = tmp - digit;
if (++i >= length) {
break;
}
}
return isNegative ? result : -result;
} catch (IndexOutOfBoundsException e) {
throw new NumberFormatException(
"For input characters: \"" + chars.toString() + "\"");
}
}
/**
* Parses the specified CharSequence
as a signed decimal
* long
.
*
* @param chars the character sequence to parse.
* @return parseLong(chars, 10)
* @throws NumberFormatException if the specified character sequence
* does not contain a parsable long
.
* @see #parseLong(CharSequence, int)
*/
public static long parseLong(CharSequence chars) {
return parseLong(chars, 10);
}
/**
* Parses the specified CharSequence
as a signed
* long
in the specified radix. The characters in the string
* must all be digits of the specified radix, except the first character
* which may be a plus sign '+'
or a minus sign
* '-'
.
*
* @param chars the character sequence to parse.
* @param radix the radix to be used while parsing.
* @return the corresponding long
.
* @throws NumberFormatException if the specified character sequence
* does not contain a parsable long
.
*/
public static long parseLong(CharSequence chars, int radix) {
try {
boolean isNegative = (chars.charAt(0) == '-') ? true : false;
long result = 0;
long limit = (isNegative) ? Long.MIN_VALUE : -Long.MAX_VALUE;
long multmin = limit / radix;
int length = chars.length();
int i = (isNegative || (chars.charAt(0) == '+')) ? 1 : 0;
while (true) {
int digit = Character.digit(chars.charAt(i), radix);
long tmp = result * radix;
if ((digit < 0) || (result < multmin) ||
(tmp < limit + digit)) { // Overflow.
throw new NumberFormatException(
"For input characters: \"" + chars.toString() + "\"");
}
// Accumulates negatively to avoid surprises near MAX_VALUE
result = tmp - digit;
if (++i >= length) {
break;
}
}
return isNegative ? result : -result;
} catch (IndexOutOfBoundsException e) {
throw new NumberFormatException(
"For input characters: \"" + chars.toString() + "\"");
}
}
/**
* Parses this CharSequence
as a float
.
*
* @param chars the character sequence to parse.
* @return the float number represented by the specified character sequence.
* @throws NumberFormatException if the character sequence does not contain
* a parsable float
.
*/
public static float parseFloat(CharSequence chars) {
double d = parseDouble(chars);
if ( (d >= Float.MIN_VALUE) && (d <= Float.MAX_VALUE)) {
return (float) d;
} else {
throw new NumberFormatException(
"Float overflow for input characters: \"" +
chars.toString() + "\"");
}
}
/**
* Parses this CharSequence
as a double
.
*
* @param chars the character sequence to parse.
* @return the double number represented by this character sequence.
* @throws NumberFormatException if the character sequence does not contain
* a parsable double
.
*/
public static double parseDouble(CharSequence chars)
throws NumberFormatException {
try {
int length = chars.length();
double result = 0.0;
int exp = 0;
boolean isNegative = (chars.charAt(0) == '-') ? true : false;
int i = (isNegative || (chars.charAt(0) == '+')) ? 1 : 0;
// Checks special cases NaN or Infinity.
if ((chars.charAt(i) == 'N') || (chars.charAt(i) == 'I')) {
if (chars.toString().equals("NaN")) {
return Double.NaN;
} else if (chars.subSequence(i, length).toString().
equals("Infinity")) {
return isNegative ? Double.NEGATIVE_INFINITY :
Double.POSITIVE_INFINITY;
}
}
// Reads decimal number.
boolean fraction = false;
while (true) {
char c = chars.charAt(i);
if ( (c == '.') && (!fraction)) {
fraction = true;
} else if ((c == 'e') || (c == 'E')) {
break;
} else if ((c >= '0') && (c <= '9')) {
result = result * 10 + (c - '0');
if (fraction) {
exp--;
}
} else {
throw new NumberFormatException(
"For input characters: \"" + chars.toString() + "\"");
}
if (++i >= length) {
break;
}
}
result = isNegative ? - result : result;
// Reads exponent (if any).
if (i < length) {
i++;
boolean negE = (chars.charAt(i) == '-') ? true : false;
i = (negE || (chars.charAt(i) == '+')) ? i+1 : i;
int valE = 0;
while (true) {
char c = chars.charAt(i);
if ((c >= '0') && (c <= '9')) {
valE = valE * 10 + (c - '0');
if (valE > 10000000) { // Hard-limit to avoid overflow.
valE = 10000000;
}
} else {
throw new NumberFormatException(
"For input characters: \"" + chars.toString() +
"\"");
}
if (++i >= length) {
break;
}
}
exp += negE ? -valE : valE;
}
// Returns product decimal number with exponent.
return multE(result, exp);
} catch (IndexOutOfBoundsException e) {
throw new NumberFormatException(
"For input characters: \"" + chars.toString() + "\"");
}
}
/**
* Formats the specified boolean
and appends the resulting
* text to the StringBuffer
argument.
*
* @param b a boolean
.
* @param sb the StrinBuffer
to append.
* @return the specified StringBuffer
object.
* @see #parseBoolean
*/
public static StringBuffer format(boolean b, StringBuffer sb) {
return b ? sb.append("true") : sb.append("false");
}
/**
* Formats the specified short
and appends the resulting
* text (decimal representation) to the StringBuffer
argument.
*
* Note: This method is preferred to StringBuffer.append(short)
*
as it does not create temporary String
* objects (several times faster for small numbers).
*
* @param s the short
number.
* @param sb the StrinBuffer
to append.
* @return the specified StringBuffer
object.
* @see #parseShort
*/
public static StringBuffer format(short s, StringBuffer sb) {
return format((int)s, sb); // Forwards to int formatting (fast).
}
/**
* Formats the specified short
in the specified radix and
* appends the resulting text to the StringBuffer
argument.
*
* @param s the short
number.
* @param radix the radix.
* @param sb the StrinBuffer
to append.
* @return the specified StringBuffer
object.
* @see #parseShort(CharSequence, int)
* throws IllegalArgumentException if radix is not in [2 .. 36] range.
*/
public static StringBuffer format(short s, int radix, StringBuffer sb) {
return format((int)s, radix, sb); // Forwards to int formatting (fast).
}
/**
* Formats the specified int
and appends the resulting
* text (decimal representation) to the StringBuffer
argument.
*
* Note: This method is preferred to StringBuffer.append(int)
*
as it does not create temporary String
* objects (several times faster for small numbers).
*
* @param i the int
number.
* @param sb the StrinBuffer
to append.
* @return the specified StringBuffer
object.
* @see #parseInt
*/
public static StringBuffer format(int i, StringBuffer sb) {
if (i <= 0) {
if (i == Integer.MIN_VALUE) { // Negation would overflow.
return sb.append("-2147483648"); // 11 char max.
} else if (i == 0) {
return sb.append('0');
}
i = -i;
sb.append('-');
}
int j = 1;
for (; (j < 10) && (i >= INT_POW_10[j]); j++) {}
// POW_10[j] > i >= POW_10[j-1]
for (j--; j >= 0; j--) {
int pow10 = INT_POW_10[j];
int digit = i / pow10;
i -= digit * pow10;
sb.append(DIGITS[digit]);
}
return sb;
}
private static final int[] INT_POW_10 = new int[10];
static {
int pow = 1;
for (int i=0; i < 10; i++) {
INT_POW_10[i] = pow;
pow *= 10;
}
}
/**
* Formats the specified int
in the specified radix and appends
* the resulting text to the StringBuffer
argument.
*
* @param i the int
number.
* @param radix the radix.
* @param sb the StrinBuffer
to append.
* @return the specified StringBuffer
object.
* @see #parseInt(CharSequence, int)
* throws IllegalArgumentException if radix is not in [2 .. 36] range.
*/
public static StringBuffer format(int i, int radix, StringBuffer sb) {
if (radix == 10) {
return format(i, sb); // Faster version.
} else if (radix < 2 || radix > 36) {
throw new IllegalArgumentException("radix: " + radix);
}
if (i < 0) {
sb.append('-');
} else {
i = -i;
}
format2(i, radix, sb);
return sb;
}
private static void format2(int i, int radix, StringBuffer sb) {
if (i <= -radix) {
format2(i / radix, radix, sb);
sb.append(DIGITS[-(i % radix)]);
} else {
sb.append(DIGITS[-i]);
}
}
/**
* Formats the specified long
and appends the resulting
* text (decimal representation) to the StringBuffer
argument.
*
* Note: This method is preferred to StringBuffer.append(long)
*
as it does not create temporary String
* objects (several times faster for small numbers).
*
* @param l the long
number.
* @param sb the StrinBuffer
to append.
* @return the specified StringBuffer
object.
* @see #parseLong
*/
public static StringBuffer format(long l, StringBuffer sb) {
if (l <= 0) {
if (l == Long.MIN_VALUE) { // Negation would overflow.
return sb.append("-9223372036854775808"); // 20 characters max.
} else if (l == 0) {
return sb.append('0');
}
l = -l;
sb.append('-');
}
int j = 1;
for (; (j < 19) && (l >= LONG_POW_10[j]); j++) {}
// POW_10[j] > l >= POW_10[j-1]
for (j--; j >= 0; j--) {
long pow10 = LONG_POW_10[j];
int digit = (int) (l / pow10);
l -= digit * pow10;
sb.append(DIGITS[digit]);
}
return sb;
}
private static final long[] LONG_POW_10 = new long[19];
static {
long pow = 1;
for (int i=0; i < 19; i++) {
LONG_POW_10[i] = pow;
pow *= 10;
}
}
/**
* Formats the specified long
in the specified radix and
* appends the resulting text to the StringBuffer
argument.
*
* @param l the long
number.
* @param radix the radix.
* @param sb the StrinBuffer
to append.
* @return the specified StringBuffer
object.
* @see #parseLong(CharSequence, int)
* throws IllegalArgumentException if radix is not in [2 .. 36] range.
*/
public static StringBuffer format(long l, int radix, StringBuffer sb) {
if (radix == 10) {
return format(l, sb); // Faster version.
} else if (radix < 2 || radix > 36) {
throw new IllegalArgumentException("radix: " + radix);
}
if (l < 0) {
sb.append('-');
} else {
l = -l;
}
format2(l, radix, sb);
return sb;
}
private static void format2(long l, int radix, StringBuffer sb) {
if (l <= -radix) {
format2(l / radix, radix, sb);
sb.append(DIGITS[(int)-(l % radix)]);
} else {
sb.append(DIGITS[(int)-l]);
}
}
/**
* Formats the specified float
and appends the resulting
* text to the StringBuffer
argument.
*
* @param f the float
number.
* @param sb the StrinBuffer
to append.
* @return format(f, 0.0f, sb)
* @see #format(float, float, StringBuffer)
*/
public static StringBuffer format(float f, StringBuffer sb) {
return format(f, 0.0f, sb);
}
/**
* Formats the specified float
and appends the resulting text
* to the StringBuffer
argument; the number of significative
* digits is deduced from the specifed precision. All digits at least as
* significant as the specified precision are represented. For example:
*
* format(5.6f, 0.01f, sb)
appends "5.60"
* format(5.6f, 0.1f, sb)
appends "5.6"
* format(5.6f, 1f, sb)
appends "6"
*
* If the precision is 0.0f
, the precision is assumed to be
* the intrinsic float
precision (64 bits IEEE 754 format);
* no formatting is performed, all significant digits are displayed and
* trailing zeros are removed.
*
* @param f the float
number.
* @param precision the maximum weight of the last digit represented.
* @param sb the StrinBuffer
to append.
* @return the specified StringBuffer
object.
* @throws IllegalArgumentException if the specified precision is negative
* or would result in too many digits (19+).
*/
public static StringBuffer format(float f, float precision,
StringBuffer sb) {
// Adjusts precision.
boolean precisionOnLastDigit;
if (precision > 0.0f) {
precisionOnLastDigit = true;
} else if (precision == 0.0f) {
if (f != 0.0f) {
precisionOnLastDigit = false;
precision = Math.max(Math.abs(f * FLOAT_RELATIVE_ERROR),
Float.MIN_VALUE);
} else {
return sb.append("0.0"); // Exact zero.
}
} else {
throw new IllegalArgumentException(
"precision: Negative values not allowed");
}
return format(f, precision, precisionOnLastDigit, sb);
}
/**
* Formats the specified double
and appends the resulting
* text to the StringBuffer
argument.
*
* Note : This method is preferred to StringBuffer.append(double)
*
or even String.valueOf(double)
as it
* does not create temporary String
or
* FloatingDecimal
objects (several times faster,
* e.g. 15x faster for Double.MAX_VALUE
).
*
* @param d the double
number.
* @param sb the StrinBuffer
to append.
* @return format(d, 0.0, sb)
* @see #format(double, double, StringBuffer)
*/
public static StringBuffer format(double d, StringBuffer sb) {
return format(d, 0.0, sb);
}
/**
* Formats the specified double
and appends the resulting text
* to the StringBuffer
argument; the number of significand
* digits is specified as integer argument.
*
* @param d the double
number.
* @param digits the number of significand digits (excludes exponent).
* @param sb the StrinBuffer
to append.
* @return the specified StringBuffer
object.
* @throws IllegalArgumentException if the number of digits is not in
* range [1..19]
.
*/
public static StringBuffer format(double d, int digits,
StringBuffer sb) {
if ((digits >= 1) && (digits <= 19)) {
double precision = Math.abs(d / DOUBLE_POW_10[digits-1]);
return format(d, precision, sb);
} else {
throw new java.lang.IllegalArgumentException(
"digits: " + digits + " is not in range [1 .. 19]");
}
}
/**
* Formats the specified double
and appends the resulting text
* to the StringBuffer
argument; the number of significative
* digits is deduced from the specifed precision. All digits at least as
* significant as the specified precision are represented. For example:
*
* format(5.6, 0.01, sb)
appends "5.60"
* format(5.6, 0.1, sb)
appends "5.6"
* format(5.6, 1, sb)
appends "6"
*
* If the precision is 0.0
, the precision is assumed to be
* the intrinsic double
precision (64 bits IEEE 754 format);
* no formatting is performed, all significant digits are displayed and
* trailing zeros are removed.
*
* @param d the double
number.
* @param precision the maximum weight of the last digit represented.
* @param sb the StrinBuffer
to append.
* @return the specified StringBuffer
object.
* @throws IllegalArgumentException if the specified precision is negative
* or would result in too many digits (19+).
*/
public static StringBuffer format(double d, double precision,
StringBuffer sb) {
// Adjusts precision.
boolean precisionOnLastDigit = false;
if (precision > 0.0) {
precisionOnLastDigit = true;
} else if (precision == 0.0) {
if (d != 0.0) {
precision = Math.max(Math.abs(d * DOUBLE_RELATIVE_ERROR),
Double.MIN_VALUE);
} else {
return sb.append("0.0"); // Exact zero.
}
} else if (precision < 0.0) { // Not NaN
throw new IllegalArgumentException(
"precision: Negative values not allowed");
}
return format(d, precision, precisionOnLastDigit, sb);
}
/**
* Formats the specified double
and appends the resulting text
* to the StringBuffer
argument; the number of significative
* digits is deduced from the specifed precision.
*
* @param d the double
number.
* @param precision the maximum weight of the last digit represented.
* @param precisionOnLastDigit indicates if the number of digits is
* deduced from the specified precision.
* @param sb the StrinBuffer
to append.
* @return the specified StringBuffer
object.
*/
private static StringBuffer format(double d, double precision,
boolean precisionOnLastDigit,
StringBuffer sb) {
// Special cases.
if (Double.isNaN(d)) {
return sb.append("NaN");
} else if (Double.isInfinite(d)) {
return (d >= 0) ? sb.append("Infinity") : sb.append("-Infinity");
}
if (d < 0) {
d = -d;
sb.append('-');
}
// Formats decimal part.
int rank = (int) Math.floor(Math.log(precision) / LOG_10);
double digitValue = multE(d, -rank);
if (digitValue >= Long.MAX_VALUE) {
throw new IllegalArgumentException(
"Specified precision would result in too many digits");
}
int digitStart = sb.length();
format(Math.round(digitValue), sb);
int digitLength = sb.length() - digitStart;
int dotPos = digitLength + rank;
boolean useScientificNotation = false;
// Inserts dot ('.')
if ((dotPos <= -LEADING_ZEROS.length) || (dotPos > digitLength)) {
// Scientific notation has to be used ("x.xxxEyy").
sb.insert(digitStart + 1, '.');
useScientificNotation = true;
} else if (dotPos > 0) {
// Dot within the string ("xxxx.xxxxx").
sb.insert(digitStart + dotPos, '.');
} else {
// Leading zeros ("0.xxxxx").
sb.insert(digitStart, LEADING_ZEROS[-dotPos]);
}
// Removes trailing zeros.
if (!precisionOnLastDigit) {
int newLength = sb.length();
do {
newLength--;
} while (sb.charAt(newLength) == '0');
sb.setLength(newLength+1);
}
// Avoids trailing '.'
if (sb.charAt(sb.length()-1) == '.') {
if (precisionOnLastDigit) {
sb.setLength(sb.length()-1); // Prefers "xxx" to "xxx."
} else {
sb.append('0'); // Prefer "xxx.0" to "xxx."
}
}
// Writes exponent.
if (useScientificNotation) {
sb.append('E');
format(dotPos - 1, sb);
}
return sb;
}
private static final double LOG_10 = Math.log(10);
private static final float FLOAT_RELATIVE_ERROR = (float) Math.pow(2, -24);
private static final double DOUBLE_RELATIVE_ERROR = Math.pow(2, -53);
private static String[] LEADING_ZEROS = {"0.", "0.0", "0.00"};
/**
* Returns the product of the specified value with 10
raised
* at the specified power exponent.
*
* @param value the value.
* @param E the exponent.
* @return value * 10^E
*/
private static final double multE(double value, int E) {
if (E >= 0) {
if (E <= 308) {
// Max: 1.7976931348623157E+308
return value * DOUBLE_POW_10[E];
} else {
value *= 1E21; // Exact multiplicand.
E = Math.min(308, E-21);
return value * DOUBLE_POW_10[E];
}
} else {
if (E >= -308) {
return value / DOUBLE_POW_10[-E];
} else {
// Min: 4.9E-324
value /= 1E21; // Exact divisor.
E = Math.max(-308, E+21);
return value / DOUBLE_POW_10[-E];
}
}
}
// Note: Approximation for exponents > 21. This may introduce round-off
// errors (e.g. 1E23 represented as "9.999999999999999E22").
private static final double[] DOUBLE_POW_10 = new double[] {
1E000, 1E001, 1E002, 1E003, 1E004, 1E005, 1E006, 1E007, 1E008, 1E009,
1E010, 1E011, 1E012, 1E013, 1E014, 1E015, 1E016, 1E017, 1E018, 1E019,
1E020, 1E021, 1E022, 1E023, 1E024, 1E025, 1E026, 1E027, 1E028, 1E029,
1E030, 1E031, 1E032, 1E033, 1E034, 1E035, 1E036, 1E037, 1E038, 1E039,
1E040, 1E041, 1E042, 1E043, 1E044, 1E045, 1E046, 1E047, 1E048, 1E049,
1E050, 1E051, 1E052, 1E053, 1E054, 1E055, 1E056, 1E057, 1E058, 1E059,
1E060, 1E061, 1E062, 1E063, 1E064, 1E065, 1E066, 1E067, 1E068, 1E069,
1E070, 1E071, 1E072, 1E073, 1E074, 1E075, 1E076, 1E077, 1E078, 1E079,
1E080, 1E081, 1E082, 1E083, 1E084, 1E085, 1E086, 1E087, 1E088, 1E089,
1E090, 1E091, 1E092, 1E093, 1E094, 1E095, 1E096, 1E097, 1E098, 1E099,
1E100, 1E101, 1E102, 1E103, 1E104, 1E105, 1E106, 1E107, 1E108, 1E109,
1E110, 1E111, 1E112, 1E113, 1E114, 1E115, 1E116, 1E117, 1E118, 1E119,
1E120, 1E121, 1E122, 1E123, 1E124, 1E125, 1E126, 1E127, 1E128, 1E129,
1E130, 1E131, 1E132, 1E133, 1E134, 1E135, 1E136, 1E137, 1E138, 1E139,
1E140, 1E141, 1E142, 1E143, 1E144, 1E145, 1E146, 1E147, 1E148, 1E149,
1E150, 1E151, 1E152, 1E153, 1E154, 1E155, 1E156, 1E157, 1E158, 1E159,
1E160, 1E161, 1E162, 1E163, 1E164, 1E165, 1E166, 1E167, 1E168, 1E169,
1E170, 1E171, 1E172, 1E173, 1E174, 1E175, 1E176, 1E177, 1E178, 1E179,
1E180, 1E181, 1E182, 1E183, 1E184, 1E185, 1E186, 1E187, 1E188, 1E189,
1E190, 1E191, 1E192, 1E193, 1E194, 1E195, 1E196, 1E197, 1E198, 1E199,
1E200, 1E201, 1E202, 1E203, 1E204, 1E205, 1E206, 1E207, 1E208, 1E209,
1E210, 1E211, 1E212, 1E213, 1E214, 1E215, 1E216, 1E217, 1E218, 1E219,
1E220, 1E221, 1E222, 1E223, 1E224, 1E225, 1E226, 1E227, 1E228, 1E229,
1E230, 1E231, 1E232, 1E233, 1E234, 1E235, 1E236, 1E237, 1E238, 1E239,
1E240, 1E241, 1E242, 1E243, 1E244, 1E245, 1E246, 1E247, 1E248, 1E249,
1E250, 1E251, 1E252, 1E253, 1E254, 1E255, 1E256, 1E257, 1E258, 1E259,
1E260, 1E261, 1E262, 1E263, 1E264, 1E265, 1E266, 1E267, 1E268, 1E269,
1E270, 1E271, 1E272, 1E273, 1E274, 1E275, 1E276, 1E277, 1E278, 1E279,
1E280, 1E281, 1E282, 1E283, 1E284, 1E285, 1E286, 1E287, 1E288, 1E289,
1E290, 1E291, 1E292, 1E293, 1E294, 1E295, 1E296, 1E297, 1E298, 1E299,
1E300, 1E301, 1E302, 1E303, 1E304, 1E305, 1E306, 1E307, 1E308 };
}