1/* $NetBSD: t_cbrt.c,v 1.5 2018/11/15 05:14:20 riastradh Exp $ */
2
3/*-
4 * Copyright (c) 2011 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.
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#include <sys/cdefs.h>
32__RCSID("$NetBSD: t_cbrt.c,v 1.5 2018/11/15 05:14:20 riastradh Exp $");
33
34#include <atf-c.h>
35#include <float.h>
36#include <math.h>
37#include <stdio.h>
38
39/*
40 * cbrt(3)
41 */
42ATF_TC(cbrt_nan);
43ATF_TC_HEAD(cbrt_nan, tc)
44{
45	atf_tc_set_md_var(tc, "descr", "Test cbrt(NaN) == NaN");
46}
47
48ATF_TC_BODY(cbrt_nan, tc)
49{
50	const double x = 0.0L / 0.0L;
51
52	ATF_CHECK(isnan(x) != 0);
53	ATF_CHECK(isnan(cbrt(x)) != 0);
54}
55
56ATF_TC(cbrt_pow);
57ATF_TC_HEAD(cbrt_pow, tc)
58{
59	atf_tc_set_md_var(tc, "descr", "Test cbrt(3) vs. pow(3)");
60}
61
62ATF_TC_BODY(cbrt_pow, tc)
63{
64	const double x[] = { 0.0, 0.005, 1.0, 99.0, 123.123, 9999.0 };
65	/* Neither cbrt nor pow is required to be correctly rounded.  */
66	const double eps = 2*DBL_EPSILON;
67	size_t i;
68
69	for (i = 0; i < __arraycount(x); i++) {
70		double x_cbrt = cbrt(x[i]);
71		double x_pow13 = pow(x[i], 1.0 / 3.0);
72		bool ok;
73
74		if (x[i] == 0) {
75			ok = (x_cbrt == x_pow13);
76		} else {
77			ok = (fabs((x_cbrt - x_pow13)/x_cbrt) <= eps);
78		}
79
80		if (!ok) {
81			atf_tc_fail_nonfatal("cbrt(%.17g) = %.17g != "
82			    "pow(%.17g, 1/3) = %.17g\n",
83			    x[i], x_cbrt, x[i], x_pow13);
84		}
85	}
86}
87
88ATF_TC(cbrt_inf_neg);
89ATF_TC_HEAD(cbrt_inf_neg, tc)
90{
91	atf_tc_set_md_var(tc, "descr", "Test cbrt(-Inf) == -Inf");
92}
93
94ATF_TC_BODY(cbrt_inf_neg, tc)
95{
96	const double x = -1.0L / 0.0L;
97	double y = cbrt(x);
98
99	ATF_CHECK(isinf(y) != 0);
100	ATF_CHECK(signbit(y) != 0);
101}
102
103ATF_TC(cbrt_inf_pos);
104ATF_TC_HEAD(cbrt_inf_pos, tc)
105{
106	atf_tc_set_md_var(tc, "descr", "Test cbrt(+Inf) == +Inf");
107}
108
109ATF_TC_BODY(cbrt_inf_pos, tc)
110{
111	const double x = 1.0L / 0.0L;
112	double y = cbrt(x);
113
114	ATF_CHECK(isinf(y) != 0);
115	ATF_CHECK(signbit(y) == 0);
116}
117
118ATF_TC(cbrt_zero_neg);
119ATF_TC_HEAD(cbrt_zero_neg, tc)
120{
121	atf_tc_set_md_var(tc, "descr", "Test cbrt(-0.0) == -0.0");
122}
123
124ATF_TC_BODY(cbrt_zero_neg, tc)
125{
126	const double x = -0.0L;
127	double y = cbrt(x);
128
129	if (fabs(y) > 0.0 || signbit(y) == 0)
130		atf_tc_fail_nonfatal("cbrt(-0.0) != -0.0");
131}
132
133ATF_TC(cbrt_zero_pos);
134ATF_TC_HEAD(cbrt_zero_pos, tc)
135{
136	atf_tc_set_md_var(tc, "descr", "Test cbrt(+0.0) == +0.0");
137}
138
139ATF_TC_BODY(cbrt_zero_pos, tc)
140{
141	const double x = 0.0L;
142	double y = cbrt(x);
143
144	if (fabs(y) > 0.0 || signbit(y) != 0)
145		atf_tc_fail_nonfatal("cbrt(+0.0) != +0.0");
146}
147
148/*
149 * cbrtf(3)
150 */
151ATF_TC(cbrtf_nan);
152ATF_TC_HEAD(cbrtf_nan, tc)
153{
154	atf_tc_set_md_var(tc, "descr", "Test cbrtf(NaN) == NaN");
155}
156
157ATF_TC_BODY(cbrtf_nan, tc)
158{
159	const float x = 0.0L / 0.0L;
160
161	ATF_CHECK(isnan(x) != 0);
162	ATF_CHECK(isnan(cbrtf(x)) != 0);
163}
164
165ATF_TC(cbrtf_powf);
166ATF_TC_HEAD(cbrtf_powf, tc)
167{
168	atf_tc_set_md_var(tc, "descr", "Test cbrtf(3) vs. powf(3)");
169}
170
171ATF_TC_BODY(cbrtf_powf, tc)
172{
173	const float x[] = { 0.0, 0.005, 1.0, 99.0, 123.123, 9999.0 };
174	/* Neither cbrt nor pow is required to be correctly rounded.  */
175	const float eps = 2*FLT_EPSILON;
176	size_t i;
177
178	for (i = 0; i < __arraycount(x); i++) {
179		float x_cbrt = cbrtf(x[i]);
180		float x_pow13 = powf(x[i], 1.0 / 3.0);
181		bool ok;
182
183		if (x[i] == 0) {
184			ok = (x_cbrt == x_pow13);
185		} else {
186			ok = (fabsf((x_cbrt - x_pow13)/x_cbrt) <= eps);
187		}
188
189		if (!ok) {
190			atf_tc_fail_nonfatal("cbrtf(%.9g) = %.9g. != "
191			    "powf(%.9g, 1/3) = %.9g\n",
192			    (double)x[i], (double)x_cbrt,
193			    (double)x[i], (double)x_pow13);
194		}
195	}
196}
197
198ATF_TC(cbrtf_inf_neg);
199ATF_TC_HEAD(cbrtf_inf_neg, tc)
200{
201	atf_tc_set_md_var(tc, "descr", "Test cbrtf(-Inf) == -Inf");
202}
203
204ATF_TC_BODY(cbrtf_inf_neg, tc)
205{
206	const float x = -1.0L / 0.0L;
207	float y = cbrtf(x);
208
209	ATF_CHECK(isinf(y) != 0);
210	ATF_CHECK(signbit(y) != 0);
211}
212
213ATF_TC(cbrtf_inf_pos);
214ATF_TC_HEAD(cbrtf_inf_pos, tc)
215{
216	atf_tc_set_md_var(tc, "descr", "Test cbrtf(+Inf) == +Inf");
217}
218
219ATF_TC_BODY(cbrtf_inf_pos, tc)
220{
221	const float x = 1.0L / 0.0L;
222	float y = cbrtf(x);
223
224	ATF_CHECK(isinf(y) != 0);
225	ATF_CHECK(signbit(y) == 0);
226}
227
228ATF_TC(cbrtf_zero_neg);
229ATF_TC_HEAD(cbrtf_zero_neg, tc)
230{
231	atf_tc_set_md_var(tc, "descr", "Test cbrtf(-0.0) == -0.0");
232}
233
234ATF_TC_BODY(cbrtf_zero_neg, tc)
235{
236	const float x = -0.0L;
237	float y = cbrtf(x);
238
239	if (fabsf(y) > 0.0 || signbit(y) == 0)
240		atf_tc_fail_nonfatal("cbrtf(-0.0) != -0.0");
241}
242
243ATF_TC(cbrtf_zero_pos);
244ATF_TC_HEAD(cbrtf_zero_pos, tc)
245{
246	atf_tc_set_md_var(tc, "descr", "Test cbrtf(+0.0) == +0.0");
247}
248
249ATF_TC_BODY(cbrtf_zero_pos, tc)
250{
251	const float x = 0.0L;
252	float y = cbrtf(x);
253
254	if (fabsf(y) > 0.0 || signbit(y) != 0)
255		atf_tc_fail_nonfatal("cbrtf(+0.0) != +0.0");
256}
257
258#if !defined(__FreeBSD__) || LDBL_PREC != 53
259/*
260 * cbrtl(3)
261 */
262ATF_TC(cbrtl_nan);
263ATF_TC_HEAD(cbrtl_nan, tc)
264{
265	atf_tc_set_md_var(tc, "descr", "Test cbrtl(NaN) == NaN");
266}
267
268ATF_TC_BODY(cbrtl_nan, tc)
269{
270	const long double x = 0.0L / 0.0L;
271
272	ATF_CHECK(isnan(x) != 0);
273	ATF_CHECK(isnan(cbrtl(x)) != 0);
274}
275
276ATF_TC(cbrtl_powl);
277ATF_TC_HEAD(cbrtl_powl, tc)
278{
279	atf_tc_set_md_var(tc, "descr", "Test cbrtl(3) vs. powl(3)");
280}
281
282ATF_TC_BODY(cbrtl_powl, tc)
283{
284	const long double x[] = { 0.0, 0.005, 1.0, 99.0, 123.123, 9999.0 };
285	/* Neither cbrt nor pow is required to be correctly rounded.  */
286	const long double eps = 2*LDBL_EPSILON;
287	size_t i;
288
289#if defined(__amd64__) && defined(__clang__) && __clang_major__ >= 7 && \
290    __clang_major__ < 10 && __FreeBSD_cc_version < 1300002
291	atf_tc_expect_fail("test fails with clang 7-9 - bug 234040");
292#endif
293	for (i = 0; i < __arraycount(x); i++) {
294		long double x_cbrt = cbrtl(x[i]);
295#ifdef __FreeBSD__
296		/*
297		 * NetBSD doesn't have a real powl/cbrtl implementation, they
298		 * just call the double version. On FreeBSD we have a real
299		 * powl implementation so we have to cast the second argument
300		 * to long double before dividing to get a more precise
301		 * approximation of 1/3.
302		 * TODO: upstream this diff.
303		 */
304		long double x_pow13 = powl(x[i], (long double)1.0 / 3.0);
305#else
306		long double x_pow13 = powl(x[i], 1.0 / 3.0);
307#endif
308		bool ok;
309
310		if (x[i] == 0) {
311			ok = (x_cbrt == x_pow13);
312		} else {
313			ok = (fabsl((x_cbrt - x_pow13)/x_cbrt) <= eps);
314		}
315
316		if (!ok) {
317			atf_tc_fail_nonfatal("cbrtl(%.35Lg) = %.35Lg != "
318			    "powl(%.35Lg, 1/3) = %.35Lg\n",
319			    x[i], x_cbrt, x[i], x_pow13);
320		}
321	}
322}
323
324ATF_TC(cbrtl_inf_neg);
325ATF_TC_HEAD(cbrtl_inf_neg, tc)
326{
327	atf_tc_set_md_var(tc, "descr", "Test cbrtl(-Inf) == -Inf");
328}
329
330ATF_TC_BODY(cbrtl_inf_neg, tc)
331{
332	const long double x = -1.0L / 0.0L;
333	long double y = cbrtl(x);
334
335	ATF_CHECK(isinf(y) != 0);
336	ATF_CHECK(signbit(y) != 0);
337}
338
339ATF_TC(cbrtl_inf_pos);
340ATF_TC_HEAD(cbrtl_inf_pos, tc)
341{
342	atf_tc_set_md_var(tc, "descr", "Test cbrtl(+Inf) == +Inf");
343}
344
345ATF_TC_BODY(cbrtl_inf_pos, tc)
346{
347	const long double x = 1.0L / 0.0L;
348	long double y = cbrtl(x);
349
350	ATF_CHECK(isinf(y) != 0);
351	ATF_CHECK(signbit(y) == 0);
352}
353
354ATF_TC(cbrtl_zero_neg);
355ATF_TC_HEAD(cbrtl_zero_neg, tc)
356{
357	atf_tc_set_md_var(tc, "descr", "Test cbrtl(-0.0) == -0.0");
358}
359
360ATF_TC_BODY(cbrtl_zero_neg, tc)
361{
362	const long double x = -0.0L;
363	long double y = cbrtl(x);
364
365	if (fabsl(y) > 0.0 || signbit(y) == 0)
366		atf_tc_fail_nonfatal("cbrtl(-0.0) != -0.0");
367}
368
369ATF_TC(cbrtl_zero_pos);
370ATF_TC_HEAD(cbrtl_zero_pos, tc)
371{
372	atf_tc_set_md_var(tc, "descr", "Test cbrtl(+0.0) == +0.0");
373}
374
375ATF_TC_BODY(cbrtl_zero_pos, tc)
376{
377	const long double x = 0.0L;
378	long double y = cbrtl(x);
379
380	if (fabsl(y) > 0.0 || signbit(y) != 0)
381		atf_tc_fail_nonfatal("cbrtl(+0.0) != +0.0");
382}
383#endif
384
385ATF_TP_ADD_TCS(tp)
386{
387
388	ATF_TP_ADD_TC(tp, cbrt_nan);
389	ATF_TP_ADD_TC(tp, cbrt_pow);
390	ATF_TP_ADD_TC(tp, cbrt_inf_neg);
391	ATF_TP_ADD_TC(tp, cbrt_inf_pos);
392	ATF_TP_ADD_TC(tp, cbrt_zero_neg);
393	ATF_TP_ADD_TC(tp, cbrt_zero_pos);
394
395	ATF_TP_ADD_TC(tp, cbrtf_nan);
396	ATF_TP_ADD_TC(tp, cbrtf_powf);
397	ATF_TP_ADD_TC(tp, cbrtf_inf_neg);
398	ATF_TP_ADD_TC(tp, cbrtf_inf_pos);
399	ATF_TP_ADD_TC(tp, cbrtf_zero_neg);
400	ATF_TP_ADD_TC(tp, cbrtf_zero_pos);
401
402#if !defined(__FreeBSD__) || LDBL_PREC != 53
403	ATF_TP_ADD_TC(tp, cbrtl_nan);
404	ATF_TP_ADD_TC(tp, cbrtl_powl);
405	ATF_TP_ADD_TC(tp, cbrtl_inf_neg);
406	ATF_TP_ADD_TC(tp, cbrtl_inf_pos);
407	ATF_TP_ADD_TC(tp, cbrtl_zero_neg);
408	ATF_TP_ADD_TC(tp, cbrtl_zero_pos);
409#endif
410
411	return atf_no_error();
412}
413