11/*
2- * Copyright (c) 2021, 2022 , Oracle and/or its affiliates. All rights reserved.
2+ * Copyright (c) 2021, 2023 , Oracle and/or its affiliates. All rights reserved.
33 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44 *
55 * This code is free software; you can redistribute it and/or modify it
3535/**
3636 * This class exposes a method to render a {@code double} as a string.
3737 */
38- final public class DoubleToDecimal {
38+ public final class DoubleToDecimal {
3939 /*
4040 * For full details about this code see the following references:
4141 *
@@ -110,12 +110,13 @@ final public class DoubleToDecimal {
110110 */
111111 public static final int MAX_CHARS = H + 7 ;
112112
113- private final byte [] bytes = new byte [ MAX_CHARS ] ;
113+ private final byte [] bytes ;
114114
115115 /* Index into bytes of rightmost valid character */
116116 private int index ;
117117
118- private DoubleToDecimal () {
118+ private DoubleToDecimal (boolean noChars ) {
119+ bytes = noChars ? null : new byte [MAX_CHARS ];
119120 }
120121
121122 /**
@@ -127,7 +128,28 @@ private DoubleToDecimal() {
127128 * @see Double#toString(double)
128129 */
129130 public static String toString (double v ) {
130- return new DoubleToDecimal ().toDecimalString (v );
131+ return new DoubleToDecimal (false ).toDecimalString (v );
132+ }
133+
134+ /**
135+ * Splits the decimal <i>d</i> described in
136+ * {@link Double#toString(double)} in integers <i>f</i> and <i>e</i>
137+ * such that <i>d</i> = <i>f</i> 10<sup><i>e</i></sup>.
138+ *
139+ * <p>Further, determines integer <i>n</i> such that <i>n</i> = 0 when
140+ * <i>f</i> = 0, and
141+ * 10<sup><i>n</i>-1</sup> ≤ <i>f</i> < 10<sup><i>n</i></sup>
142+ * otherwise.
143+ *
144+ * <p>The argument {@code v} is assumed to be a positive finite value or
145+ * positive zero.
146+ * Further, {@code fd} must not be {@code null}.
147+ *
148+ * @param v the finite {@code double} to be split.
149+ * @param fd the object that will carry <i>f</i>, <i>e</i>, and <i>n</i>.
150+ */
151+ public static void split (double v , FormattedFPDecimal fd ) {
152+ new DoubleToDecimal (true ).toDecimal (v , fd );
131153 }
132154
133155 /**
@@ -143,11 +165,11 @@ public static String toString(double v) {
143165 */
144166 public static Appendable appendTo (double v , Appendable app )
145167 throws IOException {
146- return new DoubleToDecimal ().appendDecimalTo (v , app );
168+ return new DoubleToDecimal (false ).appendDecimalTo (v , app );
147169 }
148170
149171 private String toDecimalString (double v ) {
150- return switch (toDecimal (v )) {
172+ return switch (toDecimal (v , null )) {
151173 case NON_SPECIAL -> charsToString ();
152174 case PLUS_ZERO -> "0.0" ;
153175 case MINUS_ZERO -> "-0.0" ;
@@ -159,7 +181,7 @@ private String toDecimalString(double v) {
159181
160182 private Appendable appendDecimalTo (double v , Appendable app )
161183 throws IOException {
162- switch (toDecimal (v )) {
184+ switch (toDecimal (v , null )) {
163185 case NON_SPECIAL :
164186 char [] chars = new char [index + 1 ];
165187 for (int i = 0 ; i < chars .length ; ++i ) {
@@ -191,7 +213,7 @@ private Appendable appendDecimalTo(double v, Appendable app)
191213 * MINUS_INF iff v is NEGATIVE_INFINITY
192214 * NAN iff v is NaN
193215 */
194- private int toDecimal (double v ) {
216+ private int toDecimal (double v , FormattedFPDecimal fd ) {
195217 /*
196218 * For full details see references [2] and [1].
197219 *
@@ -207,6 +229,10 @@ private int toDecimal(double v) {
207229 if (bq < BQ_MASK ) {
208230 index = -1 ;
209231 if (bits < 0 ) {
232+ /*
233+ * fd != null implies bytes == null and bits >= 0
234+ * Thus, when fd != null, control never reaches here.
235+ */
210236 append ('-' );
211237 }
212238 if (bq != 0 ) {
@@ -217,16 +243,16 @@ private int toDecimal(double v) {
217243 if (0 < mq & mq < P ) {
218244 long f = c >> mq ;
219245 if (f << mq == c ) {
220- return toChars (f , 0 );
246+ return toChars (f , 0 , fd );
221247 }
222248 }
223- return toDecimal (-mq , c , 0 );
249+ return toDecimal (-mq , c , 0 , fd );
224250 }
225251 if (t != 0 ) {
226252 /* subnormal value */
227253 return t < C_TINY
228- ? toDecimal (Q_MIN , 10 * t , -1 )
229- : toDecimal (Q_MIN , t , 0 );
254+ ? toDecimal (Q_MIN , 10 * t , -1 , fd )
255+ : toDecimal (Q_MIN , t , 0 , fd );
230256 }
231257 return bits == 0 ? PLUS_ZERO : MINUS_ZERO ;
232258 }
@@ -236,7 +262,7 @@ private int toDecimal(double v) {
236262 return bits > 0 ? PLUS_INF : MINUS_INF ;
237263 }
238264
239- private int toDecimal (int q , long c , int dk ) {
265+ private int toDecimal (int q , long c , int dk , FormattedFPDecimal fd ) {
240266 /*
241267 * The skeleton corresponds to figure 7 of [1].
242268 * The efficient computations are those summarized in figure 9.
@@ -301,7 +327,7 @@ private int toDecimal(int q, long c, int dk) {
301327 boolean upin = vbl + out <= sp10 << 2 ;
302328 boolean wpin = (tp10 << 2 ) + out <= vbr ;
303329 if (upin != wpin ) {
304- return toChars (upin ? sp10 : tp10 , k );
330+ return toChars (upin ? sp10 : tp10 , k , fd );
305331 }
306332 }
307333
@@ -316,14 +342,14 @@ private int toDecimal(int q, long c, int dk) {
316342 boolean win = (t << 2 ) + out <= vbr ;
317343 if (uin != win ) {
318344 /* Exactly one of u or w lies in Rv */
319- return toChars (uin ? s : t , k + dk );
345+ return toChars (uin ? s : t , k + dk , fd );
320346 }
321347 /*
322348 * Both u and w lie in Rv: determine the one closest to v.
323349 * See section 9.3 of [1].
324350 */
325351 long cmp = vb - (s + t << 1 );
326- return toChars (cmp < 0 || cmp == 0 && (s & 0x1 ) == 0 ? s : t , k + dk );
352+ return toChars (cmp < 0 || cmp == 0 && (s & 0x1 ) == 0 ? s : t , k + dk , fd );
327353 }
328354
329355 /*
@@ -342,7 +368,7 @@ private static long rop(long g1, long g0, long cp) {
342368 /*
343369 * Formats the decimal f 10^e.
344370 */
345- private int toChars (long f , int e ) {
371+ private int toChars (long f , int e , FormattedFPDecimal fd ) {
346372 /*
347373 * For details not discussed here see section 10 of [1].
348374 *
@@ -353,6 +379,10 @@ private int toChars(long f, int e) {
353379 if (f >= pow10 (len )) {
354380 len += 1 ;
355381 }
382+ if (fd != null ) {
383+ fd .set (f , e , len );
384+ return NON_SPECIAL ;
385+ }
356386
357387 /*
358388 * Let fp and ep be the original f and e, respectively.
0 commit comments