1/* $NetBSD: t_ldexp.c,v 1.17 2018/11/07 03:59:36 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_ldexp.c,v 1.17 2018/11/07 03:59:36 riastradh Exp $");
33
34#include <sys/param.h>
35
36#include <atf-c.h>
37
38#include <float.h>
39#include <limits.h>
40#include <math.h>
41#include <stdio.h>
42#include <string.h>
43
44#define SKIP	9999
45#define FORMAT  "%23.23lg"
46
47static const int exps[] = { 0, 1, -1, 100, -100 };
48
49struct ldexp_test {
50	double	    x;
51	int	    exp1;
52	int	    exp2;
53	const char *result;
54};
55
56struct ldexp_test ldexp_basic[] = {
57	{ 1.0,	5,	SKIP,	"                     32" },
58	{ 1.0,	1022,	SKIP,	"4.4942328371557897693233e+307" },
59	{ 1.0,	1023,	-1,	"4.4942328371557897693233e+307" },
60	{ 1.0,	1023,	SKIP,	"8.9884656743115795386465e+307" },
61	{ 1.0,	1022,	1,	"8.9884656743115795386465e+307" },
62	{ 1.0,	-1022,	2045,	"8.9884656743115795386465e+307" },
63	{ 1.0,	-5,	SKIP,	"                0.03125" },
64	{ 1.0,	-1021,	SKIP,	"4.4501477170144027661805e-308" },
65	{ 1.0,	-1022,	1,	"4.4501477170144027661805e-308" },
66	{ 1.0,	-1022,	SKIP,	"2.2250738585072013830902e-308" },
67	{ 1.0,	-1021,	-1,	"2.2250738585072013830902e-308" },
68	{ 1.0,	1023,	-2045,	"2.2250738585072013830902e-308" },
69	{ 1.0,	1023,	-1023,	"                      1" },
70	{ 1.0,	-1022,	1022,	"                      1" },
71	{ 0,	0,	0,	NULL }
72};
73
74struct ldexp_test ldexp_zero[] = {
75	{ 0.0,	-1,	SKIP,	"                      0" },
76	{ 0.0,	0,	SKIP,	"                      0" },
77	{ 0.0,	1,	SKIP,	"                      0" },
78	{ 0.0,	1024,	SKIP,	"                      0" },
79	{ 0.0,	1025,	SKIP,	"                      0" },
80	{ 0.0,	-1023,	SKIP,	"                      0" },
81	{ 0.0,	-1024,	SKIP,	"                      0" },
82	{ 0,	0,	0,	NULL }
83};
84
85struct ldexp_test ldexp_infinity[] = {
86	{ 1.0,	1024,	-1,	"                    inf" },
87	{ 1.0,	1024,	0,	"                    inf" },
88	{ 1.0,	1024,	1,	"                    inf" },
89	{ -1.0,	1024,	-1,	"                   -inf" },
90	{ -1.0,	1024,	0,	"                   -inf" },
91	{ -1.0,	1024,	1,	"                   -inf" },
92	{ 0,	0,	0,	NULL }
93};
94
95struct ldexp_test ldexp_overflow[] = {
96	{ 1.0,	1024,	SKIP,	"                    inf" },
97	{ 1.0,	1023,	1,	"                    inf" },
98	{ 1.0,	-1022,	2046,	"                    inf" },
99	{ 1.0,	1025,	SKIP,	"                    inf" },
100	{ 2.0,	INT_MAX,SKIP,	"                    inf" },
101	{ -1.0,	1024,	SKIP,	"                   -inf" },
102	{ -1.0,	1023,	1,	"                   -inf" },
103	{ -1.0,	-1022,	2046,	"                   -inf" },
104	{ -1.0,	1025,	SKIP,	"                   -inf" },
105	{ -2.0, INT_MAX,SKIP,	"                   -inf" },
106	{ 0,	0,	0,	NULL }
107};
108
109struct ldexp_test ldexp_denormal[] = {
110	{ 1.0,	-1023,	SKIP,	"1.1125369292536006915451e-308" },
111	{ 1.0,	-1022,	-1,	"1.1125369292536006915451e-308" },
112	{ 1.0,	1023,	-2046,	"1.1125369292536006915451e-308" },
113	{ 1.0,	-1024,	SKIP,	"5.5626846462680034577256e-309" },
114	{ 1.0,	-1074,	SKIP,	"4.9406564584124654417657e-324" },
115	{ -1.0,	-1023,	SKIP,	"-1.1125369292536006915451e-308" },
116	{ -1.0,	-1022,	-1,	"-1.1125369292536006915451e-308" },
117	{ -1.0,	1023,	-2046,	"-1.1125369292536006915451e-308" },
118	{ -1.0,	-1024,	SKIP,	"-5.5626846462680034577256e-309" },
119	{ -1.0,	-1074,	SKIP,	"-4.9406564584124654417657e-324" },
120	{ 0,	0,	0,	NULL }
121};
122
123struct ldexp_test ldexp_underflow[] = {
124	{ 1.0,	-1075,	SKIP,	"                      0" },
125	{ 1.0,	-1074,	-1,	"                      0" },
126	{ 1.0,	1023,	-2098,	"                      0" },
127	{ 1.0,	-1076,	SKIP,	"                      0" },
128	{ -1.0,	-1075,	SKIP,	"                     -0" },
129	{ -1.0,	-1074,	-1,	"                     -0" },
130	{ -1.0,	1023,	-2098,	"                     -0" },
131	{ -1.0,	-1076,	SKIP,	"                     -0" },
132	{ 0,	0,	0,	NULL }
133};
134
135struct ldexp_test ldexp_denormal_large[] = {
136	{ 1.0,	-1028,	1024,	"                 0.0625" },
137	{ 1.0,	-1028,	1025,	"                  0.125" },
138	{ 1.0,	-1028,	1026,	"                   0.25" },
139	{ 1.0,	-1028,	1027,	"                    0.5" },
140	{ 1.0,	-1028,	1028,	"                      1" },
141	{ 1.0,	-1028,	1029,	"                      2" },
142	{ 1.0,	-1028,	1030,	"                      4" },
143	{ 1.0,	-1028,	1040,	"                   4096" },
144	{ 1.0,	-1028,	1050,	"                4194304" },
145	{ 1.0,	-1028,	1060,	"             4294967296" },
146	{ 1.0,	-1028,	1100,	" 4722366482869645213696" },
147	{ 1.0,	-1028,	1200,	"5.9863107065073783529623e+51" },
148	{ 1.0,	-1028,	1300,	"7.5885503602567541832791e+81" },
149	{ 1.0,	-1028,	1400,	"9.6196304190416209014353e+111" },
150	{ 1.0,	-1028,	1500,	"1.2194330274671844653834e+142" },
151	{ 1.0,	-1028,	1600,	"1.5458150092069033378781e+172" },
152	{ 1.0,	-1028,	1700,	"1.9595533242629369747791e+202" },
153	{ 1.0,	-1028,	1800,	"2.4840289476811342962384e+232" },
154	{ 1.0,	-1028,	1900,	"3.1488807865122869393369e+262" },
155	{ 1.0,	-1028,	2000,	"3.9916806190694396233127e+292" },
156	{ 1.0,	-1028,	2046,	"2.808895523222368605827e+306" },
157	{ 1.0,	-1028,	2047,	"5.6177910464447372116541e+306" },
158	{ 1.0,	-1028,	2048,	"1.1235582092889474423308e+307" },
159	{ 1.0,	-1028,	2049,	"2.2471164185778948846616e+307" },
160	{ 1.0,	-1028,	2050,	"4.4942328371557897693233e+307" },
161	{ 1.0,	-1028,	2051,	"8.9884656743115795386465e+307" },
162	{ 0,	0,	0,	NULL }
163};
164
165static void
166run_test(struct ldexp_test *table)
167{
168	char outbuf[64];
169	size_t i;
170	double v;
171
172	for (i = 0; table->result != NULL; table++, i++) {
173
174		v = ldexp(table->x, table->exp1);
175
176		if (table->exp2 != SKIP)
177			v = ldexp(v, table->exp2);
178
179		(void)snprintf(outbuf, sizeof(outbuf), FORMAT, v);
180
181		ATF_CHECK_STREQ_MSG(table->result, outbuf,
182			    "Entry %zu:\n\tExp: \"%s\"\n\tAct: \"%s\"",
183			    i, table->result, outbuf);
184	}
185}
186
187/*
188 * ldexp(3)
189 */
190ATF_TC(ldexp_exp2);
191ATF_TC_HEAD(ldexp_exp2, tc)
192{
193	atf_tc_set_md_var(tc, "descr", "Test ldexp(x, n) == x * exp2(n)");
194}
195
196ATF_TC_BODY(ldexp_exp2, tc)
197{
198	const double n[] = { 1, 2, 3, 10, 50, 100 };
199	const double eps = DBL_EPSILON;
200	const double x = 12.0;
201	size_t i;
202
203	for (i = 0; i < __arraycount(n); i++) {
204		double y = ldexp(x, n[i]);
205
206		if (!(fabs((y - (x * exp2(n[i])))/y) <= eps)) {
207			atf_tc_fail_nonfatal("ldexp(%.17g, %.17g) = %.17g "
208			    "!= %.17g * exp2(%.17g) = %.17g",
209			    x, n[i], y, x, n[i], (x * exp2(n[i])));
210		}
211	}
212}
213
214ATF_TC(ldexp_nan);
215ATF_TC_HEAD(ldexp_nan, tc)
216{
217	atf_tc_set_md_var(tc, "descr", "Test ldexp(NaN) == NaN");
218}
219
220ATF_TC_BODY(ldexp_nan, tc)
221{
222	const double x = 0.0L / 0.0L;
223	double y;
224	size_t i;
225
226	ATF_REQUIRE(isnan(x) != 0);
227
228	for (i = 0; i < __arraycount(exps); i++) {
229		y = ldexp(x, exps[i]);
230		ATF_CHECK(isnan(y) != 0);
231	}
232}
233
234ATF_TC(ldexp_inf_neg);
235ATF_TC_HEAD(ldexp_inf_neg, tc)
236{
237	atf_tc_set_md_var(tc, "descr", "Test ldexp(-Inf) == -Inf");
238}
239
240ATF_TC_BODY(ldexp_inf_neg, tc)
241{
242	const double x = -1.0L / 0.0L;
243	size_t i;
244
245	for (i = 0; i < __arraycount(exps); i++)
246		ATF_CHECK(ldexp(x, exps[i]) == x);
247}
248
249ATF_TC(ldexp_inf_pos);
250ATF_TC_HEAD(ldexp_inf_pos, tc)
251{
252	atf_tc_set_md_var(tc, "descr", "Test ldexp(+Inf) == +Inf");
253}
254
255ATF_TC_BODY(ldexp_inf_pos, tc)
256{
257	const double x = 1.0L / 0.0L;
258	size_t i;
259
260	for (i = 0; i < __arraycount(exps); i++)
261		ATF_CHECK(ldexp(x, exps[i]) == x);
262}
263
264ATF_TC(ldexp_zero_neg);
265ATF_TC_HEAD(ldexp_zero_neg, tc)
266{
267	atf_tc_set_md_var(tc, "descr", "Test ldexp(-0.0) == -0.0");
268}
269
270ATF_TC_BODY(ldexp_zero_neg, tc)
271{
272	const double x = -0.0L;
273	double y;
274	size_t i;
275
276	ATF_REQUIRE(signbit(x) != 0);
277
278	for (i = 0; i < __arraycount(exps); i++) {
279		y = ldexp(x, exps[i]);
280		ATF_CHECK(x == y);
281		ATF_CHECK(signbit(y) != 0);
282	}
283}
284
285ATF_TC(ldexp_zero_pos);
286ATF_TC_HEAD(ldexp_zero_pos, tc)
287{
288	atf_tc_set_md_var(tc, "descr", "Test ldexp(+0.0) == +0.0");
289}
290
291ATF_TC_BODY(ldexp_zero_pos, tc)
292{
293	const double x = 0.0L;
294	double y;
295	size_t i;
296
297	ATF_REQUIRE(signbit(x) == 0);
298
299	for (i = 0; i < __arraycount(exps); i++) {
300		y = ldexp(x, exps[i]);
301		ATF_CHECK(x == y);
302		ATF_CHECK(signbit(y) == 0);
303	}
304}
305
306/*
307 * ldexpf(3)
308 */
309
310ATF_TC(ldexpf_exp2f);
311ATF_TC_HEAD(ldexpf_exp2f, tc)
312{
313	atf_tc_set_md_var(tc, "descr", "Test ldexpf(x, n) == x * exp2f(n)");
314}
315
316ATF_TC_BODY(ldexpf_exp2f, tc)
317{
318	const float n[] = { 1, 2, 3, 10, 50, 100 };
319	const float eps = FLT_EPSILON;
320	const float x = 12.0;
321	size_t i;
322
323	for (i = 0; i < __arraycount(n); i++) {
324		float y = ldexpf(x, n[i]);
325
326		if (!(fabsf((y - (x * exp2f(n[i])))/y) <= eps)) {
327			atf_tc_fail_nonfatal("ldexpf(%.17g, %.17g) = %.17g "
328			    "!= %.17g * exp2f(%.17g) = %.17g",
329			    x, n[i], y, x, n[i], (x * exp2f(n[i])));
330		}
331	}
332}
333
334ATF_TC(ldexpf_nan);
335ATF_TC_HEAD(ldexpf_nan, tc)
336{
337	atf_tc_set_md_var(tc, "descr", "Test ldexpf(NaN) == NaN");
338}
339
340ATF_TC_BODY(ldexpf_nan, tc)
341{
342	const float x = 0.0L / 0.0L;
343	float y;
344	size_t i;
345
346	ATF_REQUIRE(isnan(x) != 0);
347
348	for (i = 0; i < __arraycount(exps); i++) {
349		y = ldexpf(x, exps[i]);
350		ATF_CHECK(isnan(y) != 0);
351	}
352}
353
354ATF_TC(ldexpf_inf_neg);
355ATF_TC_HEAD(ldexpf_inf_neg, tc)
356{
357	atf_tc_set_md_var(tc, "descr", "Test ldexpf(-Inf) == -Inf");
358}
359
360ATF_TC_BODY(ldexpf_inf_neg, tc)
361{
362	const float x = -1.0L / 0.0L;
363	size_t i;
364
365	for (i = 0; i < __arraycount(exps); i++)
366		ATF_CHECK(ldexpf(x, exps[i]) == x);
367}
368
369ATF_TC(ldexpf_inf_pos);
370ATF_TC_HEAD(ldexpf_inf_pos, tc)
371{
372	atf_tc_set_md_var(tc, "descr", "Test ldexpf(+Inf) == +Inf");
373}
374
375ATF_TC_BODY(ldexpf_inf_pos, tc)
376{
377	const float x = 1.0L / 0.0L;
378	size_t i;
379
380	for (i = 0; i < __arraycount(exps); i++)
381		ATF_CHECK(ldexpf(x, exps[i]) == x);
382}
383
384ATF_TC(ldexpf_zero_neg);
385ATF_TC_HEAD(ldexpf_zero_neg, tc)
386{
387	atf_tc_set_md_var(tc, "descr", "Test ldexpf(-0.0) == -0.0");
388}
389
390ATF_TC_BODY(ldexpf_zero_neg, tc)
391{
392	const float x = -0.0L;
393	float y;
394	size_t i;
395
396	ATF_REQUIRE(signbit(x) != 0);
397
398	for (i = 0; i < __arraycount(exps); i++) {
399		y = ldexpf(x, exps[i]);
400		ATF_CHECK(x == y);
401		ATF_CHECK(signbit(y) != 0);
402	}
403}
404
405ATF_TC(ldexpf_zero_pos);
406ATF_TC_HEAD(ldexpf_zero_pos, tc)
407{
408	atf_tc_set_md_var(tc, "descr", "Test ldexpf(+0.0) == +0.0");
409}
410
411ATF_TC_BODY(ldexpf_zero_pos, tc)
412{
413	const float x = 0.0L;
414	float y;
415	size_t i;
416
417	ATF_REQUIRE(signbit(x) == 0);
418
419	for (i = 0; i < __arraycount(exps); i++) {
420		y = ldexpf(x, exps[i]);
421		ATF_CHECK(x == y);
422		ATF_CHECK(signbit(y) == 0);
423	}
424}
425
426#define TEST(name, desc)						\
427	ATF_TC(name);							\
428	ATF_TC_HEAD(name, tc)						\
429	{								\
430									\
431		atf_tc_set_md_var(tc, "descr",				\
432		    "Test ldexp(3) for " ___STRING(desc));		\
433	}								\
434	ATF_TC_BODY(name, tc)						\
435	{								\
436		if (strcmp("vax", MACHINE_ARCH) == 0)			\
437			atf_tc_skip("Test not valid for " MACHINE_ARCH); \
438		run_test(name);						\
439	}
440
441TEST(ldexp_basic, basics)
442TEST(ldexp_zero, zero)
443TEST(ldexp_infinity, infinity)
444TEST(ldexp_overflow, overflow)
445TEST(ldexp_denormal, denormal)
446TEST(ldexp_denormal_large, large)
447TEST(ldexp_underflow, underflow)
448
449ATF_TP_ADD_TCS(tp)
450{
451
452	ATF_TP_ADD_TC(tp, ldexp_basic);
453	ATF_TP_ADD_TC(tp, ldexp_zero);
454	ATF_TP_ADD_TC(tp, ldexp_infinity);
455	ATF_TP_ADD_TC(tp, ldexp_overflow);
456	ATF_TP_ADD_TC(tp, ldexp_denormal);
457	ATF_TP_ADD_TC(tp, ldexp_underflow);
458	ATF_TP_ADD_TC(tp, ldexp_denormal_large);
459
460	ATF_TP_ADD_TC(tp, ldexp_exp2);
461	ATF_TP_ADD_TC(tp, ldexp_nan);
462	ATF_TP_ADD_TC(tp, ldexp_inf_neg);
463	ATF_TP_ADD_TC(tp, ldexp_inf_pos);
464	ATF_TP_ADD_TC(tp, ldexp_zero_neg);
465	ATF_TP_ADD_TC(tp, ldexp_zero_pos);
466
467	ATF_TP_ADD_TC(tp, ldexpf_exp2f);
468	ATF_TP_ADD_TC(tp, ldexpf_nan);
469	ATF_TP_ADD_TC(tp, ldexpf_inf_neg);
470	ATF_TP_ADD_TC(tp, ldexpf_inf_pos);
471	ATF_TP_ADD_TC(tp, ldexpf_zero_neg);
472	ATF_TP_ADD_TC(tp, ldexpf_zero_pos);
473
474	return atf_no_error();
475}
476