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 #define _GNU_SOURCE
37 #include <stdlib.h>
38 #include <stdio.h>
39 #include <string.h>
40
41 struct test {
42 double value;
43 int ndigit;
44 int decpt;
45 int sign;
46 char *expect;
47 };
48
49 const struct test ecvt_tests[] = {
50 { 1.0e0, 4, 1, 0, "1000", },
51 { -1.0e0, 4, 1, 1, "1000", },
52 { 1.0e7, 7, 8, 0, "1000000" },
53 { 1.0e-12, 4, -11, 0, "1000" },
54 };
55
56 #pragma GCC diagnostic ignored "-Wpragmas"
57 #pragma GCC diagnostic ignored "-Wunknown-warning-option"
58 #pragma GCC diagnostic ignored "-Wunused-value"
59 #pragma GCC diagnostic ignored "-Woverflow"
60 #pragma GCC diagnostic ignored "-Wliteral-range"
61
62 #if !defined(TINY_STDIO) && !defined(NO_NEWLIB)
63 #define ecvt_r(n, dig, dec, sign, buf, len) (ecvtbuf(n, dig, dec, sign, buf) ? 0 : -1)
64 #define fcvt_r(n, dig, dec, sign, buf, len) (fcvtbuf(n, dig, dec, sign, buf) ? 0 : -1)
65 #define ecvtf_r(n, dig, dec, sign, buf, len) (ecvtbuf(n, dig, dec, sign, buf) ? 0 : -1)
66 #define fcvtf_r(n, dig, dec, sign, buf, len) (fcvtbuf(n, dig, dec, sign, buf) ? 0 : -1)
67 #define SKIP_FCVT_NEG
68 #endif
69
70 #define N_ECVT_TESTS (sizeof(ecvt_tests) / sizeof(ecvt_tests[0]))
71
72 const struct test fcvt_tests[] = {
73 { 0.0058882729652625027, 7, -2, 0, "58883", },
74 { 1.0e0, 4, 1, 0, "10000", },
75 { -1.0e0, 4, 1, 1, "10000", },
76 { 1.0e7, 7, 8, 0, "100000000000000" },
77 { 1.0e-12, 4, -4, 0, "" },
78 #ifndef SKIP_FCVT_NEG
79 /* legacy newlib doesn't handle negative ndecimal correctly */
80 { 1.23456e0,-4, 1, 0, "1" },
81 { 1.23456e1,-4, 2, 0, "10" },
82 { 1.23456e2,-4, 3, 0, "100" },
83 { 1.23456e3,-4, 4, 0, "1000" },
84 { 1.23456e4,-4, 5, 0, "10000" },
85 { 1.23456e5,-4, 6, 0, "120000" },
86 { 1.23456e6,-4, 7, 0, "1230000" },
87 #endif
88 { 1.23456e-10,4,-4, 0, "" },
89 { 1.23456e-9,4, -4, 0, "" },
90 { 1.23456e-8,4, -4, 0, "" },
91 { 1.23456e-7,4, -4, 0, "" },
92 { 1.23456e-6,4, -4, 0, "" },
93 { 1.23456e-5,4, -4, 0, "" },
94 { 1.23456e-4,4, -3, 0, "1" },
95 { 1.23456e-3,4, -2, 0, "12" },
96 { 1.23456e-2,4, -1, 0, "123" },
97 { 1.23456e-1,4, 0, 0, "1235" },
98 { 1.23456e0,4, 1, 0, "12346" },
99 { 1.23456e1,4, 2, 0, "123456" },
100 { 1.23456e2,4, 3, 0, "1234560" },
101 { 1.23456e3,4, 4, 0, "12345600" },
102 { 1.23456e4,4, 5, 0, "123456000" },
103 { 1.23456e5,4, 6, 0, "1234560000" },
104 { 1.23456e6,4, 7, 0, "12345600000" },
105 { 1.23456e7,4, 8, 0, "123456000000" },
106 { 1.23456e8,4, 9, 0, "1234560000000" },
107 { 1.23456e9,4, 10, 0, "12345600000000" },
108 };
109
110 #define N_FCVT_TESTS (sizeof(fcvt_tests) / sizeof(fcvt_tests[0]))
111
112 const struct test fcvt_extra_tests[] = {
113 #ifdef TINY_STDIO
114 #if __SIZEOF_DOUBLE__ == 4
115 { 0x1.fffffep127, 9, 39, 0, "340282350000000000000000000000000000000000000000" },
116 #else
117 { 0x1.fffffffffffffp1023, 17, 309, 0, "17976931348623157"
118 "0000000000000000000000000000000000000000"
119 "0000000000000000000000000000000000000000"
120 "0000000000000000000000000000000000000000"
121 "0000000000000000000000000000000000000000"
122 "0000000000000000000000000000000000000000"
123 "0000000000000000000000000000000000000000"
124 "0000000000000000000000000000000000000000"
125 "000000000000"
126 "00000000000000000"},
127 { 0x1.fffffep127, 9, 39, 0, "340282346638528860000000000000000000000000000000" },
128 #endif
129 #else
130 { 0x1.fffffffffffffp1023, 17, 309, 0, "17976931348623157"
131 "0814527423731704356798070567525844996598"
132 "9174768031572607800285387605895586327668"
133 "7817154045895351438246423432132688946418"
134 "2768467546703537516986049910576551282076"
135 "2454900903893289440758685084551339423045"
136 "8323690322294816580855933212334827479782"
137 "6204144723168738177180919299881250404026"
138 "184124858368"
139 "00000000000000000"},
140 { 0x1.fffffep127, 9, 39, 0, "340282346638528859811704183484516925440000000000" },
141 #endif
142 };
143
144 #define N_FCVT_EXTRA_TESTS (sizeof(fcvt_extra_tests) / sizeof(fcvt_extra_tests[0]))
145
146 const struct test fcvtf_tests[] = {
147 #ifdef TINY_STDIO
148 { 0x1.fffffep127, 9, 39, 0, "340282350000000000000000000000000000000000000000" },
149 #else
150 /* legacy newlib uses the double path for this operation */
151 { 0x1.fffffep127, 9, 39, 0, "340282346638528859811704183484516925440000000000" },
152 #endif
153 };
154
155 #define N_FCVTF_TESTS (sizeof(fcvtf_tests) / sizeof(fcvtf_tests[0]))
156
157 #if defined(TINY_STDIO) && !defined(_IO_FLOAT_EXACT)
158 /* non-exact tinystdio conversions are not precise over about 6 digits */
159 #define SKIP_LONG_FLOAT 1
160 #else
161 #define SKIP_LONG_FLOAT 0
162 #endif
163
164 #if (!defined(TINY_STDIO) || !defined(_IO_FLOAT_EXACT)) && __SIZEOF_DOUBLE__ < 8
165 #undef SKIP_LONG_FLOAT
166 #define SKIP_LONG_FLOAT 1
167 #define SKIP_LONGISH_FLOAT 1
168 #endif
169
170 #ifndef SKIP_LONGISH_FLOAT
171 #define SKIP_LONGISH_FLOAT 0
172 #endif
173
174 #define many_tests(tests, func, n, skip_long) do { \
175 for (i = 0; i < n; i++) { \
176 int decpt; \
177 int sign; \
178 int ret = func(tests[i].value, tests[i].ndigit, &decpt, &sign, buf, sizeof(buf)); \
179 \
180 if (ret < 0) { \
181 printf("%d: failed\n", ret); \
182 continue; \
183 } \
184 if (skip_long && strlen(buf) > 6) { \
185 printf("skipping test as result is long (%s)\n", buf); \
186 continue; \
187 } \
188 if (strcmp(buf, tests[i].expect) != 0 || \
189 decpt != tests[i].decpt || \
190 sign != tests[i].sign) \
191 { \
192 printf(#func ":%d got '%s' dec %d sign %d expect '%s' dec %d sign %d\n", \
193 i, buf, decpt, sign, \
194 tests[i].expect, tests[i].decpt, tests[i].sign); \
195 error = 1; \
196 } \
197 } \
198 } while(0)
199
200 int
main(void)201 main(void)
202 {
203 int error = 0;
204 unsigned i;
205 static char buf[2048];
206
207 many_tests(fcvt_tests, fcvt_r, N_FCVT_TESTS, SKIP_LONGISH_FLOAT);
208 many_tests(fcvt_extra_tests, fcvt_r, N_FCVT_EXTRA_TESTS, SKIP_LONG_FLOAT);
209 many_tests(ecvt_tests, ecvt_r, N_ECVT_TESTS, SKIP_LONGISH_FLOAT);
210 #ifdef __PICOLIBC__
211 many_tests(fcvt_tests, fcvtf_r, N_FCVT_TESTS, SKIP_LONG_FLOAT);
212 many_tests(fcvtf_tests, fcvtf_r, N_FCVTF_TESTS, SKIP_LONG_FLOAT);
213 many_tests(ecvt_tests, ecvtf_r, N_ECVT_TESTS, SKIP_LONGISH_FLOAT);
214 #endif
215 return error;
216 }
217