xref: /netbsd-src/tests/lib/libm/t_sincos.c (revision afab4e300d3a9fb07dd8c80daf53d0feb3345706)
1 /* $NetBSD: t_sincos.c,v 1.1 2022/08/27 08:31:58 christos 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 #ifdef __HAVE_LONG_DOUBLE
89 /*
90  * sincosl(3)
91  */
92 ATF_TC(sincosl_angles);
93 ATF_TC_HEAD(sincosl_angles, tc)
94 {
95 	atf_tc_set_md_var(tc, "descr", "Test some selected angles");
96 }
97 
98 ATF_TC_BODY(sincosl_angles, tc)
99 {
100 	/*
101 	 * XXX The given data is for double, so take that
102 	 * into account and expect less precise results..
103 	 */
104 	const long double eps = DBL_EPSILON;
105 	size_t i;
106 
107 	ATF_CHECK(__arraycount(sin_angles) == __arraycount(cos_angles));
108 
109 	for (i = 0; i < __arraycount(sin_angles); i++) {
110 		ATF_CHECK_MSG(sin_angles[i].angle == cos_angles[i].angle,
111 		    "%zu %d %d", i, sin_angles[i].angle, cos_angles[i].angle);
112 		int deg = sin_angles[i].angle;
113 		ATF_CHECK_MSG(sin_angles[i].x == cos_angles[i].x,
114 		    "%zu %g %g", i, sin_angles[i].x, cos_angles[i].x);
115 		long double theta = sin_angles[i].x;
116 		long double sin_theta = sin_angles[i].y;
117 		long double cos_theta = cos_angles[i].y;
118 		long double s, c;
119 
120 		sincosl(theta, &s, &c);
121 
122 		if (fabsl((s - sin_theta)/sin_theta) > eps) {
123 			atf_tc_fail_nonfatal("sin(%d deg = %.17Lg) = %.17Lg"
124 			    " != %.17Lg",
125 			    deg, theta, s, sin_theta);
126 		}
127 		if (fabsl((c - cos_theta)/cos_theta) > eps) {
128 			atf_tc_fail_nonfatal("cos(%d deg = %.17Lg) = %.17Lg"
129 			    " != %.17Lg",
130 			    deg, theta, c, cos_theta);
131 		}
132 	}
133 }
134 
135 ATF_TC(sincosl_nan);
136 ATF_TC_HEAD(sincosl_nan, tc)
137 {
138 	atf_tc_set_md_var(tc, "descr", "Test sincosl(NaN) == (NaN, NaN)");
139 }
140 
141 ATF_TC_BODY(sincosl_nan, tc)
142 {
143 	const long double x = 0.0L / 0.0L;
144 	long double s, c;
145 
146 	sincosl(x, &s, &c);
147 	ATF_CHECK(isnan(x) && isnan(s) && isnan(c));
148 }
149 
150 ATF_TC(sincosl_inf_neg);
151 ATF_TC_HEAD(sincosl_inf_neg, tc)
152 {
153 	atf_tc_set_md_var(tc, "descr", "Test sincosl(-Inf) == (NaN, NaN)");
154 }
155 
156 ATF_TC_BODY(sincosl_inf_neg, tc)
157 {
158 	const long double x = -1.0L / 0.0L;
159 	long double s, c;
160 
161 	sincosl(x, &s, &c);
162 	ATF_CHECK(isnan(s) && isnan(c));
163 }
164 
165 ATF_TC(sincosl_inf_pos);
166 ATF_TC_HEAD(sincosl_inf_pos, tc)
167 {
168 	atf_tc_set_md_var(tc, "descr", "Test sincosl(+Inf) == (NaN, NaN)");
169 }
170 
171 ATF_TC_BODY(sincosl_inf_pos, tc)
172 {
173 	const long double x = 1.0L / 0.0L;
174 	long double s, c;
175 
176 	sincosl(x, &s, &c);
177 	ATF_CHECK(isnan(s) && isnan(c));
178 }
179 
180 
181 ATF_TC(sincosl_zero_neg);
182 ATF_TC_HEAD(sincosl_zero_neg, tc)
183 {
184 	atf_tc_set_md_var(tc, "descr", "Test sincosl(-0.0) == (0.0, 1.0)");
185 }
186 
187 ATF_TC_BODY(sincosl_zero_neg, tc)
188 {
189 	const long double x = -0.0L;
190 	long double s, c;
191 
192 	sincosl(x, &s, &c);
193 	ATF_CHECK(s == 0.0 && c == 1.0);
194 }
195 
196 ATF_TC(sincosl_zero_pos);
197 ATF_TC_HEAD(sincosl_zero_pos, tc)
198 {
199 	atf_tc_set_md_var(tc, "descr", "Test sincosl(+0.0) == (0.0, 1.0)");
200 }
201 
202 ATF_TC_BODY(sincosl_zero_pos, tc)
203 {
204 	const long double x = 0.0L;
205 	long double s, c;
206 
207 	sincosl(x, &s, &c);
208 	ATF_CHECK(s == 0.0 && c == 1.0);
209 }
210 #endif
211 
212 /*
213  * sincos(3)
214  */
215 ATF_TC(sincos_angles);
216 ATF_TC_HEAD(sincos_angles, tc)
217 {
218 	atf_tc_set_md_var(tc, "descr", "Test some selected angles");
219 }
220 
221 ATF_TC_BODY(sincos_angles, tc)
222 {
223 	const double eps = DBL_EPSILON;
224 	size_t i;
225 
226 	for (i = 0; i < __arraycount(sin_angles); i++) {
227 		ATF_CHECK_MSG(sin_angles[i].angle == cos_angles[i].angle,
228 		    "%zu %d %d", i, sin_angles[i].angle, cos_angles[i].angle);
229 		int deg = sin_angles[i].angle;
230 		ATF_CHECK_MSG(sin_angles[i].x == cos_angles[i].x,
231 		    "%zu %g %g", i, sin_angles[i].x, cos_angles[i].x);
232 		double theta = sin_angles[i].x;
233 		double sin_theta = sin_angles[i].y;
234 		double cos_theta = cos_angles[i].y;
235 		double s, c;
236 
237 		sincos(theta, &s, &c);
238 
239 		if (fabs((s - sin_theta)/sin_theta) > eps) {
240 			atf_tc_fail_nonfatal("sin(%d deg = %.17g) = %.17g"
241 			    " != %.17g",
242 			    deg, theta, s, sin_theta);
243 		}
244 		if (fabs((c - cos_theta)/cos_theta) > eps) {
245 			atf_tc_fail_nonfatal("cos(%d deg = %.17g) = %.17g"
246 			    " != %.17g",
247 			    deg, theta, c, cos_theta);
248 		}
249 	}
250 }
251 
252 ATF_TC(sincos_nan);
253 ATF_TC_HEAD(sincos_nan, tc)
254 {
255 	atf_tc_set_md_var(tc, "descr", "Test sincos(NaN) == (NaN, NaN)");
256 }
257 
258 ATF_TC_BODY(sincos_nan, tc)
259 {
260 	const double x = 0.0L / 0.0L;
261 	double s, c;
262 
263 	sincos(x, &s, &c);
264 	ATF_CHECK(isnan(x) && isnan(s) && isnan(c));
265 }
266 
267 ATF_TC(sincos_inf_neg);
268 ATF_TC_HEAD(sincos_inf_neg, tc)
269 {
270 	atf_tc_set_md_var(tc, "descr", "Test sincos(-Inf) == (NaN, NaN)");
271 }
272 
273 ATF_TC_BODY(sincos_inf_neg, tc)
274 {
275 	const double x = -1.0L / 0.0L;
276 	double s, c;
277 
278 	sincos(x, &s, &c);
279 	ATF_CHECK(isnan(s) && isnan(c));
280 }
281 
282 ATF_TC(sincos_inf_pos);
283 ATF_TC_HEAD(sincos_inf_pos, tc)
284 {
285 	atf_tc_set_md_var(tc, "descr", "Test sincos(+Inf) == (NaN, NaN)");
286 }
287 
288 ATF_TC_BODY(sincos_inf_pos, tc)
289 {
290 	const double x = 1.0L / 0.0L;
291 	double s, c;
292 
293 	sincos(x, &s, &c);
294 	ATF_CHECK(isnan(s) && isnan(c));
295 }
296 
297 
298 ATF_TC(sincos_zero_neg);
299 ATF_TC_HEAD(sincos_zero_neg, tc)
300 {
301 	atf_tc_set_md_var(tc, "descr", "Test sincos(-0.0) == (0.0, 1.0)");
302 }
303 
304 ATF_TC_BODY(sincos_zero_neg, tc)
305 {
306 	const double x = -0.0L;
307 	double s, c;
308 
309 	sincos(x, &s, &c);
310 	ATF_CHECK(s == 0 && c == 1.0);
311 }
312 
313 ATF_TC(sincos_zero_pos);
314 ATF_TC_HEAD(sincos_zero_pos, tc)
315 {
316 	atf_tc_set_md_var(tc, "descr", "Test cos(+0.0) == (0.0, 1.0)");
317 }
318 
319 ATF_TC_BODY(sincos_zero_pos, tc)
320 {
321 	const double x = 0.0L;
322 	double s, c;
323 
324 	sincos(x, &s, &c);
325 	ATF_CHECK(s == 0 && c == 1.0);
326 }
327 
328 /*
329  * sincosf(3)
330  */
331 ATF_TC(sincosf_angles);
332 ATF_TC_HEAD(sincosf_angles, tc)
333 {
334 	atf_tc_set_md_var(tc, "descr", "Test some selected angles");
335 }
336 
337 ATF_TC_BODY(sincosf_angles, tc)
338 {
339 	const float eps = FLT_EPSILON;
340 	size_t i;
341 
342 	for (i = 0; i < __arraycount(sin_angles); i++) {
343 		ATF_CHECK_MSG(sin_angles[i].angle == cos_angles[i].angle,
344 		    "%zu %d %d", i, sin_angles[i].angle, cos_angles[i].angle);
345 		int deg = sin_angles[i].angle;
346 		ATF_CHECK_MSG(sin_angles[i].x == cos_angles[i].x,
347 		    "%zu %g %g", i, sin_angles[i].x, cos_angles[i].x);
348 		float theta = sin_angles[i].x;
349 		float sin_theta = sin_angles[i].fy;
350 		float cos_theta = cos_angles[i].fy;
351 		float s, c;
352 
353 		sincosf(theta, &s, &c);
354 		if (cos_theta == 999)
355 			cos_theta = cos_angles[i].y;
356 		if (sin_theta == 999)
357 			sin_theta = sin_angles[i].y;
358 
359 		if (fabs((s - sin_theta)/sin_theta) > eps) {
360 			atf_tc_fail_nonfatal("sin(%d deg = %.8g) = %.8g"
361 			    " != %.8g",
362 			    deg, theta, s, sin_theta);
363 		}
364 		if (fabs((c - cos_theta)/cos_theta) > eps) {
365 			atf_tc_fail_nonfatal("cos(%d deg = %.8g) = %.8g"
366 			    " != %.8g",
367 			    deg, theta, c, cos_theta);
368 		}
369 	}
370 }
371 
372 ATF_TC(sincosf_nan);
373 ATF_TC_HEAD(sincosf_nan, tc)
374 {
375 	atf_tc_set_md_var(tc, "descr", "Test cosf(NaN) == (NaN, NaN)");
376 }
377 
378 ATF_TC_BODY(sincosf_nan, tc)
379 {
380 	const float x = 0.0L / 0.0L;
381 	float s, c;
382 
383 	sincosf(x, &s, &c);
384 	ATF_CHECK(isnan(x) && isnan(s) && isnan(c));
385 }
386 
387 ATF_TC(sincosf_inf_neg);
388 ATF_TC_HEAD(sincosf_inf_neg, tc)
389 {
390 	atf_tc_set_md_var(tc, "descr", "Test cosf(-Inf) == (NaN, NaN)");
391 }
392 
393 ATF_TC_BODY(sincosf_inf_neg, tc)
394 {
395 	const float x = -1.0L / 0.0L;
396 	float s, c;
397 
398 	sincosf(x, &s, &c);
399 	ATF_CHECK(isnan(s) && isnan(c));
400 
401 }
402 
403 ATF_TC(sincosf_inf_pos);
404 ATF_TC_HEAD(sincosf_inf_pos, tc)
405 {
406 	atf_tc_set_md_var(tc, "descr", "Test sincosf(+Inf) == (NaN, NaN)");
407 }
408 
409 ATF_TC_BODY(sincosf_inf_pos, tc)
410 {
411 	const float x = 1.0L / 0.0L;
412 	float s, c;
413 
414 	sincosf(x, &s, &c);
415 	ATF_CHECK(isnan(s) && isnan(c));
416 }
417 
418 
419 ATF_TC(sincosf_zero_neg);
420 ATF_TC_HEAD(sincosf_zero_neg, tc)
421 {
422 	atf_tc_set_md_var(tc, "descr", "Test sincosf(-0.0) == (0.0, 1.0)");
423 }
424 
425 ATF_TC_BODY(sincosf_zero_neg, tc)
426 {
427 	const float x = -0.0L;
428 	float s, c;
429 
430 	sincosf(x, &s, &c);
431 
432 	ATF_CHECK(s == 0.0 && c == 1.0);
433 }
434 
435 ATF_TC(sincosf_zero_pos);
436 ATF_TC_HEAD(sincosf_zero_pos, tc)
437 {
438 	atf_tc_set_md_var(tc, "descr", "Test sincosf(+0.0) == (0.0, 1.0)");
439 }
440 
441 ATF_TC_BODY(sincosf_zero_pos, tc)
442 {
443 	const float x = 0.0L;
444 
445 	float s, c;
446 
447 	sincosf(x, &s, &c);
448 
449 	ATF_CHECK(s == 0 && c == 1.0);
450 }
451 
452 ATF_TP_ADD_TCS(tp)
453 {
454 #ifdef __HAVE_LONG_DOUBLE
455 	ATF_TP_ADD_TC(tp, sincosl_angles);
456 	ATF_TP_ADD_TC(tp, sincosl_nan);
457 	ATF_TP_ADD_TC(tp, sincosl_inf_neg);
458 	ATF_TP_ADD_TC(tp, sincosl_inf_pos);
459 	ATF_TP_ADD_TC(tp, sincosl_zero_neg);
460 	ATF_TP_ADD_TC(tp, sincosl_zero_pos);
461 #endif
462 
463 	ATF_TP_ADD_TC(tp, sincos_angles);
464 	ATF_TP_ADD_TC(tp, sincos_nan);
465 	ATF_TP_ADD_TC(tp, sincos_inf_neg);
466 	ATF_TP_ADD_TC(tp, sincos_inf_pos);
467 	ATF_TP_ADD_TC(tp, sincos_zero_neg);
468 	ATF_TP_ADD_TC(tp, sincos_zero_pos);
469 
470 	ATF_TP_ADD_TC(tp, sincosf_angles);
471 	ATF_TP_ADD_TC(tp, sincosf_nan);
472 	ATF_TP_ADD_TC(tp, sincosf_inf_neg);
473 	ATF_TP_ADD_TC(tp, sincosf_inf_pos);
474 	ATF_TP_ADD_TC(tp, sincosf_zero_neg);
475 	ATF_TP_ADD_TC(tp, sincosf_zero_pos);
476 
477 	return atf_no_error();
478 }
479