/*
 * Javolution - Java(TM) Solution for Real-Time and Embedded Systems
 * Copyright (C) 2005 - Javolution (http://javolution.org/)
 * All rights reserved.
 * 
 * Permission to use, copy, modify, and distribute this software is
 * freely granted, provided that this notice is preserved.
 */
package javolution37.javolution.lang;

import java.lang.CharSequence;

import javolution37.javolution.lang.TextFormat.Cursor;

import java.io.IOException;

/**
 * 

This class provides utility methods to parse CharSequence * into primitive types and to format primitive types into an * Appendable.

* *

Methods from this class do not create temporary objects * and are typically faster than standard library methods (e.g * TypeFormat#parseDouble is up to 15x faster than * Double.parseDouble).

* *

For non-primitive objects, formatting is typically performed using * specialized {@link TextFormat} instances.

* * @author Jean-Marie Dautelle * @version 3.7, January 1, 2006 */ public final class TypeFormat { /** * Holds the digits to character mapping. */ private final static char[] DIGIT_TO_CHAR = { '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' }; /** * Holds the character to digit mapping. */ private final static int[] CHAR_TO_DIGIT = new int[128]; static { for (int i = 0; i < CHAR_TO_DIGIT.length; i++) { CHAR_TO_DIGIT[i] = -1; } for (int i = 0; i < DIGIT_TO_CHAR.length; i++) { CHAR_TO_DIGIT[DIGIT_TO_CHAR[i]] = i; CHAR_TO_DIGIT[Character.toUpperCase(DIGIT_TO_CHAR[i])] = i; } } /** * Default constructor (forbids derivation). */ private TypeFormat() { } /** * Parses the specified character sequence as a boolean. * * @param csq the character sequence to parse. * @return the corresponding boolean value. * @throws IllegalArgumentException if the specified character sequence * is different from "true" or "false" ignoring cases. */ public static boolean parseBoolean(CharSequence csq) { if ((csq.length() == 4) && (csq.charAt(0) == 't' || csq.charAt(0) == 'T') && (csq.charAt(1) == 'r' || csq.charAt(1) == 'R') && (csq.charAt(2) == 'u' || csq.charAt(2) == 'U') && (csq.charAt(3) == 'e' || csq.charAt(3) == 'E')) { return true; } else if ((csq.length() == 5) && (csq.charAt(0) == 'f' || csq.charAt(0) == 'F') && (csq.charAt(1) == 'a' || csq.charAt(1) == 'A') && (csq.charAt(2) == 'l' || csq.charAt(2) == 'L') && (csq.charAt(3) == 's' || csq.charAt(3) == 'S') && (csq.charAt(4) == 'e' || csq.charAt(4) == 'E')) { return false; } throw new IllegalArgumentException("Cannot parse " + csq + " as boolean"); } /** * Parses the specified character sequence from the specified position * as a boolean. * * @param csq the character sequence to parse. * @param cursor the current cursor position (being maintained). * @return the next boolean value. * @throws IllegalArgumentException if the character sequence from the * specified position is different from "true" or "false" ignoring * cases. */ public static boolean parseBoolean(CharSequence csq, Cursor cursor) { final int i = cursor.getIndex(); if ((csq.length() > i + 4) && (csq.charAt(i) == 't' || csq.charAt(i) == 'T') && (csq.charAt(i + 1) == 'r' || csq.charAt(i + 1) == 'R') && (csq.charAt(i + 2) == 'u' || csq.charAt(i + 2) == 'U') && (csq.charAt(i + 3) == 'e' || csq.charAt(i + 3) == 'E')) { cursor.increment(4); return true; } if ((csq.length() > i + 5) && (csq.charAt(i) == 'f' || csq.charAt(i) == 'F') && (csq.charAt(i + 1) == 'a' || csq.charAt(i + 1) == 'A') && (csq.charAt(i + 2) == 'l' || csq.charAt(i + 2) == 'L') && (csq.charAt(i + 3) == 's' || csq.charAt(i + 3) == 'S') && (csq.charAt(i + 4) == 'e' || csq.charAt(i + 4) == 'E')) { cursor.increment(5); return true; } throw new IllegalArgumentException("Cannot parse boolean at " + cursor.getIndex()); } /** * Parses the specified character sequence as a signed decimal * byte. * * @param csq the character sequence to parse. * @return parseByte(csq, 10) * @throws NumberFormatException if the specified character sequence * does not contain a parsable byte. * @see #parseByte(CharSequence, int) */ public static byte parseByte(CharSequence csq) { return parseByte(csq, 10); } /** * Parses the specified character sequence as a signed byte * in the specified radix. * * @param csq the character sequence to parse. * @param radix the radix to be used while parsing. * @return the corresponding byte. * @throws NumberFormatException if the specified character sequence * does not contain a parsable byte. */ public static byte parseByte(CharSequence csq, int radix) { int i = parseInt(csq, radix); if ((i < Byte.MIN_VALUE) || (i > Byte.MAX_VALUE)) throw new NumberFormatException("Overflow"); return (byte) i; } /** * Parses the specified character sequence from the specified position * as a signed byte in the specified radix. * * @param csq the character sequence to parse. * @param radix the radix to be used while parsing. * @param cursor the current cursor position (being maintained). * @return the corresponding byte. * @throws NumberFormatException if the specified character sequence * does not contain a parsable byte. */ public static byte parseByte(CharSequence csq, int radix, Cursor cursor) { int i = parseInt(csq, radix, cursor); if ((i < Byte.MIN_VALUE) || (i > Byte.MAX_VALUE)) throw new NumberFormatException("Overflow"); return (byte) i; } /** * Parses the specified character sequence as a signed decimal * short. * * @param csq the character sequence to parse. * @return parseShort(csq, 10) * @throws NumberFormatException if the specified character sequence * does not contain a parsable short. * @see #parseShort(CharSequence, int) */ public static short parseShort(CharSequence csq) { return parseShort(csq, 10); } /** * Parses the specified character sequence as a signed short * in the specified radix. * * @param csq 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 csq, int radix) { int i = parseInt(csq, radix); if ((i < Short.MIN_VALUE) || (i > Short.MAX_VALUE)) throw new NumberFormatException("Overflow"); return (short) i; } /** * Parses the specified character sequence from the specified position * as a signed short in the specified radix. * * @param csq the character sequence to parse. * @param radix the radix to be used while parsing. * @param cursor the current cursor position (being maintained). * @return the corresponding short. * @throws NumberFormatException if the specified character sequence * does not contain a parsable short. */ public static short parseShort(CharSequence csq, int radix, Cursor cursor) { int i = parseInt(csq, radix, cursor); if ((i < Short.MIN_VALUE) || (i > Short.MAX_VALUE)) throw new NumberFormatException("Overflow"); return (short) i; } /** * Parses the specified character sequence as a signed int. * * @param csq the character sequence to parse. * @return parseInt(csq, 10) * @throws NumberFormatException if the specified character sequence * does not contain a parsable int. * @see #parseInt(CharSequence, int) */ public static int parseInt(CharSequence csq) { return parseInt(csq, 10); } /** * Parses the specified character sequence as a signed int * in the specified radix. * * @param csq 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 csq, int radix) { try { int length = csq.length(); int i = 0; boolean isNegative = (csq.charAt(i) == '-') ? true : false; i += (isNegative || (csq.charAt(i) == '+')) ? 1 : 0; char c0 = csq.charAt(i); int digit = (c0 < CHAR_TO_DIGIT.length) ? CHAR_TO_DIGIT[c0] : -1; if ((digit < 0) || (digit >= radix)) throw new NumberFormatException("Digit expected"); int result = -digit; // Accumulates negatively. while (true) { if (++i >= length) break; final char c = csq.charAt(i); digit = (c < CHAR_TO_DIGIT.length) ? CHAR_TO_DIGIT[c] : -1; if ((digit < 0) || (digit >= radix)) break; if (result <= Integer.MIN_VALUE / 36) { // Checks for potential overflow. if (result < (Integer.MIN_VALUE + digit) / radix) throw new NumberFormatException("Overflow"); } result = result * radix - digit; } if (!isNegative && (result == Integer.MIN_VALUE)) // Negation overflow. throw new NumberFormatException("Overflow"); return isNegative ? result : -result; } catch (IndexOutOfBoundsException e) { throw new NumberFormatException(); } } /** * Parses the specified character sequence from the specified position * as a signed int in the specified radix. * * @param csq the character sequence to parse. * @param radix the radix to be used while parsing. * @param cursor the current cursor position (being maintained). * @return the corresponding int. * @throws NumberFormatException if the specified character sequence * does not contain a parsable int. */ public static int parseInt(CharSequence csq, int radix, Cursor cursor) { try { int length = csq.length(); int i = cursor.getIndex(); boolean isNegative = (csq.charAt(i) == '-') ? true : false; i += (isNegative || (csq.charAt(i) == '+')) ? 1 : 0; char c0 = csq.charAt(i); int digit = (c0 < CHAR_TO_DIGIT.length) ? CHAR_TO_DIGIT[c0] : -1; if ((digit < 0) || (digit >= radix)) throw new NumberFormatException("Digit expected"); int result = -digit; // Accumulates negatively. while (true) { if (++i >= length) break; final char c = csq.charAt(i); digit = (c < CHAR_TO_DIGIT.length) ? CHAR_TO_DIGIT[c] : -1; if ((digit < 0) || (digit >= radix)) break; if (result <= Integer.MIN_VALUE / 36) { // Checks for potential overflow. if (result < (Integer.MIN_VALUE + digit) / radix) throw new NumberFormatException("Overflow"); } result = result * radix - digit; } if (!isNegative && (result == Integer.MIN_VALUE)) // Negation overflow. throw new NumberFormatException("Overflow"); cursor.setIndex(i); return isNegative ? result : -result; } catch (IndexOutOfBoundsException e) { throw new NumberFormatException(); } } /** * Parses the specified character sequence as a decimal long. * * @param csq the character sequence to parse. * @return parseLong(csq, 10) * @throws NumberFormatException if the specified character sequence * does not contain a parsable long. * @see #parseLong(CharSequence, int) */ public static long parseLong(CharSequence csq) { return parseLong(csq, 10); } /** * Parses the specified character sequence as a signed long * in the specified radix. * * @param csq 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 csq, int radix) { try { int length = csq.length(); int i = 0; boolean isNegative = (csq.charAt(i) == '-') ? true : false; i += (isNegative || (csq.charAt(i) == '+')) ? 1 : 0; char c0 = csq.charAt(i); int digit = (c0 < CHAR_TO_DIGIT.length) ? CHAR_TO_DIGIT[c0] : -1; if ((digit < 0) || (digit >= radix)) throw new NumberFormatException("Digit expected"); long result = -digit; // Accumulates negatively. while (true) { if (++i >= length) break; final char c = csq.charAt(i); digit = (c < CHAR_TO_DIGIT.length) ? CHAR_TO_DIGIT[c] : -1; if ((digit < 0) || (digit >= radix)) break; if (result <= Long.MIN_VALUE / 36) { // Checks for potential overflow. if (result < (Long.MIN_VALUE + digit) / radix) throw new NumberFormatException("Overflow"); } result = result * radix - digit; } if (!isNegative && (result == Long.MIN_VALUE)) // Negation overflow. throw new NumberFormatException("Overflow"); return isNegative ? result : -result; } catch (IndexOutOfBoundsException e) { throw new NumberFormatException(); } } /** * Parses the specified character sequence from the specified position * as a signed long in the specified radix. * * @param csq the character sequence to parse. * @param radix the radix to be used while parsing. * @param cursor the current cursor position (being maintained). * @return the corresponding long. * @throws NumberFormatException if the specified character sequence * does not contain a parsable long. */ public static long parseLong(CharSequence csq, int radix, Cursor cursor) { try { int length = csq.length(); int i = cursor.getIndex(); boolean isNegative = (csq.charAt(i) == '-') ? true : false; i += (isNegative || (csq.charAt(i) == '+')) ? 1 : 0; char c0 = csq.charAt(i); int digit = (c0 < CHAR_TO_DIGIT.length) ? CHAR_TO_DIGIT[c0] : -1; if ((digit < 0) || (digit >= radix)) throw new NumberFormatException("Digit expected"); long result = -digit; // Accumulates negatively. while (true) { if (++i >= length) break; final char c = csq.charAt(i); digit = (c < CHAR_TO_DIGIT.length) ? CHAR_TO_DIGIT[c] : -1; if ((digit < 0) || (digit >= radix)) break; if (result <= Long.MIN_VALUE / 36) { // Checks for potential overflow. if (result < (Long.MIN_VALUE + digit) / radix) throw new NumberFormatException("Overflow"); } result = result * radix - digit; } if (!isNegative && (result == Long.MIN_VALUE)) // Negation overflow. throw new NumberFormatException("Overflow"); cursor.setIndex(i); return isNegative ? result : -result; } catch (IndexOutOfBoundsException e) { throw new NumberFormatException(); } } /** * Parses the specified character sequence as a float. * * @param csq 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 csq) { double d = parseDouble(csq); if ((d >= -Float.MAX_VALUE) && (d <= Float.MAX_VALUE)) { return (float) d; } else { throw new NumberFormatException("Overflow"); } } /**/ /** * Parses the specified character sequence from the specified position * as a float. * * @param csq the character sequence to parse. * @param cursor the current cursor position (being maintained). * @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 csq, Cursor cursor) { double d = parseDouble(csq, cursor); if ((d >= -Float.MAX_VALUE) && (d <= Float.MAX_VALUE)) { return (float) d; } else { throw new NumberFormatException("Overflow"); } } /**/ /** * Parses the specified character sequence as a double. * * @param csq 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 csq) throws NumberFormatException { Cursor cursor = Cursor.newInstance(); double result = TypeFormat.parseDouble(csq, cursor); cursor.recycle(); return result; } /**/ /** * Parses the specified character sequence from the specified position * as a double. * * @param csq the character sequence to parse. * @param cursor the current cursor position (being maintained). * @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 csq, Cursor cursor) throws NumberFormatException { try { int i = cursor.getIndex(); // Reads the sign now (which might not be the sign of the decimal part, e.g. -0.XXX). boolean isNegative = (csq.charAt(i) == '-') ? true : false; i += (isNegative || (csq.charAt(i) == '+')) ? 1 : 0; char c0 = csq.charAt(i); if ((c0 == 'N') && startWith(csq, i, "NaN")) { cursor.setIndex(i + 3); return Double.NaN; } if ((c0 == 'I') && startWith(csq, i, "Infinity")) { cursor.setIndex(i + 8); return isNegative ? Double.NEGATIVE_INFINITY : Double.POSITIVE_INFINITY; } cursor.setIndex(i); long decimal = parseLong(csq, 10, cursor); final int length = csq.length(); // Reads fraction. long fraction = 0; int fractionLength = 0; if (cursor.getIndex() < length) { char c = csq.charAt(cursor.getIndex()); if (c == '.') { cursor.increment(); int startFraction = cursor.getIndex(); fraction = TypeFormat.parseLong(csq, 10, cursor); fractionLength = cursor.getIndex() - startFraction; } } // Reads exponent. int exponent = 0; if (cursor.getIndex() < length) { char c = csq.charAt(cursor.getIndex()); if ((c == 'e') || (c == 'E')) { cursor.increment(); exponent = TypeFormat.parseInt(csq, 10, cursor); } } // Adds decimal and fraction part. double decimalAsDouble = MathLib.toDouble(decimal, exponent); double fractionAsDouble = MathLib.toDouble( decimal < 0 ? -fraction : fraction, exponent - fractionLength); return isNegative ? - decimalAsDouble - fractionAsDouble : decimalAsDouble + fractionAsDouble; } catch (IndexOutOfBoundsException e) { throw new NumberFormatException(); } } /**/ static boolean startWith(CharSequence csq, int start, String str) { for (int i = 0; i < str.length(); i++) { if ((start + i >= csq.length()) || csq.charAt(start + i) != str.charAt(i)) return false; } return true; } /** * Formats the specified boolean and appends the resulting * text to the Appendable argument. * * @param b a boolean. * @param csq the Appendable to append. * @return the specified StringBuffer object. * @throws IOException if an I/O exception occurs. * @see #parseBoolean */ public static Appendable format(boolean b, Appendable csq) throws IOException { return b ? append(csq, "true") : append(csq, "false"); } /** * Formats the specified int and appends the resulting * text (decimal representation) to the Appendable argument. * *

Note: This method is preferred to Appendable.append(int) * as it does not create temporary String * objects (several times faster for small numbers).

* * @param i the int number. * @param csq the Appendable to append. * @return the specified Appendable object. * @throws IOException if an I/O exception occurs. * @see #parseInt */ public static Appendable format(int i, Appendable csq) throws IOException { if (i <= 0) { if (i == Integer.MIN_VALUE) { // Negation would overflow. return append(csq, "-2147483648"); // 11 char max. } else if (i == 0) { return csq.append('0'); } i = -i; csq.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; csq.append(DIGIT_TO_CHAR[digit]); } return csq; } 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 Appendable argument. * * @param i the int number. * @param radix the radix. * @param csq the Appendable to append. * @return the specified Appendable object. * @throws IllegalArgumentException if radix is not in [2 .. 36] range. * @throws IOException if an I/O exception occurs. * @see #parseInt(CharSequence, int) */ public static Appendable format(int i, int radix, Appendable csq) throws IOException { if (radix == 10) { return format(i, csq); // Faster version. } else if (radix < 2 || radix > 36) { throw new IllegalArgumentException("radix: " + radix); } if (i < 0) { csq.append('-'); } else { i = -i; } format2(i, radix, csq); return csq; } private static void format2(int i, int radix, Appendable csq) throws IOException { if (i <= -radix) { format2(i / radix, radix, csq); csq.append(DIGIT_TO_CHAR[-(i % radix)]); } else { csq.append(DIGIT_TO_CHAR[-i]); } } /** * Formats the specified long and appends the resulting * text (decimal representation) to the Appendable argument. * *

Note: This method is preferred to Appendable.append(long) * as it does not create temporary String * objects (several times faster for small numbers).

* * @param l the long number. * @param csq the Appendable to append. * @return the specified Appendable object. * @throws IOException if an I/O exception occurs. * @see #parseLong */ public static Appendable format(long l, Appendable csq) throws IOException { if (l <= 0) { if (l == Long.MIN_VALUE) { // Negation would overflow. return append(csq, "-9223372036854775808"); // 20 characters max. } else if (l == 0) { return csq.append('0'); } l = -l; csq.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; csq.append(DIGIT_TO_CHAR[digit]); } return csq; } 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 Appendable argument. * * @param l the long number. * @param radix the radix. * @param csq the Appendable to append. * @return the specified Appendable object. * @throws IllegalArgumentException if radix is not in [2 .. 36] range. * @throws IOException if an I/O exception occurs. * @see #parseLong(CharSequence, int) */ public static Appendable format(long l, int radix, Appendable csq) throws IOException { if (radix == 10) { return format(l, csq); // Faster version. } else if (radix < 2 || radix > 36) { throw new IllegalArgumentException("radix: " + radix); } if (l < 0) { csq.append('-'); } else { l = -l; } format2(l, radix, csq); return csq; } private static void format2(long l, int radix, Appendable csq) throws IOException { if (l <= -radix) { format2(l / radix, radix, csq); csq.append(DIGIT_TO_CHAR[(int) -(l % radix)]); } else { csq.append(DIGIT_TO_CHAR[(int) -l]); } } /** * Formats the specified float value. * * @param value the float value. * @param csq the Appendable to append. * @return format(value, 10, Math.abs(value) > 1E7, false, sb) * @throws IOException if an I/O exception occurs. * @see #format(double, int , boolean, boolean, Appendable) /**/ public static Appendable format(float value, Appendable csq) throws IOException { return format(value, 10, MathLib.abs(value) > 1E7, false, csq); } /**/ /** * Formats the specified double value. * *

Note : This method is preferred to Double.toString(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 value the double value. * @param csq the Appendable to append. * @return format(value, 17, Math.abs(value) > 1E7, false, sb) * @throws IOException if an I/O exception occurs. * @see #format(double, int , boolean, boolean, Appendable) /**/ public static Appendable format(double value, Appendable csq) throws IOException { return format(value, 17, MathLib.abs(value) > 1E7, false, csq); } /**/ /** * Formats the specified double value according to the * specified formatting arguments. * * @param value the double value. * @param digits the number of significative digits (excludes exponent). * @param scientific true to forces the use of the scientific * notation (e.g. 1.23E3); false * otherwise. * @param showZero true if trailing fractional zeros are * represented; false otherwise. * @param csq the Appendable to append. * @return the specified Appendable object. * @throws IllegalArgumentException if ((digits > 19) || * (digits <= 0))) * @throws IOException if an I/O exception occurs. /**/ public static Appendable format(double value, int digits, boolean scientific, boolean showZero, Appendable csq) throws IOException { if ((digits > 19) || (digits <= 0)) throw new IllegalArgumentException("digits: " + digits); if (value != value) { // NaN return append(csq, "NaN"); } else if (value == POSITIVE_INFINITY) { return append(csq, "Infinity"); } else if (value == NEGATIVE_INFINITY) { return append(csq, "-Infinity"); } else if (value == 0.0) { if (digits == 1) return append(csq, "0"); if (!showZero) return append(csq, "0.0"); append(csq, "0.0"); for (int i = 2; i < digits; i++) { csq.append('0'); } return csq; } if (value < 0) { value = -value; csq.append('-'); } // Find the exponent e such as: value == 0.xxx * 10^e int e = (value >= 1.0) ? 1 + minPow10(value) : - minPow10(1.0 / value); double digitValue = value * MathLib.toDouble(1, digits - e); long mantissa = (long) (digitValue + 0.5); if (scientific || (e <= 0) || (e > digits)) { // Scientific notation has to be used ("x.xxxEyy"). format(mantissa / LONG_POW_10[digits - 1], csq); formatFraction(mantissa % LONG_POW_10[digits - 1], digits - 1, showZero, csq); csq.append('E'); format(e - 1, csq); } else if (e == digits) { // Dot at last position ("xxxxx"). format(mantissa, csq); } else { // Dot within the string ("xxxx.xxxxx"). format(mantissa / LONG_POW_10[digits - e], csq); formatFraction(mantissa % LONG_POW_10[digits - e], digits - e, showZero, csq); } return csq; } private static final double POSITIVE_INFINITY = 1.0 / 0.0; private static final double NEGATIVE_INFINITY = -1.0 / 0.0; private static void formatFraction(long fraction, int digits, boolean showZero, Appendable csq) throws IOException { if (digits == 0) return; csq.append('.'); for (int i = digits; i > 0;) { long pow10 = LONG_POW_10[--i]; int digit = (int) (fraction / pow10); fraction -= digit * pow10; csq.append(DIGIT_TO_CHAR[digit]); if ((fraction == 0) && !showZero) { return; // No more than one trailing zero. } } } // Returns e such as 10^e <= value < 10^(e+1), value >= 1.0 private static int minPow10(double value) { int minE = 0; int maxE = 308; while (maxE - minE > 1) { final int exp = (minE + maxE) >> 1; if (value >= MathLib.toDouble(1, exp)) { minE = exp; } else { maxE = exp; } } return minE; } /**/ /** * Appends the specified string argument to the specified appendable * for backward compatibility when {@link String} was not a * {@link CharSequence}. * * @param to the appendable. * @param str the string to append. * @return the specified appendable * @throws IOException if an I/O exception occurs. */ private static Appendable append(Appendable to, String str) throws IOException { for (int i = 0; i < str.length(); i++) { to.append(str.charAt(i)); } return to; } }

Ads help maintain this website.