]>
Commit | Line | Data |
---|---|---|
a945c346 | 1 | // Copyright (C) 2020-2024 Free Software Foundation, Inc. |
29ef50b6 JJ |
2 | // |
3 | // This file is part of the GNU ISO C++ Library. This library is free | |
4 | // software; you can redistribute it and/or modify it under the | |
5 | // terms of the GNU General Public License as published by the | |
6 | // Free Software Foundation; either version 3, or (at your option) | |
7 | // any later version. | |
8 | ||
9 | // This library is distributed in the hope that it will be useful, | |
10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | // GNU General Public License for more details. | |
13 | ||
14 | // You should have received a copy of the GNU General Public License along | |
15 | // with this library; see the file COPYING3. If not see | |
16 | // <http://www.gnu.org/licenses/>. | |
17 | ||
29ef50b6 JJ |
18 | // { dg-do run { target c++23 } } |
19 | // { dg-add-options ieee } | |
6c3b01db | 20 | // { dg-additional-options "-DSKIP_LONG_DOUBLE" { target aarch64-*-vxworks* aarch64-*-rtems* } } |
29ef50b6 JJ |
21 | |
22 | #include <charconv> | |
23 | #include <string> | |
24 | #include <limits> | |
25 | #include <stdfloat> | |
26 | #include <cmath> | |
27 | #include <cstdlib> | |
28 | #include <testsuite_hooks.h> | |
29 | ||
30 | // Test std::from_chars floating-point conversions. | |
31 | ||
32 | #if __cpp_lib_to_chars >= 201611L | |
33 | #if defined(__STDCPP_FLOAT64_T__) && defined(_GLIBCXX_DOUBLE_IS_IEEE_BINARY64) | |
34 | void | |
35 | test01() | |
36 | { | |
37 | std::string s; | |
38 | std::float64_t f64; | |
39 | std::from_chars_result res; | |
40 | ||
41 | for (auto fmt : { std::chars_format::fixed, std::chars_format::scientific, | |
42 | std::chars_format::general, std::chars_format::hex }) | |
43 | { | |
44 | s = "Info"; | |
45 | res = std::from_chars(s.data(), s.data() + s.length(), f64, fmt); | |
46 | VERIFY( std::isinf(f64) ); | |
47 | VERIFY( res.ptr == s.data() + 3 ); | |
48 | VERIFY( res.ec == std::errc{} ); | |
49 | ||
50 | s = "-INFIN"; | |
51 | res = std::from_chars(s.data(), s.data() + s.length(), f64, fmt); | |
52 | VERIFY( std::isinf(f64) ); | |
53 | VERIFY( f64 < 0 ); | |
54 | VERIFY( res.ptr == s.data() + 4 ); | |
55 | VERIFY( res.ec == std::errc{} ); | |
56 | ||
57 | s = "InFiNiTy aNd BeYoNd"; | |
58 | res = std::from_chars(s.data(), s.data() + s.length(), f64, fmt); | |
59 | VERIFY( std::isinf(f64) ); | |
60 | VERIFY( res.ptr == s.data() + 8 ); | |
61 | VERIFY( res.ec == std::errc{} ); | |
62 | ||
63 | s = "nAn"; | |
64 | res = std::from_chars(s.data(), s.data() + s.length(), f64, fmt); | |
65 | VERIFY( std::isnan(f64) ); | |
66 | VERIFY( res.ptr == s.data() + 3 ); | |
67 | VERIFY( res.ec == std::errc{} ); | |
68 | ||
69 | s = "-NAN()"; | |
70 | res = std::from_chars(s.data(), s.data() + s.length(), f64, fmt); | |
71 | VERIFY( std::isnan(f64) ); | |
72 | VERIFY( res.ptr == s.data() + s.length() ); | |
73 | VERIFY( res.ec == std::errc{} ); | |
74 | } | |
75 | } | |
76 | ||
77 | void | |
78 | test02() | |
79 | { | |
80 | std::string s; | |
81 | std::float64_t f64 = 1.0f64; | |
82 | std::from_chars_result res; | |
83 | ||
84 | s = "0x123"; | |
85 | res = std::from_chars(s.data(), s.data() + s.length(), f64); | |
86 | VERIFY( f64 == 0.0f64 ); | |
87 | VERIFY( res.ptr == s.data() + 1 ); | |
88 | VERIFY( res.ec == std::errc{} ); | |
89 | ||
90 | f64 = 1.0f64; | |
91 | res = std::from_chars(s.data(), s.data() + s.length(), f64, | |
92 | std::chars_format::fixed); | |
93 | VERIFY( f64 == 0.0f64 ); | |
94 | VERIFY( res.ptr == s.data() + 1 ); | |
95 | VERIFY( res.ec == std::errc{} ); | |
96 | ||
97 | f64 = 1.0f64; | |
98 | res = std::from_chars(s.data(), s.data() + s.length(), f64, | |
99 | std::chars_format::scientific); | |
100 | VERIFY( f64 == 1.0f64 ); | |
101 | VERIFY( res.ptr == s.data() ); | |
102 | VERIFY( res.ec == std::errc::invalid_argument ); | |
103 | ||
104 | f64 = 1.0f64; | |
105 | res = std::from_chars(s.data(), s.data() + s.length(), f64, | |
106 | std::chars_format::general); | |
107 | VERIFY( f64 == 0.0f64 ); | |
108 | VERIFY( res.ptr == s.data() + 1 ); | |
109 | VERIFY( res.ec == std::errc{} ); | |
110 | ||
111 | f64 = 1.0f64; | |
112 | res = std::from_chars(s.data(), s.data() + s.length(), f64, | |
113 | std::chars_format::hex); | |
114 | VERIFY( f64 == 0.0f64 ); | |
115 | VERIFY( res.ptr == s.data() + 1 ); | |
116 | VERIFY( res.ec == std::errc{} ); | |
117 | } | |
118 | ||
119 | void | |
120 | test03() | |
121 | { | |
122 | std::string s; | |
123 | std::float64_t f64 = 1.0f64; | |
124 | std::from_chars_result res; | |
125 | ||
126 | s = "0.5e+2azzz"; | |
127 | res = std::from_chars(s.data(), s.data() + s.length(), f64); | |
128 | VERIFY( f64 == 0.5e+2f64 ); | |
129 | VERIFY( res.ptr == s.data() + s.length() - 1 - 3 ); | |
130 | VERIFY( res.ec == std::errc{} ); | |
131 | ||
132 | res = std::from_chars(s.data(), s.data() + s.length(), f64, | |
133 | std::chars_format::fixed); | |
134 | VERIFY( f64 == 0.5f64 ); | |
135 | VERIFY( res.ptr == s.data() + 3 ); | |
136 | VERIFY( res.ec == std::errc{} ); | |
137 | ||
138 | f64 = 1.0f64; | |
139 | res = std::from_chars(s.data(), s.data() + s.length(), f64, | |
140 | std::chars_format::scientific); | |
141 | VERIFY( f64 == 0.5e+2f64 ); | |
142 | VERIFY( res.ptr == s.data() + s.length() - 1 - 3 ); | |
143 | VERIFY( res.ec == std::errc{} ); | |
144 | ||
145 | f64 = 1.0f64; | |
146 | res = std::from_chars(s.data(), s.data() + s.length(), f64, | |
147 | std::chars_format::general); | |
148 | VERIFY( f64 == 0.5e+2f64 ); | |
149 | VERIFY( res.ptr == s.data() + s.length() - 1 - 3 ); | |
150 | VERIFY( res.ec == std::errc{} ); | |
151 | ||
152 | f64 = 1.0; | |
153 | res = std::from_chars(s.data(), s.data() + s.length(), f64, | |
154 | std::chars_format::hex); | |
155 | VERIFY( f64 == 0x0.5Ep0f64 ); | |
156 | VERIFY( res.ptr == s.data() + 4 ); | |
157 | VERIFY( res.ec == std::errc{} ); | |
158 | ||
159 | s = "1.Ap-2zzz"; | |
160 | res = std::from_chars(s.data(), s.data() + s.length(), f64, | |
161 | std::chars_format::hex); | |
162 | VERIFY( f64 == 0.40625f64 ); | |
163 | VERIFY( res.ptr == s.data() + s.length() - 3 ); | |
164 | VERIFY( res.ec == std::errc{} ); | |
165 | } | |
166 | ||
167 | void | |
168 | test04() | |
169 | { | |
170 | // Huge input strings | |
171 | std::string s(1000, '0'); | |
172 | std::float64_t f64 = 1.0f64; | |
173 | std::from_chars_result res; | |
174 | res = std::from_chars(s.data(), s.data() + s.length(), f64); | |
175 | VERIFY( res.ptr == s.data() + s.length() ); | |
176 | VERIFY( res.ec == std::errc{} ); | |
177 | VERIFY( f64 == 0.0f64 ); | |
178 | ||
179 | s += ".5"; | |
180 | res = std::from_chars(s.data(), s.data() + s.length(), f64); | |
181 | VERIFY( res.ptr == s.data() + s.length() ); | |
182 | VERIFY( res.ec == std::errc{} ); | |
183 | VERIFY( f64 == 0.5f64 ); | |
184 | ||
185 | s += "e2"; | |
186 | auto len = s.length(); | |
187 | s += std::string(1000, 'a'); | |
188 | res = std::from_chars(s.data(), s.data() + s.length(), f64); | |
189 | VERIFY( res.ptr == s.data() + len ); | |
190 | VERIFY( res.ec == std::errc{} ); | |
191 | VERIFY( f64 == 50.f64 ); | |
192 | } | |
193 | #endif | |
194 | ||
195 | using std::to_string; | |
196 | ||
197 | #ifdef __GLIBCXX_TYPE_INT_N_0 | |
198 | std::string | |
199 | to_string(unsigned __GLIBCXX_TYPE_INT_N_0 val) | |
200 | { | |
201 | using Limits = std::numeric_limits<unsigned __GLIBCXX_TYPE_INT_N_0>; | |
202 | std::string s(Limits::digits10+2, '0'); | |
203 | for (auto iter = s.end(); val != 0; val /= 10) | |
204 | *--iter = '0' + (val % 10); | |
205 | return s; | |
206 | } | |
207 | #endif | |
208 | ||
209 | template<typename FloatT> | |
210 | void | |
211 | test_small_num() | |
212 | { | |
213 | std::from_chars_result res; | |
214 | FloatT flt; | |
215 | ||
216 | // Small integer values that are exactly representable | |
217 | ||
218 | for (int i = 0; i < 100; ++i) | |
219 | { | |
220 | std::string s = to_string(i); | |
221 | int len = s.length(); | |
222 | s += "123"; | |
223 | const char* s1 = s.c_str(); | |
224 | const char* s1_end = s1 + len; | |
225 | ||
226 | for (auto fmt : { std::chars_format::fixed, | |
227 | std::chars_format::general, | |
228 | std::chars_format::hex }) | |
229 | { | |
230 | if (fmt == std::chars_format::hex && i > 9) | |
231 | continue; | |
232 | ||
233 | res = std::from_chars(s1, s1_end, flt, fmt); | |
234 | VERIFY( res.ec == std::errc{} ); | |
235 | VERIFY( res.ptr == s1_end ); | |
236 | VERIFY( flt == i ); | |
237 | } | |
238 | ||
239 | if (i > 9) | |
240 | continue; | |
241 | ||
242 | // Test single-digit integers with small exponents. | |
243 | ||
244 | const char s2[] = { '.', *s1, 'e', '0', '0', '0', '1' }; | |
245 | const char* s2_end = s2 + sizeof(s2); | |
246 | ||
247 | const char s3[] = { *s1, '0', 'e', '-', '0', '0', '1' }; | |
248 | const char* s3_end = s3 + sizeof(s3); | |
249 | ||
250 | for (auto fmt : { std::chars_format::scientific, | |
251 | std::chars_format::general }) | |
252 | { | |
253 | res = std::from_chars(s2, s2_end, flt, fmt); | |
254 | VERIFY( res.ec == std::errc{} ); | |
255 | VERIFY( res.ptr == s2_end ); | |
256 | VERIFY( flt == i ); | |
257 | ||
258 | res = std::from_chars(s3, s3_end, flt, fmt); | |
259 | VERIFY( res.ec == std::errc{} ); | |
260 | VERIFY( res.ptr == s3_end ); | |
261 | VERIFY( flt == i ); | |
262 | } | |
263 | } | |
264 | } | |
265 | ||
266 | void | |
267 | test05() | |
268 | { | |
269 | #if defined(__STDCPP_FLOAT32_T__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32) | |
270 | test_small_num<std::float32_t>(); | |
271 | #endif | |
272 | #if defined(__STDCPP_FLOAT64_T__) && defined(_GLIBCXX_DOUBLE_IS_IEEE_BINARY64) | |
273 | test_small_num<std::float64_t>(); | |
274 | #endif | |
275 | #if defined(__STDCPP_FLOAT128_T__) && defined(_GLIBCXX_LDOUBLE_IS_IEEE_BINARY128) | |
276 | test_small_num<std::float128_t>(); | |
277 | #endif | |
278 | } | |
279 | ||
280 | template<typename FloatT, typename UIntT> | |
281 | void | |
282 | test_max_mantissa() | |
283 | { | |
284 | using Float_limits = std::numeric_limits<FloatT>; | |
285 | using UInt_limits = std::numeric_limits<UIntT>; | |
286 | ||
287 | if (Float_limits::is_iec559 && Float_limits::digits < UInt_limits::digits) | |
288 | { | |
1f378f6d | 289 | #ifdef _GLIBCXX_USE_C99_MATH_FUNCS |
29ef50b6 JJ |
290 | std::printf("Testing %d-bit float, using %zu-bit integer\n", |
291 | Float_limits::digits + (int)std::log2(Float_limits::max_exponent) + 1, | |
292 | sizeof(UIntT) * __CHAR_BIT__); | |
293 | #endif | |
294 | ||
295 | std::from_chars_result res; | |
296 | FloatT flt; | |
297 | ||
298 | for (int i = 0; i < 10; ++i) | |
299 | { | |
300 | // (1 << digits) - 1 is the maximum value of the mantissa | |
301 | const auto val = ((UIntT)1 << Float_limits::digits) - 1 - i; | |
302 | std::string s = to_string(val); | |
303 | auto len = s.length(); | |
304 | s += "000"; // these should be ignored | |
305 | for (auto fmt : { std::chars_format::fixed, | |
306 | std::chars_format::general }) | |
307 | { | |
308 | res = std::from_chars(s.data(), s.data() + len, flt, fmt); | |
309 | VERIFY( res.ec == std::errc{} ); | |
310 | VERIFY( res.ptr == s.data() + len ); | |
311 | VERIFY( flt == val ); | |
312 | } | |
313 | s.resize(len); | |
314 | const auto orig_len = len; | |
315 | s += "e+000"; | |
316 | len = s.length(); | |
317 | s += "111"; | |
318 | for (auto fmt : { std::chars_format::scientific, | |
319 | std::chars_format::general }) | |
320 | { | |
321 | res = std::from_chars(s.data(), s.data() + len, flt, fmt); | |
322 | VERIFY( res.ec == std::errc{} ); | |
323 | VERIFY( res.ptr == s.data() + len ); | |
324 | VERIFY( flt == val ); | |
325 | ||
326 | std::string s2 = s.substr(0, len - 5); | |
327 | s2.insert(s2.begin() + orig_len - 1, '.'); | |
328 | s2 += "e000000000001"; | |
329 | res = std::from_chars(s.data(), s.data() + len, flt, fmt); | |
330 | VERIFY( res.ec == std::errc{} ); | |
331 | VERIFY( res.ptr == s.data() + len ); | |
332 | VERIFY( flt == val ); | |
333 | } | |
334 | } | |
335 | } | |
336 | } | |
337 | ||
338 | void | |
339 | test06() | |
340 | { | |
341 | #if defined(__STDCPP_FLOAT32_T__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32) | |
342 | test_max_mantissa<std::float32_t, unsigned long>(); | |
343 | #endif | |
344 | #if defined(__STDCPP_FLOAT64_T__) && defined(_GLIBCXX_DOUBLE_IS_IEEE_BINARY64) | |
345 | test_max_mantissa<std::float64_t, unsigned long long>(); | |
346 | #endif | |
5b178179 | 347 | #if defined(__GLIBCXX_TYPE_INT_N_0) && !defined SKIP_LONG_DOUBLE \ |
29ef50b6 JJ |
348 | && defined(__STDCPP_FLOAT128_T__) && defined(_GLIBCXX_LDOUBLE_IS_IEEE_BINARY128) |
349 | test_max_mantissa<std::float128_t, unsigned __GLIBCXX_TYPE_INT_N_0>(); | |
350 | #endif | |
351 | } | |
352 | #endif | |
353 | ||
354 | int | |
355 | main() | |
356 | { | |
357 | #if __cpp_lib_to_chars >= 201611L | |
358 | #if defined(__STDCPP_FLOAT64_T__) && defined(_GLIBCXX_DOUBLE_IS_IEEE_BINARY64) | |
359 | test01(); | |
360 | test02(); | |
361 | test03(); | |
362 | test04(); | |
363 | #endif | |
364 | test05(); | |
365 | test06(); | |
366 | #endif | |
367 | } |