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
38static 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
62static 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 */
91ATF_TC(sincosl_angles);
92ATF_TC_HEAD(sincosl_angles, tc)
93{
94	atf_tc_set_md_var(tc, "descr", "Test some selected angles");
95}
96
97ATF_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
134ATF_TC(sincosl_nan);
135ATF_TC_HEAD(sincosl_nan, tc)
136{
137	atf_tc_set_md_var(tc, "descr", "Test sincosl(NaN) == (NaN, NaN)");
138}
139
140ATF_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
149ATF_TC(sincosl_inf_neg);
150ATF_TC_HEAD(sincosl_inf_neg, tc)
151{
152	atf_tc_set_md_var(tc, "descr", "Test sincosl(-Inf) == (NaN, NaN)");
153}
154
155ATF_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
164ATF_TC(sincosl_inf_pos);
165ATF_TC_HEAD(sincosl_inf_pos, tc)
166{
167	atf_tc_set_md_var(tc, "descr", "Test sincosl(+Inf) == (NaN, NaN)");
168}
169
170ATF_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
180ATF_TC(sincosl_zero_neg);
181ATF_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
186ATF_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
195ATF_TC(sincosl_zero_pos);
196ATF_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
201ATF_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 */
213ATF_TC(sincos_angles);
214ATF_TC_HEAD(sincos_angles, tc)
215{
216	atf_tc_set_md_var(tc, "descr", "Test some selected angles");
217}
218
219ATF_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
250ATF_TC(sincos_nan);
251ATF_TC_HEAD(sincos_nan, tc)
252{
253	atf_tc_set_md_var(tc, "descr", "Test sincos(NaN) == (NaN, NaN)");
254}
255
256ATF_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
265ATF_TC(sincos_inf_neg);
266ATF_TC_HEAD(sincos_inf_neg, tc)
267{
268	atf_tc_set_md_var(tc, "descr", "Test sincos(-Inf) == (NaN, NaN)");
269}
270
271ATF_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
280ATF_TC(sincos_inf_pos);
281ATF_TC_HEAD(sincos_inf_pos, tc)
282{
283	atf_tc_set_md_var(tc, "descr", "Test sincos(+Inf) == (NaN, NaN)");
284}
285
286ATF_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
296ATF_TC(sincos_zero_neg);
297ATF_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
302ATF_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
311ATF_TC(sincos_zero_pos);
312ATF_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
317ATF_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 */
329ATF_TC(sincosf_angles);
330ATF_TC_HEAD(sincosf_angles, tc)
331{
332	atf_tc_set_md_var(tc, "descr", "Test some selected angles");
333}
334
335ATF_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
370ATF_TC(sincosf_nan);
371ATF_TC_HEAD(sincosf_nan, tc)
372{
373	atf_tc_set_md_var(tc, "descr", "Test cosf(NaN) == (NaN, NaN)");
374}
375
376ATF_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
385ATF_TC(sincosf_inf_neg);
386ATF_TC_HEAD(sincosf_inf_neg, tc)
387{
388	atf_tc_set_md_var(tc, "descr", "Test cosf(-Inf) == (NaN, NaN)");
389}
390
391ATF_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
401ATF_TC(sincosf_inf_pos);
402ATF_TC_HEAD(sincosf_inf_pos, tc)
403{
404	atf_tc_set_md_var(tc, "descr", "Test sincosf(+Inf) == (NaN, NaN)");
405}
406
407ATF_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
417ATF_TC(sincosf_zero_neg);
418ATF_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
423ATF_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
433ATF_TC(sincosf_zero_pos);
434ATF_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
439ATF_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
450ATF_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