Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/misc/FormattedFloatingDecimal.java
38829 views
/*1* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.misc;2627import java.util.Arrays;2829public class FormattedFloatingDecimal{3031public enum Form { SCIENTIFIC, COMPATIBLE, DECIMAL_FLOAT, GENERAL };323334public static FormattedFloatingDecimal valueOf(double d, int precision, Form form){35FloatingDecimal.BinaryToASCIIConverter fdConverter =36FloatingDecimal.getBinaryToASCIIConverter(d, form == Form.COMPATIBLE);37return new FormattedFloatingDecimal(precision,form, fdConverter);38}3940private int decExponentRounded;41private char[] mantissa;42private char[] exponent;4344private static final ThreadLocal<Object> threadLocalCharBuffer =45new ThreadLocal<Object>() {46@Override47protected Object initialValue() {48return new char[20];49}50};5152private static char[] getBuffer(){53return (char[]) threadLocalCharBuffer.get();54}5556private FormattedFloatingDecimal(int precision, Form form, FloatingDecimal.BinaryToASCIIConverter fdConverter) {57if (fdConverter.isExceptional()) {58this.mantissa = fdConverter.toJavaFormatString().toCharArray();59this.exponent = null;60return;61}62char[] digits = getBuffer();63int nDigits = fdConverter.getDigits(digits);64int decExp = fdConverter.getDecimalExponent();65int exp;66boolean isNegative = fdConverter.isNegative();67switch (form) {68case COMPATIBLE:69exp = decExp;70this.decExponentRounded = exp;71fillCompatible(precision, digits, nDigits, exp, isNegative);72break;73case DECIMAL_FLOAT:74exp = applyPrecision(decExp, digits, nDigits, decExp + precision);75fillDecimal(precision, digits, nDigits, exp, isNegative);76this.decExponentRounded = exp;77break;78case SCIENTIFIC:79exp = applyPrecision(decExp, digits, nDigits, precision + 1);80fillScientific(precision, digits, nDigits, exp, isNegative);81this.decExponentRounded = exp;82break;83case GENERAL:84exp = applyPrecision(decExp, digits, nDigits, precision);85// adjust precision to be the number of digits to right of decimal86// the real exponent to be output is actually exp - 1, not exp87if (exp - 1 < -4 || exp - 1 >= precision) {88// form = Form.SCIENTIFIC;89precision--;90fillScientific(precision, digits, nDigits, exp, isNegative);91} else {92// form = Form.DECIMAL_FLOAT;93precision = precision - exp;94fillDecimal(precision, digits, nDigits, exp, isNegative);95}96this.decExponentRounded = exp;97break;98default:99assert false;100}101}102103// returns the exponent after rounding has been done by applyPrecision104public int getExponentRounded() {105return decExponentRounded - 1;106}107108public char[] getMantissa(){109return mantissa;110}111112public char[] getExponent(){113return exponent;114}115116/**117* Returns new decExp in case of overflow.118*/119private static int applyPrecision(int decExp, char[] digits, int nDigits, int prec) {120if (prec >= nDigits || prec < 0) {121// no rounding necessary122return decExp;123}124if (prec == 0) {125// only one digit (0 or 1) is returned because the precision126// excludes all significant digits127if (digits[0] >= '5') {128digits[0] = '1';129Arrays.fill(digits, 1, nDigits, '0');130return decExp + 1;131} else {132Arrays.fill(digits, 0, nDigits, '0');133return decExp;134}135}136int q = digits[prec];137if (q >= '5') {138int i = prec;139q = digits[--i];140if ( q == '9' ) {141while ( q == '9' && i > 0 ){142q = digits[--i];143}144if ( q == '9' ){145// carryout! High-order 1, rest 0s, larger exp.146digits[0] = '1';147Arrays.fill(digits, 1, nDigits, '0');148return decExp+1;149}150}151digits[i] = (char)(q + 1);152Arrays.fill(digits, i+1, nDigits, '0');153} else {154Arrays.fill(digits, prec, nDigits, '0');155}156return decExp;157}158159/**160* Fills mantissa and exponent char arrays for compatible format.161*/162private void fillCompatible(int precision, char[] digits, int nDigits, int exp, boolean isNegative) {163int startIndex = isNegative ? 1 : 0;164if (exp > 0 && exp < 8) {165// print digits.digits.166if (nDigits < exp) {167int extraZeros = exp - nDigits;168mantissa = create(isNegative, nDigits + extraZeros + 2);169System.arraycopy(digits, 0, mantissa, startIndex, nDigits);170Arrays.fill(mantissa, startIndex + nDigits, startIndex + nDigits + extraZeros, '0');171mantissa[startIndex + nDigits + extraZeros] = '.';172mantissa[startIndex + nDigits + extraZeros+1] = '0';173} else if (exp < nDigits) {174int t = Math.min(nDigits - exp, precision);175mantissa = create(isNegative, exp + 1 + t);176System.arraycopy(digits, 0, mantissa, startIndex, exp);177mantissa[startIndex + exp ] = '.';178System.arraycopy(digits, exp, mantissa, startIndex+exp+1, t);179} else { // exp == digits.length180mantissa = create(isNegative, nDigits + 2);181System.arraycopy(digits, 0, mantissa, startIndex, nDigits);182mantissa[startIndex + nDigits ] = '.';183mantissa[startIndex + nDigits +1] = '0';184}185} else if (exp <= 0 && exp > -3) {186int zeros = Math.max(0, Math.min(-exp, precision));187int t = Math.max(0, Math.min(nDigits, precision + exp));188// write '0' s before the significant digits189if (zeros > 0) {190mantissa = create(isNegative, zeros + 2 + t);191mantissa[startIndex] = '0';192mantissa[startIndex+1] = '.';193Arrays.fill(mantissa, startIndex + 2, startIndex + 2 + zeros, '0');194if (t > 0) {195// copy only when significant digits are within the precision196System.arraycopy(digits, 0, mantissa, startIndex + 2 + zeros, t);197}198} else if (t > 0) {199mantissa = create(isNegative, zeros + 2 + t);200mantissa[startIndex] = '0';201mantissa[startIndex + 1] = '.';202// copy only when significant digits are within the precision203System.arraycopy(digits, 0, mantissa, startIndex + 2, t);204} else {205this.mantissa = create(isNegative, 1);206this.mantissa[startIndex] = '0';207}208} else {209if (nDigits > 1) {210mantissa = create(isNegative, nDigits + 1);211mantissa[startIndex] = digits[0];212mantissa[startIndex + 1] = '.';213System.arraycopy(digits, 1, mantissa, startIndex + 2, nDigits - 1);214} else {215mantissa = create(isNegative, 3);216mantissa[startIndex] = digits[0];217mantissa[startIndex + 1] = '.';218mantissa[startIndex + 2] = '0';219}220int e, expStartIntex;221boolean isNegExp = (exp <= 0);222if (isNegExp) {223e = -exp + 1;224expStartIntex = 1;225} else {226e = exp - 1;227expStartIntex = 0;228}229// decExponent has 1, 2, or 3, digits230if (e <= 9) {231exponent = create(isNegExp,1);232exponent[expStartIntex] = (char) (e + '0');233} else if (e <= 99) {234exponent = create(isNegExp,2);235exponent[expStartIntex] = (char) (e / 10 + '0');236exponent[expStartIntex+1] = (char) (e % 10 + '0');237} else {238exponent = create(isNegExp,3);239exponent[expStartIntex] = (char) (e / 100 + '0');240e %= 100;241exponent[expStartIntex+1] = (char) (e / 10 + '0');242exponent[expStartIntex+2] = (char) (e % 10 + '0');243}244}245}246247private static char[] create(boolean isNegative, int size) {248if(isNegative) {249char[] r = new char[size +1];250r[0] = '-';251return r;252} else {253return new char[size];254}255}256257/*258* Fills mantissa char arrays for DECIMAL_FLOAT format.259* Exponent should be equal to null.260*/261private void fillDecimal(int precision, char[] digits, int nDigits, int exp, boolean isNegative) {262int startIndex = isNegative ? 1 : 0;263if (exp > 0) {264// print digits.digits.265if (nDigits < exp) {266mantissa = create(isNegative,exp);267System.arraycopy(digits, 0, mantissa, startIndex, nDigits);268Arrays.fill(mantissa, startIndex + nDigits, startIndex + exp, '0');269// Do not append ".0" for formatted floats since the user270// may request that it be omitted. It is added as necessary271// by the Formatter.272} else {273int t = Math.min(nDigits - exp, precision);274mantissa = create(isNegative, exp + (t > 0 ? (t + 1) : 0));275System.arraycopy(digits, 0, mantissa, startIndex, exp);276// Do not append ".0" for formatted floats since the user277// may request that it be omitted. It is added as necessary278// by the Formatter.279if (t > 0) {280mantissa[startIndex + exp] = '.';281System.arraycopy(digits, exp, mantissa, startIndex + exp + 1, t);282}283}284} else if (exp <= 0) {285int zeros = Math.max(0, Math.min(-exp, precision));286int t = Math.max(0, Math.min(nDigits, precision + exp));287// write '0' s before the significant digits288if (zeros > 0) {289mantissa = create(isNegative, zeros + 2 + t);290mantissa[startIndex] = '0';291mantissa[startIndex+1] = '.';292Arrays.fill(mantissa, startIndex + 2, startIndex + 2 + zeros, '0');293if (t > 0) {294// copy only when significant digits are within the precision295System.arraycopy(digits, 0, mantissa, startIndex + 2 + zeros, t);296}297} else if (t > 0) {298mantissa = create(isNegative, zeros + 2 + t);299mantissa[startIndex] = '0';300mantissa[startIndex + 1] = '.';301// copy only when significant digits are within the precision302System.arraycopy(digits, 0, mantissa, startIndex + 2, t);303} else {304this.mantissa = create(isNegative, 1);305this.mantissa[startIndex] = '0';306}307}308}309310/**311* Fills mantissa and exponent char arrays for SCIENTIFIC format.312*/313private void fillScientific(int precision, char[] digits, int nDigits, int exp, boolean isNegative) {314int startIndex = isNegative ? 1 : 0;315int t = Math.max(0, Math.min(nDigits - 1, precision));316if (t > 0) {317mantissa = create(isNegative, t + 2);318mantissa[startIndex] = digits[0];319mantissa[startIndex + 1] = '.';320System.arraycopy(digits, 1, mantissa, startIndex + 2, t);321} else {322mantissa = create(isNegative, 1);323mantissa[startIndex] = digits[0];324}325char expSign;326int e;327if (exp <= 0) {328expSign = '-';329e = -exp + 1;330} else {331expSign = '+' ;332e = exp - 1;333}334// decExponent has 1, 2, or 3, digits335if (e <= 9) {336exponent = new char[] { expSign,337'0', (char) (e + '0') };338} else if (e <= 99) {339exponent = new char[] { expSign,340(char) (e / 10 + '0'), (char) (e % 10 + '0') };341} else {342char hiExpChar = (char) (e / 100 + '0');343e %= 100;344exponent = new char[] { expSign,345hiExpChar, (char) (e / 10 + '0'), (char) (e % 10 + '0') };346}347}348}349350351