|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
package sun.misc; |
|
|
|
import java.util.Arrays; |
|
|
|
public class FormattedFloatingDecimal{ |
|
|
|
public enum Form { SCIENTIFIC, COMPATIBLE, DECIMAL_FLOAT, GENERAL }; |
|
|
|
|
|
public static FormattedFloatingDecimal valueOf(double d, int precision, Form form){ |
|
FloatingDecimal.BinaryToASCIIConverter fdConverter = |
|
FloatingDecimal.getBinaryToASCIIConverter(d, form == Form.COMPATIBLE); |
|
return new FormattedFloatingDecimal(precision,form, fdConverter); |
|
} |
|
|
|
private int decExponentRounded; |
|
private char[] mantissa; |
|
private char[] exponent; |
|
|
|
private static final ThreadLocal<Object> threadLocalCharBuffer = |
|
new ThreadLocal<Object>() { |
|
@Override |
|
protected Object initialValue() { |
|
return new char[20]; |
|
} |
|
}; |
|
|
|
private static char[] getBuffer(){ |
|
return (char[]) threadLocalCharBuffer.get(); |
|
} |
|
|
|
private FormattedFloatingDecimal(int precision, Form form, FloatingDecimal.BinaryToASCIIConverter fdConverter) { |
|
if (fdConverter.isExceptional()) { |
|
this.mantissa = fdConverter.toJavaFormatString().toCharArray(); |
|
this.exponent = null; |
|
return; |
|
} |
|
char[] digits = getBuffer(); |
|
int nDigits = fdConverter.getDigits(digits); |
|
int decExp = fdConverter.getDecimalExponent(); |
|
int exp; |
|
boolean isNegative = fdConverter.isNegative(); |
|
switch (form) { |
|
case COMPATIBLE: |
|
exp = decExp; |
|
this.decExponentRounded = exp; |
|
fillCompatible(precision, digits, nDigits, exp, isNegative); |
|
break; |
|
case DECIMAL_FLOAT: |
|
exp = applyPrecision(decExp, digits, nDigits, decExp + precision); |
|
fillDecimal(precision, digits, nDigits, exp, isNegative); |
|
this.decExponentRounded = exp; |
|
break; |
|
case SCIENTIFIC: |
|
exp = applyPrecision(decExp, digits, nDigits, precision + 1); |
|
fillScientific(precision, digits, nDigits, exp, isNegative); |
|
this.decExponentRounded = exp; |
|
break; |
|
case GENERAL: |
|
exp = applyPrecision(decExp, digits, nDigits, precision); |
|
// adjust precision to be the number of digits to right of decimal |
|
|
|
if (exp - 1 < -4 || exp - 1 >= precision) { |
|
|
|
precision--; |
|
fillScientific(precision, digits, nDigits, exp, isNegative); |
|
} else { |
|
|
|
precision = precision - exp; |
|
fillDecimal(precision, digits, nDigits, exp, isNegative); |
|
} |
|
this.decExponentRounded = exp; |
|
break; |
|
default: |
|
assert false; |
|
} |
|
} |
|
|
|
|
|
public int getExponentRounded() { |
|
return decExponentRounded - 1; |
|
} |
|
|
|
public char[] getMantissa(){ |
|
return mantissa; |
|
} |
|
|
|
public char[] getExponent(){ |
|
return exponent; |
|
} |
|
|
|
|
|
|
|
*/ |
|
private static int applyPrecision(int decExp, char[] digits, int nDigits, int prec) { |
|
if (prec >= nDigits || prec < 0) { |
|
|
|
return decExp; |
|
} |
|
if (prec == 0) { |
|
// only one digit (0 or 1) is returned because the precision |
|
|
|
if (digits[0] >= '5') { |
|
digits[0] = '1'; |
|
Arrays.fill(digits, 1, nDigits, '0'); |
|
return decExp + 1; |
|
} else { |
|
Arrays.fill(digits, 0, nDigits, '0'); |
|
return decExp; |
|
} |
|
} |
|
int q = digits[prec]; |
|
if (q >= '5') { |
|
int i = prec; |
|
q = digits[--i]; |
|
if ( q == '9' ) { |
|
while ( q == '9' && i > 0 ){ |
|
q = digits[--i]; |
|
} |
|
if ( q == '9' ){ |
|
|
|
digits[0] = '1'; |
|
Arrays.fill(digits, 1, nDigits, '0'); |
|
return decExp+1; |
|
} |
|
} |
|
digits[i] = (char)(q + 1); |
|
Arrays.fill(digits, i+1, nDigits, '0'); |
|
} else { |
|
Arrays.fill(digits, prec, nDigits, '0'); |
|
} |
|
return decExp; |
|
} |
|
|
|
|
|
|
|
*/ |
|
private void fillCompatible(int precision, char[] digits, int nDigits, int exp, boolean isNegative) { |
|
int startIndex = isNegative ? 1 : 0; |
|
if (exp > 0 && exp < 8) { |
|
|
|
if (nDigits < exp) { |
|
int extraZeros = exp - nDigits; |
|
mantissa = create(isNegative, nDigits + extraZeros + 2); |
|
System.arraycopy(digits, 0, mantissa, startIndex, nDigits); |
|
Arrays.fill(mantissa, startIndex + nDigits, startIndex + nDigits + extraZeros, '0'); |
|
mantissa[startIndex + nDigits + extraZeros] = '.'; |
|
mantissa[startIndex + nDigits + extraZeros+1] = '0'; |
|
} else if (exp < nDigits) { |
|
int t = Math.min(nDigits - exp, precision); |
|
mantissa = create(isNegative, exp + 1 + t); |
|
System.arraycopy(digits, 0, mantissa, startIndex, exp); |
|
mantissa[startIndex + exp ] = '.'; |
|
System.arraycopy(digits, exp, mantissa, startIndex+exp+1, t); |
|
} else { |
|
mantissa = create(isNegative, nDigits + 2); |
|
System.arraycopy(digits, 0, mantissa, startIndex, nDigits); |
|
mantissa[startIndex + nDigits ] = '.'; |
|
mantissa[startIndex + nDigits +1] = '0'; |
|
} |
|
} else if (exp <= 0 && exp > -3) { |
|
int zeros = Math.max(0, Math.min(-exp, precision)); |
|
int t = Math.max(0, Math.min(nDigits, precision + exp)); |
|
|
|
if (zeros > 0) { |
|
mantissa = create(isNegative, zeros + 2 + t); |
|
mantissa[startIndex] = '0'; |
|
mantissa[startIndex+1] = '.'; |
|
Arrays.fill(mantissa, startIndex + 2, startIndex + 2 + zeros, '0'); |
|
if (t > 0) { |
|
|
|
System.arraycopy(digits, 0, mantissa, startIndex + 2 + zeros, t); |
|
} |
|
} else if (t > 0) { |
|
mantissa = create(isNegative, zeros + 2 + t); |
|
mantissa[startIndex] = '0'; |
|
mantissa[startIndex + 1] = '.'; |
|
|
|
System.arraycopy(digits, 0, mantissa, startIndex + 2, t); |
|
} else { |
|
this.mantissa = create(isNegative, 1); |
|
this.mantissa[startIndex] = '0'; |
|
} |
|
} else { |
|
if (nDigits > 1) { |
|
mantissa = create(isNegative, nDigits + 1); |
|
mantissa[startIndex] = digits[0]; |
|
mantissa[startIndex + 1] = '.'; |
|
System.arraycopy(digits, 1, mantissa, startIndex + 2, nDigits - 1); |
|
} else { |
|
mantissa = create(isNegative, 3); |
|
mantissa[startIndex] = digits[0]; |
|
mantissa[startIndex + 1] = '.'; |
|
mantissa[startIndex + 2] = '0'; |
|
} |
|
int e, expStartIntex; |
|
boolean isNegExp = (exp <= 0); |
|
if (isNegExp) { |
|
e = -exp + 1; |
|
expStartIntex = 1; |
|
} else { |
|
e = exp - 1; |
|
expStartIntex = 0; |
|
} |
|
|
|
if (e <= 9) { |
|
exponent = create(isNegExp,1); |
|
exponent[expStartIntex] = (char) (e + '0'); |
|
} else if (e <= 99) { |
|
exponent = create(isNegExp,2); |
|
exponent[expStartIntex] = (char) (e / 10 + '0'); |
|
exponent[expStartIntex+1] = (char) (e % 10 + '0'); |
|
} else { |
|
exponent = create(isNegExp,3); |
|
exponent[expStartIntex] = (char) (e / 100 + '0'); |
|
e %= 100; |
|
exponent[expStartIntex+1] = (char) (e / 10 + '0'); |
|
exponent[expStartIntex+2] = (char) (e % 10 + '0'); |
|
} |
|
} |
|
} |
|
|
|
private static char[] create(boolean isNegative, int size) { |
|
if(isNegative) { |
|
char[] r = new char[size +1]; |
|
r[0] = '-'; |
|
return r; |
|
} else { |
|
return new char[size]; |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
private void fillDecimal(int precision, char[] digits, int nDigits, int exp, boolean isNegative) { |
|
int startIndex = isNegative ? 1 : 0; |
|
if (exp > 0) { |
|
|
|
if (nDigits < exp) { |
|
mantissa = create(isNegative,exp); |
|
System.arraycopy(digits, 0, mantissa, startIndex, nDigits); |
|
Arrays.fill(mantissa, startIndex + nDigits, startIndex + exp, '0'); |
|
// Do not append ".0" for formatted floats since the user |
|
// may request that it be omitted. It is added as necessary |
|
// by the Formatter. |
|
} else { |
|
int t = Math.min(nDigits - exp, precision); |
|
mantissa = create(isNegative, exp + (t > 0 ? (t + 1) : 0)); |
|
System.arraycopy(digits, 0, mantissa, startIndex, exp); |
|
// Do not append ".0" for formatted floats since the user |
|
// may request that it be omitted. It is added as necessary |
|
|
|
if (t > 0) { |
|
mantissa[startIndex + exp] = '.'; |
|
System.arraycopy(digits, exp, mantissa, startIndex + exp + 1, t); |
|
} |
|
} |
|
} else if (exp <= 0) { |
|
int zeros = Math.max(0, Math.min(-exp, precision)); |
|
int t = Math.max(0, Math.min(nDigits, precision + exp)); |
|
|
|
if (zeros > 0) { |
|
mantissa = create(isNegative, zeros + 2 + t); |
|
mantissa[startIndex] = '0'; |
|
mantissa[startIndex+1] = '.'; |
|
Arrays.fill(mantissa, startIndex + 2, startIndex + 2 + zeros, '0'); |
|
if (t > 0) { |
|
|
|
System.arraycopy(digits, 0, mantissa, startIndex + 2 + zeros, t); |
|
} |
|
} else if (t > 0) { |
|
mantissa = create(isNegative, zeros + 2 + t); |
|
mantissa[startIndex] = '0'; |
|
mantissa[startIndex + 1] = '.'; |
|
|
|
System.arraycopy(digits, 0, mantissa, startIndex + 2, t); |
|
} else { |
|
this.mantissa = create(isNegative, 1); |
|
this.mantissa[startIndex] = '0'; |
|
} |
|
} |
|
} |
|
|
|
|
|
|
|
*/ |
|
private void fillScientific(int precision, char[] digits, int nDigits, int exp, boolean isNegative) { |
|
int startIndex = isNegative ? 1 : 0; |
|
int t = Math.max(0, Math.min(nDigits - 1, precision)); |
|
if (t > 0) { |
|
mantissa = create(isNegative, t + 2); |
|
mantissa[startIndex] = digits[0]; |
|
mantissa[startIndex + 1] = '.'; |
|
System.arraycopy(digits, 1, mantissa, startIndex + 2, t); |
|
} else { |
|
mantissa = create(isNegative, 1); |
|
mantissa[startIndex] = digits[0]; |
|
} |
|
char expSign; |
|
int e; |
|
if (exp <= 0) { |
|
expSign = '-'; |
|
e = -exp + 1; |
|
} else { |
|
expSign = '+' ; |
|
e = exp - 1; |
|
} |
|
|
|
if (e <= 9) { |
|
exponent = new char[] { expSign, |
|
'0', (char) (e + '0') }; |
|
} else if (e <= 99) { |
|
exponent = new char[] { expSign, |
|
(char) (e / 10 + '0'), (char) (e % 10 + '0') }; |
|
} else { |
|
char hiExpChar = (char) (e / 100 + '0'); |
|
e %= 100; |
|
exponent = new char[] { expSign, |
|
hiExpChar, (char) (e / 10 + '0'), (char) (e % 10 + '0') }; |
|
} |
|
} |
|
} |