Home | History | Annotate | Line # | Download | only in libm
      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);
     92 ATF_TC_HEAD(sincosl_angles, tc)
     93 {
     94 	atf_tc_set_md_var(tc, "descr", "Test some selected angles");
     95 }
     96 
     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);
    135 ATF_TC_HEAD(sincosl_nan, tc)
    136 {
    137 	atf_tc_set_md_var(tc, "descr", "Test sincosl(NaN) == (NaN, NaN)");
    138 }
    139 
    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);
    150 ATF_TC_HEAD(sincosl_inf_neg, tc)
    151 {
    152 	atf_tc_set_md_var(tc, "descr", "Test sincosl(-Inf) == (NaN, NaN)");
    153 }
    154 
    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);
    165 ATF_TC_HEAD(sincosl_inf_pos, tc)
    166 {
    167 	atf_tc_set_md_var(tc, "descr", "Test sincosl(+Inf) == (NaN, NaN)");
    168 }
    169 
    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);
    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 
    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);
    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 
    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);
    214 ATF_TC_HEAD(sincos_angles, tc)
    215 {
    216 	atf_tc_set_md_var(tc, "descr", "Test some selected angles");
    217 }
    218 
    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);
    251 ATF_TC_HEAD(sincos_nan, tc)
    252 {
    253 	atf_tc_set_md_var(tc, "descr", "Test sincos(NaN) == (NaN, NaN)");
    254 }
    255 
    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);
    266 ATF_TC_HEAD(sincos_inf_neg, tc)
    267 {
    268 	atf_tc_set_md_var(tc, "descr", "Test sincos(-Inf) == (NaN, NaN)");
    269 }
    270 
    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);
    281 ATF_TC_HEAD(sincos_inf_pos, tc)
    282 {
    283 	atf_tc_set_md_var(tc, "descr", "Test sincos(+Inf) == (NaN, NaN)");
    284 }
    285 
    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);
    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 
    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);
    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 
    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);
    330 ATF_TC_HEAD(sincosf_angles, tc)
    331 {
    332 	atf_tc_set_md_var(tc, "descr", "Test some selected angles");
    333 }
    334 
    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);
    371 ATF_TC_HEAD(sincosf_nan, tc)
    372 {
    373 	atf_tc_set_md_var(tc, "descr", "Test cosf(NaN) == (NaN, NaN)");
    374 }
    375 
    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);
    386 ATF_TC_HEAD(sincosf_inf_neg, tc)
    387 {
    388 	atf_tc_set_md_var(tc, "descr", "Test cosf(-Inf) == (NaN, NaN)");
    389 }
    390 
    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);
    402 ATF_TC_HEAD(sincosf_inf_pos, tc)
    403 {
    404 	atf_tc_set_md_var(tc, "descr", "Test sincosf(+Inf) == (NaN, NaN)");
    405 }
    406 
    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);
    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 
    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);
    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 
    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 
    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