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
56static struct 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
74static struct 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
85static struct 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
95static struct 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
109static struct 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
123static struct 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
135static struct 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		ATF_CHECK_STREQ_MSG(table->result, outbuf,
181			    "Entry %zu:\n\tExp: \"%s\"\n\tAct: \"%s\"/%a",
182			    i, table->result, outbuf, v);
183	}
184}
185
186/*
187 * ldexp(3)
188 */
189ATF_TC(ldexp_exp2);
190ATF_TC_HEAD(ldexp_exp2, tc)
191{
192	atf_tc_set_md_var(tc, "descr", "Test ldexp(x, n) == x * exp2(n)");
193}
194
195ATF_TC_BODY(ldexp_exp2, tc)
196{
197	const double n[] = { 1, 2, 3, 10, 50, 100 };
198	const double eps = DBL_EPSILON;
199	const double x = 12.0;
200	size_t i;
201
202	for (i = 0; i < __arraycount(n); i++) {
203		double y = ldexp(x, n[i]);
204
205		if (!(fabs((y - (x * exp2(n[i])))/y) <= eps)) {
206			atf_tc_fail_nonfatal("ldexp(%.17g, %.17g) = %.17g "
207			    "!= %.17g * exp2(%.17g) = %.17g",
208			    x, n[i], y, x, n[i], (x * exp2(n[i])));
209		}
210	}
211}
212
213ATF_TC(ldexp_nan);
214ATF_TC_HEAD(ldexp_nan, tc)
215{
216	atf_tc_set_md_var(tc, "descr", "Test ldexp(NaN) == NaN");
217}
218
219ATF_TC_BODY(ldexp_nan, tc)
220{
221	const double x = 0.0L / 0.0L;
222	double y;
223	size_t i;
224
225	ATF_REQUIRE(isnan(x) != 0);
226
227	for (i = 0; i < __arraycount(exps); i++) {
228		y = ldexp(x, exps[i]);
229		ATF_CHECK(isnan(y) != 0);
230	}
231}
232
233ATF_TC(ldexp_inf_neg);
234ATF_TC_HEAD(ldexp_inf_neg, tc)
235{
236	atf_tc_set_md_var(tc, "descr", "Test ldexp(-Inf) == -Inf");
237}
238
239ATF_TC_BODY(ldexp_inf_neg, tc)
240{
241	const double x = -1.0L / 0.0L;
242	size_t i;
243
244	for (i = 0; i < __arraycount(exps); i++)
245		ATF_CHECK(ldexp(x, exps[i]) == x);
246}
247
248ATF_TC(ldexp_inf_pos);
249ATF_TC_HEAD(ldexp_inf_pos, tc)
250{
251	atf_tc_set_md_var(tc, "descr", "Test ldexp(+Inf) == +Inf");
252}
253
254ATF_TC_BODY(ldexp_inf_pos, tc)
255{
256	const double x = 1.0L / 0.0L;
257	size_t i;
258
259	for (i = 0; i < __arraycount(exps); i++)
260		ATF_CHECK(ldexp(x, exps[i]) == x);
261}
262
263ATF_TC(ldexp_zero_neg);
264ATF_TC_HEAD(ldexp_zero_neg, tc)
265{
266	atf_tc_set_md_var(tc, "descr", "Test ldexp(-0.0) == -0.0");
267}
268
269ATF_TC_BODY(ldexp_zero_neg, tc)
270{
271	const double x = -0.0L;
272	double y;
273	size_t i;
274
275	ATF_REQUIRE(signbit(x) != 0);
276
277	for (i = 0; i < __arraycount(exps); i++) {
278		y = ldexp(x, exps[i]);
279		ATF_CHECK(x == y);
280		ATF_CHECK(signbit(y) != 0);
281	}
282}
283
284ATF_TC(ldexp_zero_pos);
285ATF_TC_HEAD(ldexp_zero_pos, tc)
286{
287	atf_tc_set_md_var(tc, "descr", "Test ldexp(+0.0) == +0.0");
288}
289
290ATF_TC_BODY(ldexp_zero_pos, tc)
291{
292	const double x = 0.0L;
293	double y;
294	size_t i;
295
296	ATF_REQUIRE(signbit(x) == 0);
297
298	for (i = 0; i < __arraycount(exps); i++) {
299		y = ldexp(x, exps[i]);
300		ATF_CHECK(x == y);
301		ATF_CHECK(signbit(y) == 0);
302	}
303}
304
305/*
306 * ldexpf(3)
307 */
308
309ATF_TC(ldexpf_exp2f);
310ATF_TC_HEAD(ldexpf_exp2f, tc)
311{
312	atf_tc_set_md_var(tc, "descr", "Test ldexpf(x, n) == x * exp2f(n)");
313}
314
315ATF_TC_BODY(ldexpf_exp2f, tc)
316{
317	const float n[] = { 1, 2, 3, 10, 50, 100 };
318	const float eps = FLT_EPSILON;
319	const float x = 12.0;
320	size_t i;
321
322	for (i = 0; i < __arraycount(n); i++) {
323		float y = ldexpf(x, n[i]);
324
325		if (!(fabsf((y - (x * exp2f(n[i])))/y) <= eps)) {
326			atf_tc_fail_nonfatal("ldexpf(%.17g, %.17g) = %.17g "
327			    "!= %.17g * exp2f(%.17g) = %.17g",
328			    x, n[i], y, x, n[i], (x * exp2f(n[i])));
329		}
330	}
331}
332
333ATF_TC(ldexpf_nan);
334ATF_TC_HEAD(ldexpf_nan, tc)
335{
336	atf_tc_set_md_var(tc, "descr", "Test ldexpf(NaN) == NaN");
337}
338
339ATF_TC_BODY(ldexpf_nan, tc)
340{
341	const float x = 0.0L / 0.0L;
342	float y;
343	size_t i;
344
345	ATF_REQUIRE(isnan(x) != 0);
346
347	for (i = 0; i < __arraycount(exps); i++) {
348		y = ldexpf(x, exps[i]);
349		ATF_CHECK(isnan(y) != 0);
350	}
351}
352
353ATF_TC(ldexpf_inf_neg);
354ATF_TC_HEAD(ldexpf_inf_neg, tc)
355{
356	atf_tc_set_md_var(tc, "descr", "Test ldexpf(-Inf) == -Inf");
357}
358
359ATF_TC_BODY(ldexpf_inf_neg, tc)
360{
361	const float x = -1.0L / 0.0L;
362	size_t i;
363
364	for (i = 0; i < __arraycount(exps); i++)
365		ATF_CHECK(ldexpf(x, exps[i]) == x);
366}
367
368ATF_TC(ldexpf_inf_pos);
369ATF_TC_HEAD(ldexpf_inf_pos, tc)
370{
371	atf_tc_set_md_var(tc, "descr", "Test ldexpf(+Inf) == +Inf");
372}
373
374ATF_TC_BODY(ldexpf_inf_pos, tc)
375{
376	const float x = 1.0L / 0.0L;
377	size_t i;
378
379	for (i = 0; i < __arraycount(exps); i++)
380		ATF_CHECK(ldexpf(x, exps[i]) == x);
381}
382
383ATF_TC(ldexpf_zero_neg);
384ATF_TC_HEAD(ldexpf_zero_neg, tc)
385{
386	atf_tc_set_md_var(tc, "descr", "Test ldexpf(-0.0) == -0.0");
387}
388
389ATF_TC_BODY(ldexpf_zero_neg, tc)
390{
391	const float x = -0.0L;
392	float y;
393	size_t i;
394
395	ATF_REQUIRE(signbit(x) != 0);
396
397	for (i = 0; i < __arraycount(exps); i++) {
398		y = ldexpf(x, exps[i]);
399		ATF_CHECK(x == y);
400		ATF_CHECK(signbit(y) != 0);
401	}
402}
403
404ATF_TC(ldexpf_zero_pos);
405ATF_TC_HEAD(ldexpf_zero_pos, tc)
406{
407	atf_tc_set_md_var(tc, "descr", "Test ldexpf(+0.0) == +0.0");
408}
409
410ATF_TC_BODY(ldexpf_zero_pos, tc)
411{
412	const float x = 0.0L;
413	float y;
414	size_t i;
415
416	ATF_REQUIRE(signbit(x) == 0);
417
418	for (i = 0; i < __arraycount(exps); i++) {
419		y = ldexpf(x, exps[i]);
420		ATF_CHECK(x == y);
421		ATF_CHECK(signbit(y) == 0);
422	}
423}
424
425#define TEST(name, desc)						\
426	ATF_TC(name);							\
427	ATF_TC_HEAD(name, tc)						\
428	{								\
429									\
430		atf_tc_set_md_var(tc, "descr",				\
431		    "Test ldexp(3) for " ___STRING(desc));		\
432	}								\
433	ATF_TC_BODY(name, tc)						\
434	{								\
435		if (strcmp("vax", MACHINE_ARCH) == 0)			\
436			atf_tc_skip("Test not valid for " MACHINE_ARCH); \
437		run_test(name);						\
438	}
439
440TEST(ldexp_basic, basics)
441TEST(ldexp_zero, zero)
442TEST(ldexp_infinity, infinity)
443TEST(ldexp_overflow, overflow)
444TEST(ldexp_denormal, denormal)
445TEST(ldexp_denormal_large, large)
446TEST(ldexp_underflow, underflow)
447
448ATF_TP_ADD_TCS(tp)
449{
450
451	ATF_TP_ADD_TC(tp, ldexp_basic);
452	ATF_TP_ADD_TC(tp, ldexp_zero);
453	ATF_TP_ADD_TC(tp, ldexp_infinity);
454	ATF_TP_ADD_TC(tp, ldexp_overflow);
455	ATF_TP_ADD_TC(tp, ldexp_denormal);
456	ATF_TP_ADD_TC(tp, ldexp_underflow);
457	ATF_TP_ADD_TC(tp, ldexp_denormal_large);
458
459	ATF_TP_ADD_TC(tp, ldexp_exp2);
460	ATF_TP_ADD_TC(tp, ldexp_nan);
461	ATF_TP_ADD_TC(tp, ldexp_inf_neg);
462	ATF_TP_ADD_TC(tp, ldexp_inf_pos);
463	ATF_TP_ADD_TC(tp, ldexp_zero_neg);
464	ATF_TP_ADD_TC(tp, ldexp_zero_pos);
465
466	ATF_TP_ADD_TC(tp, ldexpf_exp2f);
467	ATF_TP_ADD_TC(tp, ldexpf_nan);
468	ATF_TP_ADD_TC(tp, ldexpf_inf_neg);
469	ATF_TP_ADD_TC(tp, ldexpf_inf_pos);
470	ATF_TP_ADD_TC(tp, ldexpf_zero_neg);
471	ATF_TP_ADD_TC(tp, ldexpf_zero_pos);
472
473	return atf_no_error();
474}
475