xref: /netbsd-src/tests/lib/libm/t_sincos.c (revision 49e81414d02e4ec5e7ea50e8f17dc05f6fc17a29)
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