1*498c7b5eSderaadt /* $OpenBSD: csqrt_test.c,v 1.3 2021/12/13 18:04:28 deraadt Exp $ */
2c36e572eSmbuhl /*-
3c36e572eSmbuhl * Copyright (c) 2007 David Schultz <das@FreeBSD.org>
4c36e572eSmbuhl * All rights reserved.
5c36e572eSmbuhl *
6c36e572eSmbuhl * Redistribution and use in source and binary forms, with or without
7c36e572eSmbuhl * modification, are permitted provided that the following conditions
8c36e572eSmbuhl * are met:
9c36e572eSmbuhl * 1. Redistributions of source code must retain the above copyright
10c36e572eSmbuhl * notice, this list of conditions and the following disclaimer.
11c36e572eSmbuhl * 2. Redistributions in binary form must reproduce the above copyright
12c36e572eSmbuhl * notice, this list of conditions and the following disclaimer in the
13c36e572eSmbuhl * documentation and/or other materials provided with the distribution.
14c36e572eSmbuhl *
15c36e572eSmbuhl * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16c36e572eSmbuhl * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17c36e572eSmbuhl * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18c36e572eSmbuhl * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19c36e572eSmbuhl * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20c36e572eSmbuhl * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21c36e572eSmbuhl * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22c36e572eSmbuhl * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23c36e572eSmbuhl * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24c36e572eSmbuhl * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25c36e572eSmbuhl * SUCH DAMAGE.
26c36e572eSmbuhl */
27c36e572eSmbuhl
28c36e572eSmbuhl #include "macros.h"
29c36e572eSmbuhl
3049a6e16fSderaadt #include <sys/types.h>
31c36e572eSmbuhl
32c36e572eSmbuhl #include <complex.h>
33c36e572eSmbuhl #include <float.h>
34c36e572eSmbuhl #include <math.h>
35c36e572eSmbuhl #include <stdio.h>
36c36e572eSmbuhl
37c36e572eSmbuhl #include "test-utils.h"
38c36e572eSmbuhl
39c36e572eSmbuhl /*
40c36e572eSmbuhl * This is a test hook that can point to csqrtl(), _csqrt(), or to _csqrtf().
41c36e572eSmbuhl * The latter two convert to float or double, respectively, and test csqrtf()
42c36e572eSmbuhl * and csqrt() with the same arguments.
43c36e572eSmbuhl */
44c36e572eSmbuhl static long double complex (*t_csqrt)(long double complex);
45c36e572eSmbuhl
46c36e572eSmbuhl static long double complex
_csqrtf(long double complex d)47c36e572eSmbuhl _csqrtf(long double complex d)
48c36e572eSmbuhl {
49c36e572eSmbuhl
50c36e572eSmbuhl return (csqrtf((float complex)d));
51c36e572eSmbuhl }
52c36e572eSmbuhl
53c36e572eSmbuhl static long double complex
_csqrt(long double complex d)54c36e572eSmbuhl _csqrt(long double complex d)
55c36e572eSmbuhl {
56c36e572eSmbuhl
57c36e572eSmbuhl return (csqrt((double complex)d));
58c36e572eSmbuhl }
59c36e572eSmbuhl
60c36e572eSmbuhl #pragma STDC CX_LIMITED_RANGE OFF
61c36e572eSmbuhl
62c36e572eSmbuhl /*
63c36e572eSmbuhl * Compare d1 and d2 using special rules: NaN == NaN and +0 != -0.
64c36e572eSmbuhl * Fail an assertion if they differ.
65c36e572eSmbuhl */
66c36e572eSmbuhl #define assert_equal(d1, d2) CHECK_CFPEQUAL_CS(d1, d2, CS_BOTH)
67c36e572eSmbuhl
68c36e572eSmbuhl /*
69c36e572eSmbuhl * Test csqrt for some finite arguments where the answer is exact.
70c36e572eSmbuhl * (We do not test if it produces correctly rounded answers when the
71c36e572eSmbuhl * result is inexact, nor do we check whether it throws spurious
72c36e572eSmbuhl * exceptions.)
73c36e572eSmbuhl */
74c36e572eSmbuhl static void
test_finite(void)75c36e572eSmbuhl test_finite(void)
76c36e572eSmbuhl {
77c36e572eSmbuhl static const double tests[] = {
78c36e572eSmbuhl /* csqrt(a + bI) = x + yI */
79c36e572eSmbuhl /* a b x y */
80c36e572eSmbuhl 0, 8, 2, 2,
81c36e572eSmbuhl 0, -8, 2, -2,
82c36e572eSmbuhl 4, 0, 2, 0,
83c36e572eSmbuhl -4, 0, 0, 2,
84c36e572eSmbuhl 3, 4, 2, 1,
85c36e572eSmbuhl 3, -4, 2, -1,
86c36e572eSmbuhl -3, 4, 1, 2,
87c36e572eSmbuhl -3, -4, 1, -2,
88c36e572eSmbuhl 5, 12, 3, 2,
89c36e572eSmbuhl 7, 24, 4, 3,
90c36e572eSmbuhl 9, 40, 5, 4,
91c36e572eSmbuhl 11, 60, 6, 5,
92c36e572eSmbuhl 13, 84, 7, 6,
93c36e572eSmbuhl 33, 56, 7, 4,
94c36e572eSmbuhl 39, 80, 8, 5,
95c36e572eSmbuhl 65, 72, 9, 4,
96c36e572eSmbuhl 987, 9916, 74, 67,
97c36e572eSmbuhl 5289, 6640, 83, 40,
98c36e572eSmbuhl 460766389075.0, 16762287900.0, 678910, 12345
99c36e572eSmbuhl };
100c36e572eSmbuhl /*
101c36e572eSmbuhl * We also test some multiples of the above arguments. This
102c36e572eSmbuhl * array defines which multiples we use. Note that these have
103c36e572eSmbuhl * to be small enough to not cause overflow for float precision
104c36e572eSmbuhl * with all of the constants in the above table.
105c36e572eSmbuhl */
106c36e572eSmbuhl static const double mults[] = {
107c36e572eSmbuhl 1,
108c36e572eSmbuhl 2,
109c36e572eSmbuhl 3,
110c36e572eSmbuhl 13,
111c36e572eSmbuhl 16,
112c36e572eSmbuhl 0x1.p30,
113c36e572eSmbuhl 0x1.p-30,
114c36e572eSmbuhl };
115c36e572eSmbuhl
116c36e572eSmbuhl double a, b;
117c36e572eSmbuhl double x, y;
118c36e572eSmbuhl unsigned i, j;
119c36e572eSmbuhl
120c36e572eSmbuhl for (i = 0; i < nitems(tests); i += 4) {
121c36e572eSmbuhl for (j = 0; j < nitems(mults); j++) {
122c36e572eSmbuhl a = tests[i] * mults[j] * mults[j];
123c36e572eSmbuhl b = tests[i + 1] * mults[j] * mults[j];
124c36e572eSmbuhl x = tests[i + 2] * mults[j];
125c36e572eSmbuhl y = tests[i + 3] * mults[j];
126c36e572eSmbuhl ATF_CHECK(t_csqrt(CMPLXL(a, b)) == CMPLXL(x, y));
127c36e572eSmbuhl }
128c36e572eSmbuhl }
129c36e572eSmbuhl
130c36e572eSmbuhl }
131c36e572eSmbuhl
132c36e572eSmbuhl /*
133c36e572eSmbuhl * Test the handling of +/- 0.
134c36e572eSmbuhl */
135c36e572eSmbuhl static void
test_zeros(void)136c36e572eSmbuhl test_zeros(void)
137c36e572eSmbuhl {
138c36e572eSmbuhl
139c36e572eSmbuhl assert_equal(t_csqrt(CMPLXL(0.0, 0.0)), CMPLXL(0.0, 0.0));
140c36e572eSmbuhl assert_equal(t_csqrt(CMPLXL(-0.0, 0.0)), CMPLXL(0.0, 0.0));
141c36e572eSmbuhl assert_equal(t_csqrt(CMPLXL(0.0, -0.0)), CMPLXL(0.0, -0.0));
142c36e572eSmbuhl assert_equal(t_csqrt(CMPLXL(-0.0, -0.0)), CMPLXL(0.0, -0.0));
143c36e572eSmbuhl }
144c36e572eSmbuhl
145c36e572eSmbuhl /*
146c36e572eSmbuhl * Test the handling of infinities when the other argument is not NaN.
147c36e572eSmbuhl */
148c36e572eSmbuhl static void
test_infinities(void)149c36e572eSmbuhl test_infinities(void)
150c36e572eSmbuhl {
151c36e572eSmbuhl static const double vals[] = {
152c36e572eSmbuhl 0.0,
153c36e572eSmbuhl -0.0,
154c36e572eSmbuhl 42.0,
155c36e572eSmbuhl -42.0,
156c36e572eSmbuhl INFINITY,
157c36e572eSmbuhl -INFINITY,
158c36e572eSmbuhl };
159c36e572eSmbuhl
160c36e572eSmbuhl unsigned i;
161c36e572eSmbuhl
162c36e572eSmbuhl for (i = 0; i < nitems(vals); i++) {
163c36e572eSmbuhl if (isfinite(vals[i])) {
164c36e572eSmbuhl assert_equal(t_csqrt(CMPLXL(-INFINITY, vals[i])),
165c36e572eSmbuhl CMPLXL(0.0, copysignl(INFINITY, vals[i])));
166c36e572eSmbuhl assert_equal(t_csqrt(CMPLXL(INFINITY, vals[i])),
167c36e572eSmbuhl CMPLXL(INFINITY, copysignl(0.0, vals[i])));
168c36e572eSmbuhl }
169c36e572eSmbuhl assert_equal(t_csqrt(CMPLXL(vals[i], INFINITY)),
170c36e572eSmbuhl CMPLXL(INFINITY, INFINITY));
171c36e572eSmbuhl assert_equal(t_csqrt(CMPLXL(vals[i], -INFINITY)),
172c36e572eSmbuhl CMPLXL(INFINITY, -INFINITY));
173c36e572eSmbuhl }
174c36e572eSmbuhl }
175c36e572eSmbuhl
176c36e572eSmbuhl /*
177c36e572eSmbuhl * Test the handling of NaNs.
178c36e572eSmbuhl */
179c36e572eSmbuhl static void
test_nans(void)180c36e572eSmbuhl test_nans(void)
181c36e572eSmbuhl {
182c36e572eSmbuhl
183c36e572eSmbuhl ATF_CHECK(creall(t_csqrt(CMPLXL(INFINITY, NAN))) == INFINITY);
184c36e572eSmbuhl ATF_CHECK(isnan(cimagl(t_csqrt(CMPLXL(INFINITY, NAN)))));
185c36e572eSmbuhl
186c36e572eSmbuhl ATF_CHECK(isnan(creall(t_csqrt(CMPLXL(-INFINITY, NAN)))));
187c36e572eSmbuhl ATF_CHECK(isinf(cimagl(t_csqrt(CMPLXL(-INFINITY, NAN)))));
188c36e572eSmbuhl
189c36e572eSmbuhl assert_equal(t_csqrt(CMPLXL(NAN, INFINITY)),
190c36e572eSmbuhl CMPLXL(INFINITY, INFINITY));
191c36e572eSmbuhl assert_equal(t_csqrt(CMPLXL(NAN, -INFINITY)),
192c36e572eSmbuhl CMPLXL(INFINITY, -INFINITY));
193c36e572eSmbuhl
194c36e572eSmbuhl assert_equal(t_csqrt(CMPLXL(0.0, NAN)), CMPLXL(NAN, NAN));
195c36e572eSmbuhl assert_equal(t_csqrt(CMPLXL(-0.0, NAN)), CMPLXL(NAN, NAN));
196c36e572eSmbuhl assert_equal(t_csqrt(CMPLXL(42.0, NAN)), CMPLXL(NAN, NAN));
197c36e572eSmbuhl assert_equal(t_csqrt(CMPLXL(-42.0, NAN)), CMPLXL(NAN, NAN));
198c36e572eSmbuhl assert_equal(t_csqrt(CMPLXL(NAN, 0.0)), CMPLXL(NAN, NAN));
199c36e572eSmbuhl assert_equal(t_csqrt(CMPLXL(NAN, -0.0)), CMPLXL(NAN, NAN));
200c36e572eSmbuhl assert_equal(t_csqrt(CMPLXL(NAN, 42.0)), CMPLXL(NAN, NAN));
201c36e572eSmbuhl assert_equal(t_csqrt(CMPLXL(NAN, -42.0)), CMPLXL(NAN, NAN));
202c36e572eSmbuhl assert_equal(t_csqrt(CMPLXL(NAN, NAN)), CMPLXL(NAN, NAN));
203c36e572eSmbuhl }
204c36e572eSmbuhl
205c36e572eSmbuhl /*
206c36e572eSmbuhl * Test whether csqrt(a + bi) works for inputs that are large enough to
207c36e572eSmbuhl * cause overflow in hypot(a, b) + a. Each of the tests is scaled up to
208c36e572eSmbuhl * near MAX_EXP.
209c36e572eSmbuhl */
210c36e572eSmbuhl static void
test_overflow(int maxexp)211c36e572eSmbuhl test_overflow(int maxexp)
212c36e572eSmbuhl {
213c36e572eSmbuhl long double a, b;
214c36e572eSmbuhl long double complex result;
215c36e572eSmbuhl int exp, i;
216c36e572eSmbuhl
217c36e572eSmbuhl ATF_CHECK(maxexp > 0 && maxexp % 2 == 0);
218c36e572eSmbuhl
219c36e572eSmbuhl for (i = 0; i < 4; i++) {
220c36e572eSmbuhl exp = maxexp - 2 * i;
221c36e572eSmbuhl
222c36e572eSmbuhl /* csqrt(115 + 252*I) == 14 + 9*I */
223c36e572eSmbuhl a = ldexpl(115 * 0x1p-8, exp);
224c36e572eSmbuhl b = ldexpl(252 * 0x1p-8, exp);
225c36e572eSmbuhl result = t_csqrt(CMPLXL(a, b));
226c36e572eSmbuhl ATF_CHECK_EQ(creall(result), ldexpl(14 * 0x1p-4, exp / 2));
227c36e572eSmbuhl ATF_CHECK_EQ(cimagl(result), ldexpl(9 * 0x1p-4, exp / 2));
228c36e572eSmbuhl
229c36e572eSmbuhl /* csqrt(-11 + 60*I) = 5 + 6*I */
230c36e572eSmbuhl a = ldexpl(-11 * 0x1p-6, exp);
231c36e572eSmbuhl b = ldexpl(60 * 0x1p-6, exp);
232c36e572eSmbuhl result = t_csqrt(CMPLXL(a, b));
233c36e572eSmbuhl ATF_CHECK_EQ(creall(result), ldexpl(5 * 0x1p-3, exp / 2));
234c36e572eSmbuhl ATF_CHECK_EQ(cimagl(result), ldexpl(6 * 0x1p-3, exp / 2));
235c36e572eSmbuhl
236c36e572eSmbuhl /* csqrt(225 + 0*I) == 15 + 0*I */
237c36e572eSmbuhl a = ldexpl(225 * 0x1p-8, exp);
238c36e572eSmbuhl b = 0;
239c36e572eSmbuhl result = t_csqrt(CMPLXL(a, b));
240c36e572eSmbuhl ATF_CHECK_EQ(creall(result), ldexpl(15 * 0x1p-4, exp / 2));
241c36e572eSmbuhl ATF_CHECK_EQ(cimagl(result), 0);
242c36e572eSmbuhl }
243c36e572eSmbuhl }
244c36e572eSmbuhl
245c36e572eSmbuhl /*
246c36e572eSmbuhl * Test that precision is maintained for some large squares. Set all or
247c36e572eSmbuhl * some bits in the lower mantdig/2 bits, square the number, and try to
248c36e572eSmbuhl * recover the sqrt. Note:
249c36e572eSmbuhl * (x + xI)**2 = 2xxI
250c36e572eSmbuhl */
251c36e572eSmbuhl static void
test_precision(int maxexp,int mantdig)252c36e572eSmbuhl test_precision(int maxexp, int mantdig)
253c36e572eSmbuhl {
254c36e572eSmbuhl long double b, x;
255c36e572eSmbuhl long double complex result;
256c36e572eSmbuhl #if LDBL_MANT_DIG <= 64
257c36e572eSmbuhl typedef uint64_t ldbl_mant_type;
258c36e572eSmbuhl #elif LDBL_MANT_DIG <= 128
259c36e572eSmbuhl typedef __uint128_t ldbl_mant_type;
260c36e572eSmbuhl #else
261c36e572eSmbuhl #error "Unsupported long double format"
262c36e572eSmbuhl #endif
263c36e572eSmbuhl ldbl_mant_type mantbits, sq_mantbits;
264c36e572eSmbuhl int exp, i;
265c36e572eSmbuhl
266c36e572eSmbuhl ATF_REQUIRE(maxexp > 0 && maxexp % 2 == 0);
267c36e572eSmbuhl ATF_REQUIRE(mantdig <= LDBL_MANT_DIG);
268c36e572eSmbuhl mantdig = rounddown(mantdig, 2);
269c36e572eSmbuhl
270c36e572eSmbuhl for (exp = 0; exp <= maxexp; exp += 2) {
271c36e572eSmbuhl mantbits = ((ldbl_mant_type)1 << (mantdig / 2)) - 1;
272c36e572eSmbuhl for (i = 0; i < 100 &&
273c36e572eSmbuhl mantbits > ((ldbl_mant_type)1 << (mantdig / 2 - 1));
274c36e572eSmbuhl i++, mantbits--) {
275c36e572eSmbuhl sq_mantbits = mantbits * mantbits;
276c36e572eSmbuhl /*
277c36e572eSmbuhl * sq_mantibts is a mantdig-bit number. Divide by
278c36e572eSmbuhl * 2**mantdig to normalize it to [0.5, 1), where,
279c36e572eSmbuhl * note, the binary power will be -1. Raise it by
280c36e572eSmbuhl * 2**exp for the test. exp is even. Lower it by
281c36e572eSmbuhl * one to reach a final binary power which is also
282c36e572eSmbuhl * even. The result should be exactly
283c36e572eSmbuhl * representable, given that mantdig is less than or
284c36e572eSmbuhl * equal to the available precision.
285c36e572eSmbuhl */
286c36e572eSmbuhl b = ldexpl((long double)sq_mantbits,
287c36e572eSmbuhl exp - 1 - mantdig);
288c36e572eSmbuhl x = ldexpl(mantbits, (exp - 2 - mantdig) / 2);
289c36e572eSmbuhl CHECK_FPEQUAL(b, x * x * 2);
290c36e572eSmbuhl result = t_csqrt(CMPLXL(0, b));
291c36e572eSmbuhl CHECK_FPEQUAL(x, creall(result));
292c36e572eSmbuhl CHECK_FPEQUAL(x, cimagl(result));
293c36e572eSmbuhl }
294c36e572eSmbuhl }
295c36e572eSmbuhl }
296c36e572eSmbuhl
297c36e572eSmbuhl ATF_TC_WITHOUT_HEAD(csqrt);
ATF_TC_BODY(csqrt,tc)298c36e572eSmbuhl ATF_TC_BODY(csqrt, tc)
299c36e572eSmbuhl {
300c36e572eSmbuhl /* Test csqrt() */
301c36e572eSmbuhl t_csqrt = _csqrt;
302c36e572eSmbuhl
303c36e572eSmbuhl test_finite();
304c36e572eSmbuhl
305c36e572eSmbuhl test_zeros();
306c36e572eSmbuhl
307c36e572eSmbuhl test_infinities();
308c36e572eSmbuhl
309c36e572eSmbuhl test_nans();
310c36e572eSmbuhl
311c36e572eSmbuhl test_overflow(DBL_MAX_EXP);
312c36e572eSmbuhl
313c36e572eSmbuhl test_precision(DBL_MAX_EXP, DBL_MANT_DIG);
314c36e572eSmbuhl }
315c36e572eSmbuhl
316c36e572eSmbuhl ATF_TC_WITHOUT_HEAD(csqrtf);
ATF_TC_BODY(csqrtf,tc)317c36e572eSmbuhl ATF_TC_BODY(csqrtf, tc)
318c36e572eSmbuhl {
319c36e572eSmbuhl /* Now test csqrtf() */
320c36e572eSmbuhl t_csqrt = _csqrtf;
321c36e572eSmbuhl
322c36e572eSmbuhl test_finite();
323c36e572eSmbuhl
324c36e572eSmbuhl test_zeros();
325c36e572eSmbuhl
326c36e572eSmbuhl test_infinities();
327c36e572eSmbuhl
328c36e572eSmbuhl test_nans();
329c36e572eSmbuhl
330c36e572eSmbuhl test_overflow(FLT_MAX_EXP);
331c36e572eSmbuhl
332c36e572eSmbuhl test_precision(FLT_MAX_EXP, FLT_MANT_DIG);
333c36e572eSmbuhl }
334c36e572eSmbuhl
335c36e572eSmbuhl ATF_TC_WITHOUT_HEAD(csqrtl);
ATF_TC_BODY(csqrtl,tc)336c36e572eSmbuhl ATF_TC_BODY(csqrtl, tc)
337c36e572eSmbuhl {
338c36e572eSmbuhl /* Now test csqrtl() */
339c36e572eSmbuhl t_csqrt = csqrtl;
340c36e572eSmbuhl
341c36e572eSmbuhl test_finite();
342c36e572eSmbuhl
343c36e572eSmbuhl test_zeros();
344c36e572eSmbuhl
345c36e572eSmbuhl test_infinities();
346c36e572eSmbuhl
347c36e572eSmbuhl test_nans();
348c36e572eSmbuhl
349c36e572eSmbuhl test_overflow(LDBL_MAX_EXP);
350c36e572eSmbuhl
351c36e572eSmbuhl /* i386 is configured to use 53-bit rounding precision for long double. */
352c36e572eSmbuhl #ifndef __i386__
353c36e572eSmbuhl test_precision(LDBL_MAX_EXP, LDBL_MANT_DIG);
354c36e572eSmbuhl #else
355c36e572eSmbuhl test_precision(LDBL_MAX_EXP, DBL_MANT_DIG);
356c36e572eSmbuhl #endif
357c36e572eSmbuhl }
358c36e572eSmbuhl
ATF_TP_ADD_TCS(tp)359c36e572eSmbuhl ATF_TP_ADD_TCS(tp)
360c36e572eSmbuhl {
361c36e572eSmbuhl ATF_TP_ADD_TC(tp, csqrt);
362c36e572eSmbuhl ATF_TP_ADD_TC(tp, csqrtf);
363c36e572eSmbuhl ATF_TP_ADD_TC(tp, csqrtl);
364c36e572eSmbuhl
365c36e572eSmbuhl return (atf_no_error());
366c36e572eSmbuhl }
367