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