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