]> git.ipfire.org Git - thirdparty/gcc.git/blob - libstdc++-v3/testsuite/20_util/to_chars/long_double.cc
Update copyright years.
[thirdparty/gcc.git] / libstdc++-v3 / testsuite / 20_util / to_chars / long_double.cc
1 // Copyright (C) 2020-2022 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 // <charconv> is supported in C++14 as a GNU extension, but this test uses C++17
19 // hexadecimal floating-point literals.
20
21 // When long double is larger than double, the long double to_chars overloads
22 // are partially implemented in terms of printf, so this test in turn uses
23 // printf to verify correctness these overloads.
24 // When long double == double, the long double to_chars overloads are simple
25 // wrappers around the corresponding double overloads. Since they don't go
26 // through printf, we can't portably verify their output by comparing it with
27 // that of printf, so it's simplest to just not run this test on such targets;
28 // correctness of these overloads is already implied by that of the double
29 // overloads.
30 // { dg-do run { target { c++17 && large_long_double } } }
31 // { dg-do compile { target { c++17 && { ! large_long_double } } } }
32
33 // The system printf on these targets appear to be buggy. FIXME: Make this test
34 // more portable and robust to differences in system printf behavior.
35 // { dg-xfail-run-if "Non-conforming printf (see PR98384)" { *-*-solaris* *-*-darwin* } }
36
37 // { dg-require-effective-target ieee_floats }
38 // { dg-require-effective-target size32plus }
39
40 #include <charconv>
41
42 #include <cmath>
43 #include <cstring>
44 #include <iterator>
45 #include <optional>
46 #include <limits>
47
48 #include <testsuite_hooks.h>
49
50 using namespace std;
51
52 namespace detail
53 {
54 long double
55 nextupl(long double x)
56 { return nexttowardl(x, numeric_limits<long double>::infinity()); }
57
58 long double
59 nextdownl(long double x)
60 { return nexttowardl(x, -numeric_limits<long double>::infinity()); }
61 }
62
63 // The long double overloads of std::to_chars currently just go through printf
64 // (except for the hexadecimal formatting).
65
66 // Test our hand-written hexadecimal formatting implementation.
67 void
68 test01()
69 {
70 // Verifies correctness of the hexadecimal form [BEGIN,END) for VALUE by
71 // round-tripping it through from_chars (if available).
72 auto verify_via_from_chars = [] (char *begin, char *end, long double value) {
73 #if __cpp_lib_to_chars >= 201611L
74 long double roundtrip;
75 auto result = from_chars(begin, end, roundtrip, chars_format::hex);
76 VERIFY( result.ec == errc{} );
77 VERIFY( result.ptr == end );
78 VERIFY( roundtrip == value );
79 #endif
80 };
81
82 // Verifies correctness of the null-terminated hexadecimal form at BEGIN
83 // for VALUE and PRECISION by comparing it with the output of printf's %La
84 // conversion specifier.
85 auto verify_via_printf = [] (char *begin, long double value,
86 optional<int> precision = nullopt) {
87 char printf_buffer[1024] = {};
88 if (precision.has_value())
89 sprintf(printf_buffer, "%.*La", precision.value(), value);
90 else
91 sprintf(printf_buffer, "%La", value);
92
93 // Only compare with the output of printf if the leading hex digits agree.
94 // If the leading hex digit of our form doesn't agree with that of printf,
95 // then the two forms may still be equivalent (e.g. 1.1p+0 vs 8.8p-3). But
96 // if the leading hex digits do agree, then we do expect the two forms to be
97 // the same.
98 if (printf_buffer[strlen("0x")] == begin[0])
99 VERIFY( !strcmp(begin, printf_buffer+strlen("0x")) );
100 };
101
102 const long double hex_testcases[]
103 = { detail::nextdownl(numeric_limits<long double>::max()),
104 detail::nextupl(numeric_limits<long double>::min()),
105 42.0L,
106 0x1.2p+0L,
107 0x1.23p+0L,
108 0x1.234p+0L,
109 0x1.2345p+0L,
110 0x1.23456p+0L,
111 0x1.234567p+0L,
112 0x1.2345678p+0L,
113 0x1.23456789p+0L,
114 0x1.23456789p+0L,
115 0x1.23456789ap+0L,
116 0x1.23456789abp+0L,
117 0x1.23456789abcp+0L,
118 0x1.23456789abcdp+0L,
119 0x1.23456789abcdep+0L,
120 0x1.23456789abcdefp+0L,
121 0x1.23456789abcdef0p+0L,
122 0x1.23456789abcdef01p+0L,
123 0x1.23456789abcdef012p+0L,
124 0x1.23456789abcdef0123p+0L,
125 0x1.23456789abcdef01234p+0L,
126 0x1.23456789abcdef012345p+0L,
127 0x1.23456789abcdef0123456p+0L,
128 0x1.23456789abcdef01234567p+0L,
129 0x1.23456789abcdef012345678p+0L,
130 0x1.23456789abcdef0123456789p+0L,
131 0x1.23456789abcdef0123456789ap+0L,
132 0x1.23456789abcdef0123456789abp+0L,
133 0x1.23456789abcdef0123456789abcp+0L,
134 0x1.23456789abcdef0123456789abcdp+0L,
135 };
136
137 for (int exponent : {-11000, -3000, -300, -50, -7, 0, 7, 50, 300, 3000, 11000})
138 for (long double testcase : hex_testcases)
139 {
140 testcase = ldexpl(testcase, exponent);
141 if (testcase == 0.0L || isinf(testcase))
142 continue;
143
144 char to_chars_buffer[1024] = {};
145 auto result = to_chars(begin(to_chars_buffer), end(to_chars_buffer),
146 testcase, chars_format::hex);
147 VERIFY( result.ec == errc{} );
148 *result.ptr = '\0';
149 verify_via_from_chars(begin(to_chars_buffer), result.ptr, testcase);
150 verify_via_printf(to_chars_buffer, testcase);
151
152 // Verify the nearby values, and also check they have a different
153 // shortest form.
154 for (long double nearby
155 : { detail::nextdownl(testcase), detail::nextupl(testcase) })
156 {
157 char nearby_buffer[1024] = {};
158 result = to_chars(begin(nearby_buffer), end(nearby_buffer),
159 nearby, chars_format::hex);
160 VERIFY( result.ec == errc{} );
161 *result.ptr = '\0';
162 VERIFY( strcmp(nearby_buffer, to_chars_buffer) != 0);
163 verify_via_from_chars(begin(nearby_buffer), result.ptr, nearby);
164 verify_via_printf(nearby_buffer, nearby);
165 }
166
167 for (int precision = -1; precision < 50; precision++)
168 {
169 result = to_chars(begin(to_chars_buffer), end(to_chars_buffer),
170 testcase, chars_format::hex, precision);
171 VERIFY( result.ec == errc{} );
172 *result.ptr = '\0';
173 verify_via_printf(to_chars_buffer, testcase, precision);
174 }
175 }
176 }
177
178 // Test the rest of the formatting modes, which go through printf.
179 void
180 test02()
181 {
182 const long double growth_factor = 1.442695040888963407359924681001892137L;
183 for (chars_format fmt : {chars_format::fixed, chars_format::scientific,
184 chars_format::general})
185 for (long double __value = 1.0L, count = 0; !isinf(__value);
186 ++count <= 100.0L ? __value *= growth_factor : __value *= __value)
187 for (const long double value : {__value, 1.0L/__value})
188 {
189 for (const int precision : {-1, 0, 10, 100, 10000})
190 {
191 const char* const printf_specifier
192 = (fmt == chars_format::fixed ? "%.*Lf"
193 : fmt == chars_format::scientific ? "%.*Le"
194 : fmt == chars_format::general ? "%.*Lg"
195 : nullptr);
196 unsigned output_length = snprintf(nullptr, 0, printf_specifier,
197 precision, value);
198
199 char printf_buffer[output_length+1];
200 snprintf(printf_buffer, output_length+1, printf_specifier,
201 precision, value);
202
203 char to_chars_buffer[output_length];
204 auto result = to_chars(to_chars_buffer,
205 to_chars_buffer+output_length,
206 value, fmt, precision);
207 VERIFY( result.ec == errc{} );
208 VERIFY( !memcmp(printf_buffer, to_chars_buffer, output_length) );
209
210 result = to_chars(to_chars_buffer,
211 to_chars_buffer+output_length-1,
212 value, fmt, precision);
213 VERIFY( result.ec == errc::value_too_large );
214 }
215
216 // Verify that the nearby values have a different shortest form.
217 char to_chars_buffer[50000];
218 auto result = to_chars(begin(to_chars_buffer), end(to_chars_buffer),
219 value, fmt);
220 VERIFY( result.ec == errc{} );
221 *result.ptr = '\0';
222 char nearby_buffer[50000];
223 {
224 const long double smaller = detail::nextdownl(value);
225 result = to_chars(begin(nearby_buffer), end(nearby_buffer),
226 smaller, fmt);
227 VERIFY( result.ec == errc{} );
228 *result.ptr = '\0';
229 VERIFY( strcmp(to_chars_buffer, nearby_buffer) != 0 );
230 }
231
232 {
233 long double larger = detail::nextupl(value);
234 result = to_chars(begin(nearby_buffer), end(nearby_buffer),
235 larger, fmt);
236 VERIFY( result.ec == errc{} );
237 *result.ptr = '\0';
238 VERIFY( strcmp(to_chars_buffer, nearby_buffer) != 0 );
239 }
240 }
241 }
242
243 int
244 main()
245 {
246 test01();
247 test02();
248 }