Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.base/share/classes/jdk/internal/math/FormattedFloatingDecimal.java
41159 views
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 jdk.internal.math;
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
/**
110
* Returns the mantissa as a {@code char[]}. Note that the returned value
111
* is a reference to the internal {@code char[]} containing the mantissa,
112
* therefore code invoking this method should not pass the return value to
113
* external code but should in that case make a copy.
114
*
115
* @return a reference to the internal {@code char[]} representing the
116
* mantissa.
117
*/
118
public char[] getMantissa(){
119
return mantissa;
120
}
121
122
/**
123
* Returns the exponent as a {@code char[]}. Note that the returned value
124
* is a reference to the internal {@code char[]} containing the exponent,
125
* therefore code invoking this method should not pass the return value to
126
* external code but should in that case make a copy.
127
*
128
* @return a reference to the internal {@code char[]} representing the
129
* exponent.
130
*/
131
public char[] getExponent(){
132
return exponent;
133
}
134
135
/**
136
* Returns new decExp in case of overflow.
137
*/
138
private static int applyPrecision(int decExp, char[] digits, int nDigits, int prec) {
139
if (prec >= nDigits || prec < 0) {
140
// no rounding necessary
141
return decExp;
142
}
143
if (prec == 0) {
144
// only one digit (0 or 1) is returned because the precision
145
// excludes all significant digits
146
if (digits[0] >= '5') {
147
digits[0] = '1';
148
Arrays.fill(digits, 1, nDigits, '0');
149
return decExp + 1;
150
} else {
151
Arrays.fill(digits, 0, nDigits, '0');
152
return decExp;
153
}
154
}
155
int q = digits[prec];
156
if (q >= '5') {
157
int i = prec;
158
q = digits[--i];
159
if ( q == '9' ) {
160
while ( q == '9' && i > 0 ){
161
q = digits[--i];
162
}
163
if ( q == '9' ){
164
// carryout! High-order 1, rest 0s, larger exp.
165
digits[0] = '1';
166
Arrays.fill(digits, 1, nDigits, '0');
167
return decExp+1;
168
}
169
}
170
digits[i] = (char)(q + 1);
171
Arrays.fill(digits, i+1, nDigits, '0');
172
} else {
173
Arrays.fill(digits, prec, nDigits, '0');
174
}
175
return decExp;
176
}
177
178
/**
179
* Fills mantissa and exponent char arrays for compatible format.
180
*/
181
private void fillCompatible(int precision, char[] digits, int nDigits, int exp, boolean isNegative) {
182
int startIndex = isNegative ? 1 : 0;
183
if (exp > 0 && exp < 8) {
184
// print digits.digits.
185
if (nDigits < exp) {
186
int extraZeros = exp - nDigits;
187
mantissa = create(isNegative, nDigits + extraZeros + 2);
188
System.arraycopy(digits, 0, mantissa, startIndex, nDigits);
189
Arrays.fill(mantissa, startIndex + nDigits, startIndex + nDigits + extraZeros, '0');
190
mantissa[startIndex + nDigits + extraZeros] = '.';
191
mantissa[startIndex + nDigits + extraZeros+1] = '0';
192
} else if (exp < nDigits) {
193
int t = Math.min(nDigits - exp, precision);
194
mantissa = create(isNegative, exp + 1 + t);
195
System.arraycopy(digits, 0, mantissa, startIndex, exp);
196
mantissa[startIndex + exp ] = '.';
197
System.arraycopy(digits, exp, mantissa, startIndex+exp+1, t);
198
} else { // exp == digits.length
199
mantissa = create(isNegative, nDigits + 2);
200
System.arraycopy(digits, 0, mantissa, startIndex, nDigits);
201
mantissa[startIndex + nDigits ] = '.';
202
mantissa[startIndex + nDigits +1] = '0';
203
}
204
} else if (exp <= 0 && exp > -3) {
205
int zeros = Math.max(0, Math.min(-exp, precision));
206
int t = Math.max(0, Math.min(nDigits, precision + exp));
207
// write '0' s before the significant digits
208
if (zeros > 0) {
209
mantissa = create(isNegative, zeros + 2 + t);
210
mantissa[startIndex] = '0';
211
mantissa[startIndex+1] = '.';
212
Arrays.fill(mantissa, startIndex + 2, startIndex + 2 + zeros, '0');
213
if (t > 0) {
214
// copy only when significant digits are within the precision
215
System.arraycopy(digits, 0, mantissa, startIndex + 2 + zeros, t);
216
}
217
} else if (t > 0) {
218
mantissa = create(isNegative, zeros + 2 + t);
219
mantissa[startIndex] = '0';
220
mantissa[startIndex + 1] = '.';
221
// copy only when significant digits are within the precision
222
System.arraycopy(digits, 0, mantissa, startIndex + 2, t);
223
} else {
224
this.mantissa = create(isNegative, 1);
225
this.mantissa[startIndex] = '0';
226
}
227
} else {
228
if (nDigits > 1) {
229
mantissa = create(isNegative, nDigits + 1);
230
mantissa[startIndex] = digits[0];
231
mantissa[startIndex + 1] = '.';
232
System.arraycopy(digits, 1, mantissa, startIndex + 2, nDigits - 1);
233
} else {
234
mantissa = create(isNegative, 3);
235
mantissa[startIndex] = digits[0];
236
mantissa[startIndex + 1] = '.';
237
mantissa[startIndex + 2] = '0';
238
}
239
int e, expStartIntex;
240
boolean isNegExp = (exp <= 0);
241
if (isNegExp) {
242
e = -exp + 1;
243
expStartIntex = 1;
244
} else {
245
e = exp - 1;
246
expStartIntex = 0;
247
}
248
// decExponent has 1, 2, or 3, digits
249
if (e <= 9) {
250
exponent = create(isNegExp,1);
251
exponent[expStartIntex] = (char) (e + '0');
252
} else if (e <= 99) {
253
exponent = create(isNegExp,2);
254
exponent[expStartIntex] = (char) (e / 10 + '0');
255
exponent[expStartIntex+1] = (char) (e % 10 + '0');
256
} else {
257
exponent = create(isNegExp,3);
258
exponent[expStartIntex] = (char) (e / 100 + '0');
259
e %= 100;
260
exponent[expStartIntex+1] = (char) (e / 10 + '0');
261
exponent[expStartIntex+2] = (char) (e % 10 + '0');
262
}
263
}
264
}
265
266
private static char[] create(boolean isNegative, int size) {
267
if(isNegative) {
268
char[] r = new char[size +1];
269
r[0] = '-';
270
return r;
271
} else {
272
return new char[size];
273
}
274
}
275
276
/*
277
* Fills mantissa char arrays for DECIMAL_FLOAT format.
278
* Exponent should be equal to null.
279
*/
280
private void fillDecimal(int precision, char[] digits, int nDigits, int exp, boolean isNegative) {
281
int startIndex = isNegative ? 1 : 0;
282
if (exp > 0) {
283
// print digits.digits.
284
if (nDigits < exp) {
285
mantissa = create(isNegative,exp);
286
System.arraycopy(digits, 0, mantissa, startIndex, nDigits);
287
Arrays.fill(mantissa, startIndex + nDigits, startIndex + exp, '0');
288
// Do not append ".0" for formatted floats since the user
289
// may request that it be omitted. It is added as necessary
290
// by the Formatter.
291
} else {
292
int t = Math.min(nDigits - exp, precision);
293
mantissa = create(isNegative, exp + (t > 0 ? (t + 1) : 0));
294
System.arraycopy(digits, 0, mantissa, startIndex, exp);
295
// Do not append ".0" for formatted floats since the user
296
// may request that it be omitted. It is added as necessary
297
// by the Formatter.
298
if (t > 0) {
299
mantissa[startIndex + exp] = '.';
300
System.arraycopy(digits, exp, mantissa, startIndex + exp + 1, t);
301
}
302
}
303
} else if (exp <= 0) {
304
int zeros = Math.max(0, Math.min(-exp, precision));
305
int t = Math.max(0, Math.min(nDigits, precision + exp));
306
// write '0' s before the significant digits
307
if (zeros > 0) {
308
mantissa = create(isNegative, zeros + 2 + t);
309
mantissa[startIndex] = '0';
310
mantissa[startIndex+1] = '.';
311
Arrays.fill(mantissa, startIndex + 2, startIndex + 2 + zeros, '0');
312
if (t > 0) {
313
// copy only when significant digits are within the precision
314
System.arraycopy(digits, 0, mantissa, startIndex + 2 + zeros, t);
315
}
316
} else if (t > 0) {
317
mantissa = create(isNegative, zeros + 2 + t);
318
mantissa[startIndex] = '0';
319
mantissa[startIndex + 1] = '.';
320
// copy only when significant digits are within the precision
321
System.arraycopy(digits, 0, mantissa, startIndex + 2, t);
322
} else {
323
this.mantissa = create(isNegative, 1);
324
this.mantissa[startIndex] = '0';
325
}
326
}
327
}
328
329
/**
330
* Fills mantissa and exponent char arrays for SCIENTIFIC format.
331
*/
332
private void fillScientific(int precision, char[] digits, int nDigits, int exp, boolean isNegative) {
333
int startIndex = isNegative ? 1 : 0;
334
int t = Math.max(0, Math.min(nDigits - 1, precision));
335
if (t > 0) {
336
mantissa = create(isNegative, t + 2);
337
mantissa[startIndex] = digits[0];
338
mantissa[startIndex + 1] = '.';
339
System.arraycopy(digits, 1, mantissa, startIndex + 2, t);
340
} else {
341
mantissa = create(isNegative, 1);
342
mantissa[startIndex] = digits[0];
343
}
344
char expSign;
345
int e;
346
if (exp <= 0) {
347
expSign = '-';
348
e = -exp + 1;
349
} else {
350
expSign = '+' ;
351
e = exp - 1;
352
}
353
// decExponent has 1, 2, or 3, digits
354
if (e <= 9) {
355
exponent = new char[] { expSign,
356
'0', (char) (e + '0') };
357
} else if (e <= 99) {
358
exponent = new char[] { expSign,
359
(char) (e / 10 + '0'), (char) (e % 10 + '0') };
360
} else {
361
char hiExpChar = (char) (e / 100 + '0');
362
e %= 100;
363
exponent = new char[] { expSign,
364
hiExpChar, (char) (e / 10 + '0'), (char) (e % 10 + '0') };
365
}
366
}
367
}
368
369