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 <math.h>
38 #include <stdbool.h>
39 #include <stdio.h>
40 #include <float.h>
41
42 #ifdef LDBL_MANT_DIG
43
44 static long double max_error;
45
46 bool
within_error(long double expect,long double result,long double error)47 within_error(long double expect, long double result, long double error)
48 {
49 long double difference;
50 long double e = 1.0L;
51
52 if (isnan(expect) && isnan(result))
53 return true;
54
55 if (expect == result)
56 return true;
57
58 if (expect != 0)
59 e = scalbnl(1.0L, -ilogbl(expect));
60
61 difference = fabsl(expect - result) * e;
62
63 if (difference > max_error)
64 max_error = difference;
65
66 return difference <= error;
67 }
68
69 int
check_long_double(const char * name,int i,long double prec,long double expect,long double result)70 check_long_double(const char *name, int i, long double prec, long double expect, long double result)
71 {
72 if (!within_error(expect, result, prec)) {
73 long double diff = fabsl(expect - result);
74 #ifdef __PICOLIBC__
75 printf("%s test %d got %.15g expect %.15g diff %.15g\n", name, i, (double) result, (double) expect, (double) diff);
76 #else
77 // printf("%s test %d got %.33Lg expect %.33Lg diff %.33Lg\n", name, i, result, expect, diff);
78 printf("%s test %d got %La expect %La diff %La\n", name, i, result, expect, diff);
79 #endif
80 return 1;
81 }
82 return 0;
83 }
84
85 int
check_long_long(const char * name,int i,long long expect,long long result)86 check_long_long(const char *name, int i, long long expect, long long result)
87 {
88 if (expect != result) {
89 long long diff = expect - result;
90 printf("%s test %d got %lld expect %lld diff %lld\n", name, i, result, expect, diff);
91 return 1;
92 }
93 return 0;
94 }
95
96 typedef struct {
97 const char *name;
98 int (*test)(void);
99 } long_double_test_t;
100
101 typedef struct {
102 int line;
103 long double x;
104 long double y;
105 } long_double_test_f_f_t;
106
107 typedef struct {
108 int line;
109 long double x0;
110 long double x1;
111 long double y;
112 } long_double_test_f_ff_t;
113
114 typedef struct {
115 int line;
116 long double x0;
117 int x1;
118 long double y;
119 } long_double_test_f_fi_t;
120
121 typedef struct {
122 int line;
123 long double x;
124 long long y;
125 } long_double_test_i_f_t;
126
127 /*
128 * sqrtl is "exact", but can have up to one bit of error as it might
129 * not have enough guard bits to correctly perform rounding, leading
130 * to some answers getting rounded to an even value instead of the
131 * (more accurate) odd value
132 */
133 #if LDBL_MANT_DIG == 64
134 #define DEFAULT_PREC 0x1p-55L
135 #define SQRTL_PREC 0x1.0p-63L
136 #define FULL_LONG_DOUBLE
137 #elif LDBL_MANT_DIG == 113
138 #define FULL_LONG_DOUBLE
139 #define DEFAULT_PREC 0x1p-105L
140 #define SQRTL_PREC 0x1.0p-112L
141 #elif LDBL_MANT_DIG == 106
142 #define DEFAULT_PREC 0x1p-97L
143 #define SQRTL_PREC 0x1.0p-105L
144 #define PART_LONG_DOUBLE
145 #elif LDBL_MANT_DIG == 53
146 #define DEFAULT_PREC 0x1p-48L
147 #define SQRTL_PREC 0x1.0p-52L
148 #else
149 #error unsupported long double
150 #endif
151
152 #define HYPOTL_PREC SQRTL_PREC
153 #define CBRTL_PREC SQRTL_PREC
154 #define CEILL_PREC 0
155 #define FLOORL_PREC 0
156 #define LOGBL_PREC 0
157 #define RINTL_PREC 0
158 #define FMINL_PREC 0
159 #define FMAXL_PREC 0
160 #define SCALBNL_PREC 0
161 #define SCALBL_PREC 0
162 #define LDEXPL_PREC 0
163 #define COPYSIGNL_PREC 0
164 #define NEARBYINTL_PREC 0
165 #define ROUNDL_PREC 0
166 #define TRUNCL_PREC 0
167
168 #include "long_double_vec.h"
169
170 #if defined(_WANT_IO_LONG_DOUBLE) && (defined(TINY_STDIO) || defined(FLOATING_POINT))
171 #define TEST_IO_LONG_DOUBLE
172 #endif
173
174 #ifdef TEST_IO_LONG_DOUBLE
175 static long double vals[] = {
176 1.0L,
177 0x1.8p0L,
178 3.141592653589793238462643383279502884197169L,
179 0.0L,
180 };
181
182 #define NVALS (sizeof(vals)/sizeof(vals[0]))
183
184 static int
test_io(void)185 test_io(void)
186 {
187 int e;
188 int result = 0;
189 char buf[80];
190 unsigned i;
191
192 for (e = __LDBL_MIN_EXP__ - __LDBL_MANT_DIG__; e <= __LDBL_MAX_EXP__; e++)
193 {
194 long double v, r;
195 for (i = 0; i < NVALS; i++) {
196 v = ldexpl(vals[i], e);
197 sprintf(buf, "%La", v);
198 sscanf(buf, "%Lf", &r);
199 if (v != r) {
200 printf("%d: \"%s\", is %La should be %La\n", e, buf, r, v);
201 result++;
202 }
203 }
204 }
205 return result;
206 }
207 #endif
208
main(void)209 int main(void)
210 {
211 int result = 0;
212 unsigned int i;
213
214 printf("LDBL_MANT_DIG %d\n", LDBL_MANT_DIG);
215 #ifdef TEST_IO_LONG_DOUBLE
216 result += test_io();
217 #endif
218 for (i = 0; i < sizeof(long_double_tests) / sizeof(long_double_tests[0]); i++) {
219 result += long_double_tests[i].test();
220 }
221 return result != 0;
222 }
223
224 #else
main(void)225 int main(void)
226 {
227 printf("no long double support\n");
228 return 0;
229 }
230 #endif
231