1 /* $NetBSD: t_sincos.c,v 1.2 2024/05/06 15:53:46 riastradh Exp $ */
2
3 /*-
4 * Copyright (c) 2011, 2022 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Jukka Ruohonen and Christos Zoulas
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include <assert.h>
33 #include <atf-c.h>
34 #include <float.h>
35 #include <math.h>
36 #include <stdio.h>
37
38 static const struct {
39 int angle;
40 double x;
41 double y;
42 float fy;
43 } sin_angles[] = {
44 // { -360, -6.283185307179586, 2.4492935982947064e-16, -1.7484555e-07 },
45 { -180, -3.141592653589793, -1.2246467991473532e-16, 8.7422777e-08 },
46 { -135, -2.356194490192345, -0.7071067811865476, 999 },
47 // { -90, -1.570796326794897, -1.0000000000000000, 999 },
48 { -45, -0.785398163397448, -0.7071067811865472, 999 },
49 { 0, 0.000000000000000, 0.0000000000000000, 999 },
50 { 30, 0.5235987755982989, 0.5000000000000000, 999 },
51 { 45, 0.785398163397448, 0.7071067811865472, 999 },
52 // { 60, 1.047197551196598, 0.8660254037844388, 999 },
53 { 90, 1.570796326794897, 1.0000000000000000, 999 },
54 // { 120, 2.094395102393195, 0.8660254037844389, 999 },
55 { 135, 2.356194490192345, 0.7071067811865476, 999 },
56 { 150, 2.617993877991494, 0.5000000000000003, 999 },
57 { 180, 3.141592653589793, 1.2246467991473532e-16, -8.7422777e-08 },
58 { 270, 4.712388980384690, -1.0000000000000000, 999 },
59 { 360, 6.283185307179586, -2.4492935982947064e-16, 1.7484555e-07 },
60 };
61
62 static const struct {
63 int angle;
64 double x;
65 double y;
66 float fy;
67 } cos_angles[] = {
68 { -180, -3.141592653589793, -1.0000000000000000, 999 },
69 { -135, -2.356194490192345, -0.7071067811865476, 999 },
70 // { -90, -1.5707963267948966, 6.123233995736766e-17, -4.3711388e-08 },
71 // { -90, -1.5707963267948968, -1.6081226496766366e-16, -4.3711388e-08 },
72 { -45, -0.785398163397448, 0.7071067811865478, 999 },
73 { 0, 0.000000000000000, 1.0000000000000000, 999 },
74 { 30, 0.5235987755982989, 0.8660254037844386, 999 },
75 { 45, 0.785398163397448, 0.7071067811865478, 999 },
76 // { 60, 1.0471975511965976, 0.5000000000000001, 999 },
77 // { 60, 1.0471975511965979, 0.4999999999999999, 999 },
78 { 90, 1.570796326794897, -3.8285686989269494e-16, -4.3711388e-08 },
79 // { 120, 2.0943951023931953, -0.4999999999999998, 999 },
80 // { 120, 2.0943951023931957, -0.5000000000000002, 999 },
81 { 135, 2.356194490192345, -0.7071067811865476, 999 },
82 { 150, 2.617993877991494, -0.8660254037844386, 999 },
83 { 180, 3.141592653589793, -1.0000000000000000, 999 },
84 { 270, 4.712388980384690, -1.8369701987210297e-16, 1.1924881e-08 },
85 { 360, 6.283185307179586, 1.0000000000000000, 999 },
86 };
87
88 /*
89 * sincosl(3)
90 */
91 ATF_TC(sincosl_angles);
ATF_TC_HEAD(sincosl_angles,tc)92 ATF_TC_HEAD(sincosl_angles, tc)
93 {
94 atf_tc_set_md_var(tc, "descr", "Test some selected angles");
95 }
96
ATF_TC_BODY(sincosl_angles,tc)97 ATF_TC_BODY(sincosl_angles, tc)
98 {
99 /*
100 * XXX The given data is for double, so take that
101 * into account and expect less precise results..
102 */
103 const long double eps = DBL_EPSILON;
104 size_t i;
105
106 ATF_CHECK(__arraycount(sin_angles) == __arraycount(cos_angles));
107
108 for (i = 0; i < __arraycount(sin_angles); i++) {
109 ATF_CHECK_MSG(sin_angles[i].angle == cos_angles[i].angle,
110 "%zu %d %d", i, sin_angles[i].angle, cos_angles[i].angle);
111 int deg = sin_angles[i].angle;
112 ATF_CHECK_MSG(sin_angles[i].x == cos_angles[i].x,
113 "%zu %g %g", i, sin_angles[i].x, cos_angles[i].x);
114 long double theta = sin_angles[i].x;
115 long double sin_theta = sin_angles[i].y;
116 long double cos_theta = cos_angles[i].y;
117 long double s, c;
118
119 sincosl(theta, &s, &c);
120
121 if (fabsl((s - sin_theta)/sin_theta) > eps) {
122 atf_tc_fail_nonfatal("sin(%d deg = %.17Lg) = %.17Lg"
123 " != %.17Lg",
124 deg, theta, s, sin_theta);
125 }
126 if (fabsl((c - cos_theta)/cos_theta) > eps) {
127 atf_tc_fail_nonfatal("cos(%d deg = %.17Lg) = %.17Lg"
128 " != %.17Lg",
129 deg, theta, c, cos_theta);
130 }
131 }
132 }
133
134 ATF_TC(sincosl_nan);
ATF_TC_HEAD(sincosl_nan,tc)135 ATF_TC_HEAD(sincosl_nan, tc)
136 {
137 atf_tc_set_md_var(tc, "descr", "Test sincosl(NaN) == (NaN, NaN)");
138 }
139
ATF_TC_BODY(sincosl_nan,tc)140 ATF_TC_BODY(sincosl_nan, tc)
141 {
142 const long double x = 0.0L / 0.0L;
143 long double s, c;
144
145 sincosl(x, &s, &c);
146 ATF_CHECK(isnan(x) && isnan(s) && isnan(c));
147 }
148
149 ATF_TC(sincosl_inf_neg);
ATF_TC_HEAD(sincosl_inf_neg,tc)150 ATF_TC_HEAD(sincosl_inf_neg, tc)
151 {
152 atf_tc_set_md_var(tc, "descr", "Test sincosl(-Inf) == (NaN, NaN)");
153 }
154
ATF_TC_BODY(sincosl_inf_neg,tc)155 ATF_TC_BODY(sincosl_inf_neg, tc)
156 {
157 const long double x = -1.0L / 0.0L;
158 long double s, c;
159
160 sincosl(x, &s, &c);
161 ATF_CHECK(isnan(s) && isnan(c));
162 }
163
164 ATF_TC(sincosl_inf_pos);
ATF_TC_HEAD(sincosl_inf_pos,tc)165 ATF_TC_HEAD(sincosl_inf_pos, tc)
166 {
167 atf_tc_set_md_var(tc, "descr", "Test sincosl(+Inf) == (NaN, NaN)");
168 }
169
ATF_TC_BODY(sincosl_inf_pos,tc)170 ATF_TC_BODY(sincosl_inf_pos, tc)
171 {
172 const long double x = 1.0L / 0.0L;
173 long double s, c;
174
175 sincosl(x, &s, &c);
176 ATF_CHECK(isnan(s) && isnan(c));
177 }
178
179
180 ATF_TC(sincosl_zero_neg);
ATF_TC_HEAD(sincosl_zero_neg,tc)181 ATF_TC_HEAD(sincosl_zero_neg, tc)
182 {
183 atf_tc_set_md_var(tc, "descr", "Test sincosl(-0.0) == (0.0, 1.0)");
184 }
185
ATF_TC_BODY(sincosl_zero_neg,tc)186 ATF_TC_BODY(sincosl_zero_neg, tc)
187 {
188 const long double x = -0.0L;
189 long double s, c;
190
191 sincosl(x, &s, &c);
192 ATF_CHECK(s == 0.0 && c == 1.0);
193 }
194
195 ATF_TC(sincosl_zero_pos);
ATF_TC_HEAD(sincosl_zero_pos,tc)196 ATF_TC_HEAD(sincosl_zero_pos, tc)
197 {
198 atf_tc_set_md_var(tc, "descr", "Test sincosl(+0.0) == (0.0, 1.0)");
199 }
200
ATF_TC_BODY(sincosl_zero_pos,tc)201 ATF_TC_BODY(sincosl_zero_pos, tc)
202 {
203 const long double x = 0.0L;
204 long double s, c;
205
206 sincosl(x, &s, &c);
207 ATF_CHECK(s == 0.0 && c == 1.0);
208 }
209
210 /*
211 * sincos(3)
212 */
213 ATF_TC(sincos_angles);
ATF_TC_HEAD(sincos_angles,tc)214 ATF_TC_HEAD(sincos_angles, tc)
215 {
216 atf_tc_set_md_var(tc, "descr", "Test some selected angles");
217 }
218
ATF_TC_BODY(sincos_angles,tc)219 ATF_TC_BODY(sincos_angles, tc)
220 {
221 const double eps = DBL_EPSILON;
222 size_t i;
223
224 for (i = 0; i < __arraycount(sin_angles); i++) {
225 ATF_CHECK_MSG(sin_angles[i].angle == cos_angles[i].angle,
226 "%zu %d %d", i, sin_angles[i].angle, cos_angles[i].angle);
227 int deg = sin_angles[i].angle;
228 ATF_CHECK_MSG(sin_angles[i].x == cos_angles[i].x,
229 "%zu %g %g", i, sin_angles[i].x, cos_angles[i].x);
230 double theta = sin_angles[i].x;
231 double sin_theta = sin_angles[i].y;
232 double cos_theta = cos_angles[i].y;
233 double s, c;
234
235 sincos(theta, &s, &c);
236
237 if (fabs((s - sin_theta)/sin_theta) > eps) {
238 atf_tc_fail_nonfatal("sin(%d deg = %.17g) = %.17g"
239 " != %.17g",
240 deg, theta, s, sin_theta);
241 }
242 if (fabs((c - cos_theta)/cos_theta) > eps) {
243 atf_tc_fail_nonfatal("cos(%d deg = %.17g) = %.17g"
244 " != %.17g",
245 deg, theta, c, cos_theta);
246 }
247 }
248 }
249
250 ATF_TC(sincos_nan);
ATF_TC_HEAD(sincos_nan,tc)251 ATF_TC_HEAD(sincos_nan, tc)
252 {
253 atf_tc_set_md_var(tc, "descr", "Test sincos(NaN) == (NaN, NaN)");
254 }
255
ATF_TC_BODY(sincos_nan,tc)256 ATF_TC_BODY(sincos_nan, tc)
257 {
258 const double x = 0.0L / 0.0L;
259 double s, c;
260
261 sincos(x, &s, &c);
262 ATF_CHECK(isnan(x) && isnan(s) && isnan(c));
263 }
264
265 ATF_TC(sincos_inf_neg);
ATF_TC_HEAD(sincos_inf_neg,tc)266 ATF_TC_HEAD(sincos_inf_neg, tc)
267 {
268 atf_tc_set_md_var(tc, "descr", "Test sincos(-Inf) == (NaN, NaN)");
269 }
270
ATF_TC_BODY(sincos_inf_neg,tc)271 ATF_TC_BODY(sincos_inf_neg, tc)
272 {
273 const double x = -1.0L / 0.0L;
274 double s, c;
275
276 sincos(x, &s, &c);
277 ATF_CHECK(isnan(s) && isnan(c));
278 }
279
280 ATF_TC(sincos_inf_pos);
ATF_TC_HEAD(sincos_inf_pos,tc)281 ATF_TC_HEAD(sincos_inf_pos, tc)
282 {
283 atf_tc_set_md_var(tc, "descr", "Test sincos(+Inf) == (NaN, NaN)");
284 }
285
ATF_TC_BODY(sincos_inf_pos,tc)286 ATF_TC_BODY(sincos_inf_pos, tc)
287 {
288 const double x = 1.0L / 0.0L;
289 double s, c;
290
291 sincos(x, &s, &c);
292 ATF_CHECK(isnan(s) && isnan(c));
293 }
294
295
296 ATF_TC(sincos_zero_neg);
ATF_TC_HEAD(sincos_zero_neg,tc)297 ATF_TC_HEAD(sincos_zero_neg, tc)
298 {
299 atf_tc_set_md_var(tc, "descr", "Test sincos(-0.0) == (0.0, 1.0)");
300 }
301
ATF_TC_BODY(sincos_zero_neg,tc)302 ATF_TC_BODY(sincos_zero_neg, tc)
303 {
304 const double x = -0.0L;
305 double s, c;
306
307 sincos(x, &s, &c);
308 ATF_CHECK(s == 0 && c == 1.0);
309 }
310
311 ATF_TC(sincos_zero_pos);
ATF_TC_HEAD(sincos_zero_pos,tc)312 ATF_TC_HEAD(sincos_zero_pos, tc)
313 {
314 atf_tc_set_md_var(tc, "descr", "Test cos(+0.0) == (0.0, 1.0)");
315 }
316
ATF_TC_BODY(sincos_zero_pos,tc)317 ATF_TC_BODY(sincos_zero_pos, tc)
318 {
319 const double x = 0.0L;
320 double s, c;
321
322 sincos(x, &s, &c);
323 ATF_CHECK(s == 0 && c == 1.0);
324 }
325
326 /*
327 * sincosf(3)
328 */
329 ATF_TC(sincosf_angles);
ATF_TC_HEAD(sincosf_angles,tc)330 ATF_TC_HEAD(sincosf_angles, tc)
331 {
332 atf_tc_set_md_var(tc, "descr", "Test some selected angles");
333 }
334
ATF_TC_BODY(sincosf_angles,tc)335 ATF_TC_BODY(sincosf_angles, tc)
336 {
337 const float eps = FLT_EPSILON;
338 size_t i;
339
340 for (i = 0; i < __arraycount(sin_angles); i++) {
341 ATF_CHECK_MSG(sin_angles[i].angle == cos_angles[i].angle,
342 "%zu %d %d", i, sin_angles[i].angle, cos_angles[i].angle);
343 int deg = sin_angles[i].angle;
344 ATF_CHECK_MSG(sin_angles[i].x == cos_angles[i].x,
345 "%zu %g %g", i, sin_angles[i].x, cos_angles[i].x);
346 float theta = sin_angles[i].x;
347 float sin_theta = sin_angles[i].fy;
348 float cos_theta = cos_angles[i].fy;
349 float s, c;
350
351 sincosf(theta, &s, &c);
352 if (cos_theta == 999)
353 cos_theta = cos_angles[i].y;
354 if (sin_theta == 999)
355 sin_theta = sin_angles[i].y;
356
357 if (fabs((s - sin_theta)/sin_theta) > eps) {
358 atf_tc_fail_nonfatal("sin(%d deg = %.8g) = %.8g"
359 " != %.8g",
360 deg, theta, s, sin_theta);
361 }
362 if (fabs((c - cos_theta)/cos_theta) > eps) {
363 atf_tc_fail_nonfatal("cos(%d deg = %.8g) = %.8g"
364 " != %.8g",
365 deg, theta, c, cos_theta);
366 }
367 }
368 }
369
370 ATF_TC(sincosf_nan);
ATF_TC_HEAD(sincosf_nan,tc)371 ATF_TC_HEAD(sincosf_nan, tc)
372 {
373 atf_tc_set_md_var(tc, "descr", "Test cosf(NaN) == (NaN, NaN)");
374 }
375
ATF_TC_BODY(sincosf_nan,tc)376 ATF_TC_BODY(sincosf_nan, tc)
377 {
378 const float x = 0.0L / 0.0L;
379 float s, c;
380
381 sincosf(x, &s, &c);
382 ATF_CHECK(isnan(x) && isnan(s) && isnan(c));
383 }
384
385 ATF_TC(sincosf_inf_neg);
ATF_TC_HEAD(sincosf_inf_neg,tc)386 ATF_TC_HEAD(sincosf_inf_neg, tc)
387 {
388 atf_tc_set_md_var(tc, "descr", "Test cosf(-Inf) == (NaN, NaN)");
389 }
390
ATF_TC_BODY(sincosf_inf_neg,tc)391 ATF_TC_BODY(sincosf_inf_neg, tc)
392 {
393 const float x = -1.0L / 0.0L;
394 float s, c;
395
396 sincosf(x, &s, &c);
397 ATF_CHECK(isnan(s) && isnan(c));
398
399 }
400
401 ATF_TC(sincosf_inf_pos);
ATF_TC_HEAD(sincosf_inf_pos,tc)402 ATF_TC_HEAD(sincosf_inf_pos, tc)
403 {
404 atf_tc_set_md_var(tc, "descr", "Test sincosf(+Inf) == (NaN, NaN)");
405 }
406
ATF_TC_BODY(sincosf_inf_pos,tc)407 ATF_TC_BODY(sincosf_inf_pos, tc)
408 {
409 const float x = 1.0L / 0.0L;
410 float s, c;
411
412 sincosf(x, &s, &c);
413 ATF_CHECK(isnan(s) && isnan(c));
414 }
415
416
417 ATF_TC(sincosf_zero_neg);
ATF_TC_HEAD(sincosf_zero_neg,tc)418 ATF_TC_HEAD(sincosf_zero_neg, tc)
419 {
420 atf_tc_set_md_var(tc, "descr", "Test sincosf(-0.0) == (0.0, 1.0)");
421 }
422
ATF_TC_BODY(sincosf_zero_neg,tc)423 ATF_TC_BODY(sincosf_zero_neg, tc)
424 {
425 const float x = -0.0L;
426 float s, c;
427
428 sincosf(x, &s, &c);
429
430 ATF_CHECK(s == 0.0 && c == 1.0);
431 }
432
433 ATF_TC(sincosf_zero_pos);
ATF_TC_HEAD(sincosf_zero_pos,tc)434 ATF_TC_HEAD(sincosf_zero_pos, tc)
435 {
436 atf_tc_set_md_var(tc, "descr", "Test sincosf(+0.0) == (0.0, 1.0)");
437 }
438
ATF_TC_BODY(sincosf_zero_pos,tc)439 ATF_TC_BODY(sincosf_zero_pos, tc)
440 {
441 const float x = 0.0L;
442
443 float s, c;
444
445 sincosf(x, &s, &c);
446
447 ATF_CHECK(s == 0 && c == 1.0);
448 }
449
ATF_TP_ADD_TCS(tp)450 ATF_TP_ADD_TCS(tp)
451 {
452
453 ATF_TP_ADD_TC(tp, sincosl_angles);
454 ATF_TP_ADD_TC(tp, sincosl_nan);
455 ATF_TP_ADD_TC(tp, sincosl_inf_neg);
456 ATF_TP_ADD_TC(tp, sincosl_inf_pos);
457 ATF_TP_ADD_TC(tp, sincosl_zero_neg);
458 ATF_TP_ADD_TC(tp, sincosl_zero_pos);
459
460 ATF_TP_ADD_TC(tp, sincos_angles);
461 ATF_TP_ADD_TC(tp, sincos_nan);
462 ATF_TP_ADD_TC(tp, sincos_inf_neg);
463 ATF_TP_ADD_TC(tp, sincos_inf_pos);
464 ATF_TP_ADD_TC(tp, sincos_zero_neg);
465 ATF_TP_ADD_TC(tp, sincos_zero_pos);
466
467 ATF_TP_ADD_TC(tp, sincosf_angles);
468 ATF_TP_ADD_TC(tp, sincosf_nan);
469 ATF_TP_ADD_TC(tp, sincosf_inf_neg);
470 ATF_TP_ADD_TC(tp, sincosf_inf_pos);
471 ATF_TP_ADD_TC(tp, sincosf_zero_neg);
472 ATF_TP_ADD_TC(tp, sincosf_zero_pos);
473
474 return atf_no_error();
475 }
476