1174619Sdas/*-
2174619Sdas * Copyright (c) 2007 David Schultz <das@FreeBSD.org>
3174619Sdas * All rights reserved.
4174619Sdas *
5174619Sdas * Redistribution and use in source and binary forms, with or without
6174619Sdas * modification, are permitted provided that the following conditions
7174619Sdas * are met:
8174619Sdas * 1. Redistributions of source code must retain the above copyright
9174619Sdas *    notice, this list of conditions and the following disclaimer.
10174619Sdas * 2. Redistributions in binary form must reproduce the above copyright
11174619Sdas *    notice, this list of conditions and the following disclaimer in the
12174619Sdas *    documentation and/or other materials provided with the distribution.
13174619Sdas *
14174619Sdas * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15174619Sdas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16174619Sdas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17174619Sdas * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18174619Sdas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19174619Sdas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20174619Sdas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21174619Sdas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22174619Sdas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23174619Sdas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24174619Sdas * SUCH DAMAGE.
25174619Sdas */
26174619Sdas
27174619Sdas/*
28174619Sdas * Tests for csqrt{,f}()
29174619Sdas */
30174619Sdas
31174619Sdas#include <sys/cdefs.h>
32174619Sdas__FBSDID("$FreeBSD$");
33174619Sdas
34174619Sdas#include <assert.h>
35174619Sdas#include <complex.h>
36174619Sdas#include <float.h>
37174619Sdas#include <math.h>
38174619Sdas#include <stdio.h>
39174619Sdas
40251241Sdas#include "test-utils.h"
41251241Sdas
42174619Sdas#define	N(i)	(sizeof(i) / sizeof((i)[0]))
43174619Sdas
44174619Sdas/*
45177763Sdas * This is a test hook that can point to csqrtl(), _csqrt(), or to _csqrtf().
46177763Sdas * The latter two convert to float or double, respectively, and test csqrtf()
47177763Sdas * and csqrt() with the same arguments.
48174619Sdas */
49177763Sdaslong double complex (*t_csqrt)(long double complex);
50174619Sdas
51177763Sdasstatic long double complex
52177763Sdas_csqrtf(long double complex d)
53174619Sdas{
54174619Sdas
55174619Sdas	return (csqrtf((float complex)d));
56174619Sdas}
57174619Sdas
58177763Sdasstatic long double complex
59177763Sdas_csqrt(long double complex d)
60177763Sdas{
61177763Sdas
62177763Sdas	return (csqrt((double complex)d));
63177763Sdas}
64177763Sdas
65174619Sdas#pragma	STDC CX_LIMITED_RANGE	off
66174619Sdas
67174619Sdas/*
68174619Sdas * Compare d1 and d2 using special rules: NaN == NaN and +0 != -0.
69174619Sdas * Fail an assertion if they differ.
70174619Sdas */
71174619Sdasstatic void
72177763Sdasassert_equal(long double complex d1, long double complex d2)
73174619Sdas{
74174619Sdas
75251241Sdas	assert(cfpequal(d1, d2));
76174619Sdas}
77174619Sdas
78174619Sdas/*
79174619Sdas * Test csqrt for some finite arguments where the answer is exact.
80174619Sdas * (We do not test if it produces correctly rounded answers when the
81174619Sdas * result is inexact, nor do we check whether it throws spurious
82174619Sdas * exceptions.)
83174619Sdas */
84174619Sdasstatic void
85174619Sdastest_finite()
86174619Sdas{
87174619Sdas	static const double tests[] = {
88174619Sdas	     /* csqrt(a + bI) = x + yI */
89174619Sdas	     /* a	b	x	y */
90174619Sdas		0,	8,	2,	2,
91174619Sdas		0,	-8,	2,	-2,
92174619Sdas		4,	0,	2,	0,
93174619Sdas		-4,	0,	0,	2,
94174619Sdas		3,	4,	2,	1,
95174619Sdas		3,	-4,	2,	-1,
96174619Sdas		-3,	4,	1,	2,
97174619Sdas		-3,	-4,	1,	-2,
98174619Sdas		5,	12,	3,	2,
99174619Sdas		7,	24,	4,	3,
100174619Sdas		9,	40,	5,	4,
101174619Sdas		11,	60,	6,	5,
102174619Sdas		13,	84,	7,	6,
103174619Sdas		33,	56,	7,	4,
104174619Sdas		39,	80,	8,	5,
105174619Sdas		65,	72,	9,	4,
106174619Sdas		987,	9916,	74,	67,
107174619Sdas		5289,	6640,	83,	40,
108174619Sdas		460766389075.0, 16762287900.0, 678910, 12345
109174619Sdas	};
110174619Sdas	/*
111174619Sdas	 * We also test some multiples of the above arguments. This
112174619Sdas	 * array defines which multiples we use. Note that these have
113174619Sdas	 * to be small enough to not cause overflow for float precision
114174619Sdas	 * with all of the constants in the above table.
115174619Sdas	 */
116174619Sdas	static const double mults[] = {
117174619Sdas		1,
118174619Sdas		2,
119174619Sdas		3,
120174619Sdas		13,
121174619Sdas		16,
122174619Sdas		0x1.p30,
123174619Sdas		0x1.p-30,
124174619Sdas	};
125174619Sdas
126174619Sdas	double a, b;
127174619Sdas	double x, y;
128174619Sdas	int i, j;
129174619Sdas
130174619Sdas	for (i = 0; i < N(tests); i += 4) {
131174619Sdas		for (j = 0; j < N(mults); j++) {
132174619Sdas			a = tests[i] * mults[j] * mults[j];
133174619Sdas			b = tests[i + 1] * mults[j] * mults[j];
134174619Sdas			x = tests[i + 2] * mults[j];
135174619Sdas			y = tests[i + 3] * mults[j];
136251241Sdas			assert(t_csqrt(CMPLXL(a, b)) == CMPLXL(x, y));
137174619Sdas		}
138174619Sdas	}
139174619Sdas
140174619Sdas}
141174619Sdas
142174619Sdas/*
143174619Sdas * Test the handling of +/- 0.
144174619Sdas */
145174619Sdasstatic void
146174619Sdastest_zeros()
147174619Sdas{
148174619Sdas
149251241Sdas	assert_equal(t_csqrt(CMPLXL(0.0, 0.0)), CMPLXL(0.0, 0.0));
150251241Sdas	assert_equal(t_csqrt(CMPLXL(-0.0, 0.0)), CMPLXL(0.0, 0.0));
151251241Sdas	assert_equal(t_csqrt(CMPLXL(0.0, -0.0)), CMPLXL(0.0, -0.0));
152251241Sdas	assert_equal(t_csqrt(CMPLXL(-0.0, -0.0)), CMPLXL(0.0, -0.0));
153174619Sdas}
154174619Sdas
155174619Sdas/*
156174619Sdas * Test the handling of infinities when the other argument is not NaN.
157174619Sdas */
158174619Sdasstatic void
159174619Sdastest_infinities()
160174619Sdas{
161174619Sdas	static const double vals[] = {
162174619Sdas		0.0,
163174619Sdas		-0.0,
164174619Sdas		42.0,
165174619Sdas		-42.0,
166174619Sdas		INFINITY,
167174619Sdas		-INFINITY,
168174619Sdas	};
169174619Sdas
170174619Sdas	int i;
171174619Sdas
172174619Sdas	for (i = 0; i < N(vals); i++) {
173174619Sdas		if (isfinite(vals[i])) {
174251241Sdas			assert_equal(t_csqrt(CMPLXL(-INFINITY, vals[i])),
175251241Sdas			    CMPLXL(0.0, copysignl(INFINITY, vals[i])));
176251241Sdas			assert_equal(t_csqrt(CMPLXL(INFINITY, vals[i])),
177251241Sdas			    CMPLXL(INFINITY, copysignl(0.0, vals[i])));
178174619Sdas		}
179251241Sdas		assert_equal(t_csqrt(CMPLXL(vals[i], INFINITY)),
180251241Sdas		    CMPLXL(INFINITY, INFINITY));
181251241Sdas		assert_equal(t_csqrt(CMPLXL(vals[i], -INFINITY)),
182251241Sdas		    CMPLXL(INFINITY, -INFINITY));
183174619Sdas	}
184174619Sdas}
185174619Sdas
186174619Sdas/*
187174619Sdas * Test the handling of NaNs.
188174619Sdas */
189174619Sdasstatic void
190174619Sdastest_nans()
191174619Sdas{
192174619Sdas
193251241Sdas	assert(creall(t_csqrt(CMPLXL(INFINITY, NAN))) == INFINITY);
194251241Sdas	assert(isnan(cimagl(t_csqrt(CMPLXL(INFINITY, NAN)))));
195174619Sdas
196251241Sdas	assert(isnan(creall(t_csqrt(CMPLXL(-INFINITY, NAN)))));
197251241Sdas	assert(isinf(cimagl(t_csqrt(CMPLXL(-INFINITY, NAN)))));
198174619Sdas
199251241Sdas	assert_equal(t_csqrt(CMPLXL(NAN, INFINITY)),
200251241Sdas		     CMPLXL(INFINITY, INFINITY));
201251241Sdas	assert_equal(t_csqrt(CMPLXL(NAN, -INFINITY)),
202251241Sdas		     CMPLXL(INFINITY, -INFINITY));
203174619Sdas
204251241Sdas	assert_equal(t_csqrt(CMPLXL(0.0, NAN)), CMPLXL(NAN, NAN));
205251241Sdas	assert_equal(t_csqrt(CMPLXL(-0.0, NAN)), CMPLXL(NAN, NAN));
206251241Sdas	assert_equal(t_csqrt(CMPLXL(42.0, NAN)), CMPLXL(NAN, NAN));
207251241Sdas	assert_equal(t_csqrt(CMPLXL(-42.0, NAN)), CMPLXL(NAN, NAN));
208251241Sdas	assert_equal(t_csqrt(CMPLXL(NAN, 0.0)), CMPLXL(NAN, NAN));
209251241Sdas	assert_equal(t_csqrt(CMPLXL(NAN, -0.0)), CMPLXL(NAN, NAN));
210251241Sdas	assert_equal(t_csqrt(CMPLXL(NAN, 42.0)), CMPLXL(NAN, NAN));
211251241Sdas	assert_equal(t_csqrt(CMPLXL(NAN, -42.0)), CMPLXL(NAN, NAN));
212251241Sdas	assert_equal(t_csqrt(CMPLXL(NAN, NAN)), CMPLXL(NAN, NAN));
213174619Sdas}
214174619Sdas
215174619Sdas/*
216174619Sdas * Test whether csqrt(a + bi) works for inputs that are large enough to
217174619Sdas * cause overflow in hypot(a, b) + a. In this case we are using
218174619Sdas *	csqrt(115 + 252*I) == 14 + 9*I
219174619Sdas * scaled up to near MAX_EXP.
220174619Sdas */
221174619Sdasstatic void
222174619Sdastest_overflow(int maxexp)
223174619Sdas{
224177763Sdas	long double a, b;
225177763Sdas	long double complex result;
226174619Sdas
227177763Sdas	a = ldexpl(115 * 0x1p-8, maxexp);
228177763Sdas	b = ldexpl(252 * 0x1p-8, maxexp);
229251241Sdas	result = t_csqrt(CMPLXL(a, b));
230177763Sdas	assert(creall(result) == ldexpl(14 * 0x1p-4, maxexp / 2));
231177763Sdas	assert(cimagl(result) == ldexpl(9 * 0x1p-4, maxexp / 2));
232174619Sdas}
233174619Sdas
234174619Sdasint
235174619Sdasmain(int argc, char *argv[])
236174619Sdas{
237174619Sdas
238177763Sdas	printf("1..15\n");
239174619Sdas
240174619Sdas	/* Test csqrt() */
241177763Sdas	t_csqrt = _csqrt;
242174619Sdas
243174619Sdas	test_finite();
244174619Sdas	printf("ok 1 - csqrt\n");
245174619Sdas
246174619Sdas	test_zeros();
247174619Sdas	printf("ok 2 - csqrt\n");
248174619Sdas
249174619Sdas	test_infinities();
250174619Sdas	printf("ok 3 - csqrt\n");
251174619Sdas
252174619Sdas	test_nans();
253174619Sdas	printf("ok 4 - csqrt\n");
254174619Sdas
255174619Sdas	test_overflow(DBL_MAX_EXP);
256174619Sdas	printf("ok 5 - csqrt\n");
257174619Sdas
258174619Sdas	/* Now test csqrtf() */
259174619Sdas	t_csqrt = _csqrtf;
260174619Sdas
261174619Sdas	test_finite();
262174619Sdas	printf("ok 6 - csqrt\n");
263174619Sdas
264174619Sdas	test_zeros();
265174619Sdas	printf("ok 7 - csqrt\n");
266174619Sdas
267174619Sdas	test_infinities();
268174619Sdas	printf("ok 8 - csqrt\n");
269174619Sdas
270174619Sdas	test_nans();
271174619Sdas	printf("ok 9 - csqrt\n");
272174619Sdas
273174619Sdas	test_overflow(FLT_MAX_EXP);
274174619Sdas	printf("ok 10 - csqrt\n");
275174619Sdas
276177763Sdas	/* Now test csqrtl() */
277177763Sdas	t_csqrt = csqrtl;
278177763Sdas
279177763Sdas	test_finite();
280177763Sdas	printf("ok 11 - csqrt\n");
281177763Sdas
282177763Sdas	test_zeros();
283177763Sdas	printf("ok 12 - csqrt\n");
284177763Sdas
285177763Sdas	test_infinities();
286177763Sdas	printf("ok 13 - csqrt\n");
287177763Sdas
288177763Sdas	test_nans();
289177763Sdas	printf("ok 14 - csqrt\n");
290177763Sdas
291177763Sdas	test_overflow(LDBL_MAX_EXP);
292177763Sdas	printf("ok 15 - csqrt\n");
293177763Sdas
294174619Sdas	return (0);
295174619Sdas}
296