1 /*
2 * SPDX-License-Identifier: BSD-3-Clause
3 *
4 * Copyright © 2022 Keith Packard
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 *
13 * 2. Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials provided
16 * with the distribution.
17 *
18 * 3. Neither the name of the copyright holder nor the names of its
19 * contributors may be used to endorse or promote products derived
20 * from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
27 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
29 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
31 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
33 * OF THE POSSIBILITY OF SUCH DAMAGE.
34 */
35
36 #if __SIZEOF_LONG_DOUBLE__ > __SIZEOF_DOUBLE__
37
38 #define _NEED_IO_LONG_DOUBLE
39
40 #include "dtoa.h"
41
42 int
fcvtl_r(long double invalue,int ndecimal,int * decpt,int * sign,char * buf,size_t len)43 fcvtl_r (long double invalue,
44 int ndecimal,
45 int *decpt,
46 int *sign,
47 char *buf,
48 size_t len)
49 {
50 struct dtoa dtoa;
51 int ntrailing; /* number of zeros to add after the value */
52 int ndigit; /* numer of generated digits */
53 int dtoa_decimal = ndecimal;
54 char *digits = dtoa.digits;
55
56 if (!isfinite(invalue)) {
57 ndigit = 3;
58 ntrailing = 0;
59 *sign = invalue < 0;
60 *decpt = 0;
61 if (isnan(invalue))
62 digits = "nan";
63 else
64 digits = "inf";
65 } else {
66 /* ndecimal = digits after decimal point desired
67 * ndigit = digits actually generated
68 * dtoa.exp = exponent (position of decimal relative to first digit generated)
69 */
70 if (ndecimal < 0)
71 dtoa_decimal = 0;
72 #ifdef _NEED_IO_FLOAT_LARGE
73 ndigit = __ldtoa_engine(invalue, &dtoa, LDTOA_MAX_DIG, true, ndecimal);
74 #elif __SIZEOF_LONG_DOUBLE__ == 8
75 ndigit = __dtoa_engine((FLOAT64) invalue, &dtoa, DTOA_MAX_DIG, true, ndecimal);
76 #elif __SIZEOF_LONG_DOUBLE__ == 4
77 ndigit = __ftoa_engine ((float) invalue, &dtoa, FTOA_MAX_DIG, true, ndecimal);
78 #endif
79 *sign = !!(dtoa.flags & DTOA_MINUS);
80
81 /*
82 * To compute the number of zeros added after the value, there are
83 * three cases:
84 *
85 * 1. all of the generated digits are left of the decimal
86 * point (dtoa.exp >= ndigit). We need (dtoa.exp - ndigit)
87 * digits left of the decimal and ndecimal right of the
88 * decimal: (dtoa.exp - ndigit) + ndecimal
89 *
90 * 2. some of the generated digits are right
91 * of the decimal point (dtoa.exp < ndigit). We need
92 * ndecimal digits total, but we have (ndigit - dtoa.exp)
93 * already, so: ndecimal - (ndigit - dtoa.exp).
94 *
95 * 3. all of the generated digits are right of the decimal point
96 * We need fewer than ndecimal digits by the magnitude of
97 * the exponent (which is negative in this case, so:
98 * ndecimal - (-dtoa.exp - 1) - ndigit
99 *
100 * These all turn out to be the same computation. Kinda cool.
101 */
102 ntrailing = (dtoa.exp + 1 - ndigit) + dtoa_decimal;
103 /*
104 * If this value is negative, then we actually have *no* digits to
105 * generate. In this case, we return the empty string and set the
106 * exponent to the number of digits requested (as they're all
107 * zero)
108 */
109 if (ntrailing < 0) {
110 ntrailing = 0;
111 ndigit = 0;
112
113 /*
114 * Adjust exponent to reflect the desired output of ndecimal
115 * zeros
116 */
117 dtoa.exp = -(dtoa_decimal + 1);
118 }
119 *decpt = dtoa.exp + 1;
120 }
121
122 /* If we can't fit the whole value in the provided space,
123 * return an error
124 */
125 if ((size_t) (ndigit + ntrailing) >= len)
126 return -1;
127
128 /* Value */
129 memcpy(buf, digits, ndigit);
130 buf += ndigit;
131
132 /* Trailing zeros */
133 memset(buf, '0', ntrailing);
134 buf += ntrailing;
135
136 /* Null terminate */
137 buf[0] = '\0';
138 return 0;
139 }
140
141 #elif __SIZEOF_LONG_DOUBLE__ == 4
142
143 #include "stdio_private.h"
144
145 int
fcvtl_r(long double invalue,int ndecimal,int * decpt,int * sign,char * buf,size_t len)146 fcvtl_r (long double invalue,
147 int ndecimal,
148 int *decpt,
149 int *sign,
150 char *buf,
151 size_t len)
152 {
153 return fcvtf_r((float) invalue, ndecimal, decpt, sign, buf, len);
154 }
155
156 #elif __SIZEOF_LONG_DOUBLE__ == __SIZEOF_DOUBLE__
157
158 #include "stdio_private.h"
159
160 int
fcvtl_r(long double invalue,int ndecimal,int * decpt,int * sign,char * buf,size_t len)161 fcvtl_r (long double invalue,
162 int ndecimal,
163 int *decpt,
164 int *sign,
165 char *buf,
166 size_t len)
167 {
168 return fcvt_r((double) invalue, ndecimal, decpt, sign, buf, len);
169 }
170
171 #endif
172