Home | History | Annotate | Download | only in src
      1 /*-
      2  * Copyright (c) 2012 Stephen Montgomery-Smith <stephen (at) FreeBSD.ORG>
      3  * Copyright (c) 2017 Mahdi Mokhtari <mmokhi (at) FreeBSD.org>
      4  * All rights reserved.
      5  *
      6  * Redistribution and use in source and binary forms, with or without
      7  * modification, are permitted provided that the following conditions
      8  * are met:
      9  * 1. Redistributions of source code must retain the above copyright
     10  *    notice, this list of conditions and the following disclaimer.
     11  * 2. Redistributions in binary form must reproduce the above copyright
     12  *    notice, this list of conditions and the following disclaimer in the
     13  *    documentation and/or other materials provided with the distribution.
     14  *
     15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
     16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     25  * SUCH DAMAGE.
     26  */
     27 
     28 /*
     29  * The algorithm is very close to that in "Implementing the complex arcsine
     30  * and arccosine functions using exception handling" by T. E. Hull, Thomas F.
     31  * Fairgrieve, and Ping Tak Peter Tang, published in ACM Transactions on
     32  * Mathematical Software, Volume 23 Issue 3, 1997, Pages 299-335,
     33  * http://dl.acm.org/citation.cfm?id=275324.
     34  *
     35  * See catrig.c for complete comments.
     36  *
     37  * XXX comments were removed automatically, and even short ones on the right
     38  * of statements were removed (all of them), contrary to normal style.  Only
     39  * a few comments on the right of declarations remain.
     40  */
     41 
     42 #include <sys/cdefs.h>
     43 __FBSDID("$FreeBSD: head/lib/msun/src/catrigl.c 336362 2018-07-17 07:42:14Z bde $");
     44 
     45 #include <complex.h>
     46 #include <float.h>
     47 
     48 #include "invtrig.h"
     49 #include "math.h"
     50 #include "math_private.h"
     51 
     52 #undef isinf
     53 #define isinf(x)	(fabsl(x) == INFINITY)
     54 #undef isnan
     55 #define isnan(x)	((x) != (x))
     56 #define	raise_inexact()	do { volatile float junk __unused = 1 + tiny; } while(0)
     57 #undef signbit
     58 #define signbit(x)	(__builtin_signbitl(x))
     59 
     60 #if LDBL_MAX_EXP != 0x4000
     61 #error "Unsupported long double format"
     62 #endif
     63 
     64 static const long double
     65 A_crossover =		10,
     66 B_crossover =		0.6417,
     67 FOUR_SQRT_MIN =		0x1p-8189L,
     68 HALF_MAX =		0x1p16383L,
     69 QUARTER_SQRT_MAX =	0x1p8189L,
     70 RECIP_EPSILON =		1 / LDBL_EPSILON,
     71 SQRT_MIN =		0x1p-8191L;
     72 
     73 #if LDBL_MANT_DIG == 64
     74 static const union IEEEl2bits
     75 um_e =		LD80C(0xadf85458a2bb4a9b,  1, 2.71828182845904523536e+0L),
     76 um_ln2 =	LD80C(0xb17217f7d1cf79ac, -1, 6.93147180559945309417e-1L);
     77 #define		m_e	um_e.e
     78 #define		m_ln2	um_ln2.e
     79 static const long double
     80 /* The next 2 literals for non-i386.  Misrounding them on i386 is harmless. */
     81 SQRT_3_EPSILON = 5.70316273435758915310e-10,	/*  0x9cc470a0490973e8.0p-94 */
     82 SQRT_6_EPSILON = 8.06549008734932771664e-10;	/*  0xddb3d742c265539e.0p-94 */
     83 #elif LDBL_MANT_DIG == 113
     84 static const long double
     85 m_e =		2.71828182845904523536028747135266250e0L,	/* 0x15bf0a8b1457695355fb8ac404e7a.0p-111 */
     86 m_ln2 =		6.93147180559945309417232121458176568e-1L,	/* 0x162e42fefa39ef35793c7673007e6.0p-113 */
     87 SQRT_3_EPSILON = 2.40370335797945490975336727199878124e-17,	/*  0x1bb67ae8584caa73b25742d7078b8.0p-168 */
     88 SQRT_6_EPSILON = 3.39934988877629587239082586223300391e-17;	/*  0x13988e1409212e7d0321914321a55.0p-167 */
     89 #else
     90 #error "Unsupported long double format"
     91 #endif
     92 
     93 static const volatile float
     94 tiny =			0x1p-100;
     95 
     96 static long double complex clog_for_large_values(long double complex z);
     97 
     98 static inline long double
     99 f(long double a, long double b, long double hypot_a_b)
    100 {
    101 	if (b < 0)
    102 		return ((hypot_a_b - b) / 2);
    103 	if (b == 0)
    104 		return (a / 2);
    105 	return (a * a / (hypot_a_b + b) / 2);
    106 }
    107 
    108 static inline void
    109 do_hard_work(long double x, long double y, long double *rx, int *B_is_usable,
    110     long double *B, long double *sqrt_A2my2, long double *new_y)
    111 {
    112 	long double R, S, A;
    113 	long double Am1, Amy;
    114 
    115 	R = hypotl(x, y + 1);
    116 	S = hypotl(x, y - 1);
    117 
    118 	A = (R + S) / 2;
    119 	if (A < 1)
    120 		A = 1;
    121 
    122 	if (A < A_crossover) {
    123 		if (y == 1 && x < LDBL_EPSILON * LDBL_EPSILON / 128) {
    124 			*rx = sqrtl(x);
    125 		} else if (x >= LDBL_EPSILON * fabsl(y - 1)) {
    126 			Am1 = f(x, 1 + y, R) + f(x, 1 - y, S);
    127 			*rx = log1pl(Am1 + sqrtl(Am1 * (A + 1)));
    128 		} else if (y < 1) {
    129 			*rx = x / sqrtl((1 - y) * (1 + y));
    130 		} else {
    131 			*rx = log1pl((y - 1) + sqrtl((y - 1) * (y + 1)));
    132 		}
    133 	} else {
    134 		*rx = logl(A + sqrtl(A * A - 1));
    135 	}
    136 
    137 	*new_y = y;
    138 
    139 	if (y < FOUR_SQRT_MIN) {
    140 		*B_is_usable = 0;
    141 		*sqrt_A2my2 = A * (2 / LDBL_EPSILON);
    142 		*new_y = y * (2 / LDBL_EPSILON);
    143 		return;
    144 	}
    145 
    146 	*B = y / A;
    147 	*B_is_usable = 1;
    148 
    149 	if (*B > B_crossover) {
    150 		*B_is_usable = 0;
    151 		if (y == 1 && x < LDBL_EPSILON / 128) {
    152 			*sqrt_A2my2 = sqrtl(x) * sqrtl((A + y) / 2);
    153 		} else if (x >= LDBL_EPSILON * fabsl(y - 1)) {
    154 			Amy = f(x, y + 1, R) + f(x, y - 1, S);
    155 			*sqrt_A2my2 = sqrtl(Amy * (A + y));
    156 		} else if (y > 1) {
    157 			*sqrt_A2my2 = x * (4 / LDBL_EPSILON / LDBL_EPSILON) * y /
    158 			    sqrtl((y + 1) * (y - 1));
    159 			*new_y = y * (4 / LDBL_EPSILON / LDBL_EPSILON);
    160 		} else {
    161 			*sqrt_A2my2 = sqrtl((1 - y) * (1 + y));
    162 		}
    163 	}
    164 }
    165 
    166 long double complex
    167 casinhl(long double complex z)
    168 {
    169 	long double x, y, ax, ay, rx, ry, B, sqrt_A2my2, new_y;
    170 	int B_is_usable;
    171 	long double complex w;
    172 
    173 	x = creall(z);
    174 	y = cimagl(z);
    175 	ax = fabsl(x);
    176 	ay = fabsl(y);
    177 
    178 	if (isnan(x) || isnan(y)) {
    179 		if (isinf(x))
    180 			return (CMPLXL(x, y + y));
    181 		if (isinf(y))
    182 			return (CMPLXL(y, x + x));
    183 		if (y == 0)
    184 			return (CMPLXL(x + x, y));
    185 		return (CMPLXL(nan_mix(x, y), nan_mix(x, y)));
    186 	}
    187 
    188 	if (ax > RECIP_EPSILON || ay > RECIP_EPSILON) {
    189 		if (signbit(x) == 0)
    190 			w = clog_for_large_values(z) + m_ln2;
    191 		else
    192 			w = clog_for_large_values(-z) + m_ln2;
    193 		return (CMPLXL(copysignl(creall(w), x),
    194 		    copysignl(cimagl(w), y)));
    195 	}
    196 
    197 	if (x == 0 && y == 0)
    198 		return (z);
    199 
    200 	raise_inexact();
    201 
    202 	if (ax < SQRT_6_EPSILON / 4 && ay < SQRT_6_EPSILON / 4)
    203 		return (z);
    204 
    205 	do_hard_work(ax, ay, &rx, &B_is_usable, &B, &sqrt_A2my2, &new_y);
    206 	if (B_is_usable)
    207 		ry = asinl(B);
    208 	else
    209 		ry = atan2l(new_y, sqrt_A2my2);
    210 	return (CMPLXL(copysignl(rx, x), copysignl(ry, y)));
    211 }
    212 
    213 long double complex
    214 casinl(long double complex z)
    215 {
    216 	long double complex w;
    217 
    218 	w = casinhl(CMPLXL(cimagl(z), creall(z)));
    219 	return (CMPLXL(cimagl(w), creall(w)));
    220 }
    221 
    222 long double complex
    223 cacosl(long double complex z)
    224 {
    225 	long double x, y, ax, ay, rx, ry, B, sqrt_A2mx2, new_x;
    226 	int sx, sy;
    227 	int B_is_usable;
    228 	long double complex w;
    229 
    230 	x = creall(z);
    231 	y = cimagl(z);
    232 	sx = signbit(x);
    233 	sy = signbit(y);
    234 	ax = fabsl(x);
    235 	ay = fabsl(y);
    236 
    237 	if (isnan(x) || isnan(y)) {
    238 		if (isinf(x))
    239 			return (CMPLXL(y + y, -INFINITY));
    240 		if (isinf(y))
    241 			return (CMPLXL(x + x, -y));
    242 		if (x == 0)
    243 			return (CMPLXL(pio2_hi + pio2_lo, y + y));
    244 		return (CMPLXL(nan_mix(x, y), nan_mix(x, y)));
    245 	}
    246 
    247 	if (ax > RECIP_EPSILON || ay > RECIP_EPSILON) {
    248 		w = clog_for_large_values(z);
    249 		rx = fabsl(cimagl(w));
    250 		ry = creall(w) + m_ln2;
    251 		if (sy == 0)
    252 			ry = -ry;
    253 		return (CMPLXL(rx, ry));
    254 	}
    255 
    256 	if (x == 1 && y == 0)
    257 		return (CMPLXL(0, -y));
    258 
    259 	raise_inexact();
    260 
    261 	if (ax < SQRT_6_EPSILON / 4 && ay < SQRT_6_EPSILON / 4)
    262 		return (CMPLXL(pio2_hi - (x - pio2_lo), -y));
    263 
    264 	do_hard_work(ay, ax, &ry, &B_is_usable, &B, &sqrt_A2mx2, &new_x);
    265 	if (B_is_usable) {
    266 		if (sx == 0)
    267 			rx = acosl(B);
    268 		else
    269 			rx = acosl(-B);
    270 	} else {
    271 		if (sx == 0)
    272 			rx = atan2l(sqrt_A2mx2, new_x);
    273 		else
    274 			rx = atan2l(sqrt_A2mx2, -new_x);
    275 	}
    276 	if (sy == 0)
    277 		ry = -ry;
    278 	return (CMPLXL(rx, ry));
    279 }
    280 
    281 long double complex
    282 cacoshl(long double complex z)
    283 {
    284 	long double complex w;
    285 	long double rx, ry;
    286 
    287 	w = cacosl(z);
    288 	rx = creall(w);
    289 	ry = cimagl(w);
    290 	if (isnan(rx) && isnan(ry))
    291 		return (CMPLXL(ry, rx));
    292 	if (isnan(rx))
    293 		return (CMPLXL(fabsl(ry), rx));
    294 	if (isnan(ry))
    295 		return (CMPLXL(ry, ry));
    296 	return (CMPLXL(fabsl(ry), copysignl(rx, cimagl(z))));
    297 }
    298 
    299 static long double complex
    300 clog_for_large_values(long double complex z)
    301 {
    302 	long double x, y;
    303 	long double ax, ay, t;
    304 
    305 	x = creall(z);
    306 	y = cimagl(z);
    307 	ax = fabsl(x);
    308 	ay = fabsl(y);
    309 	if (ax < ay) {
    310 		t = ax;
    311 		ax = ay;
    312 		ay = t;
    313 	}
    314 
    315 	if (ax > HALF_MAX)
    316 		return (CMPLXL(logl(hypotl(x / m_e, y / m_e)) + 1,
    317 		    atan2l(y, x)));
    318 
    319 	if (ax > QUARTER_SQRT_MAX || ay < SQRT_MIN)
    320 		return (CMPLXL(logl(hypotl(x, y)), atan2l(y, x)));
    321 
    322 	return (CMPLXL(logl(ax * ax + ay * ay) / 2, atan2l(y, x)));
    323 }
    324 
    325 static inline long double
    326 sum_squares(long double x, long double y)
    327 {
    328 
    329 	if (y < SQRT_MIN)
    330 		return (x * x);
    331 
    332 	return (x * x + y * y);
    333 }
    334 
    335 static inline long double
    336 real_part_reciprocal(long double x, long double y)
    337 {
    338 	long double scale;
    339 	uint16_t hx, hy;
    340 	int16_t ix, iy;
    341 
    342 	GET_LDBL_EXPSIGN(hx, x);
    343 	ix = hx & 0x7fff;
    344 	GET_LDBL_EXPSIGN(hy, y);
    345 	iy = hy & 0x7fff;
    346 #define	BIAS	(LDBL_MAX_EXP - 1)
    347 #define	CUTOFF	(LDBL_MANT_DIG / 2 + 1)
    348 	if (ix - iy >= CUTOFF || isinf(x))
    349 		return (1 / x);
    350 	if (iy - ix >= CUTOFF)
    351 		return (x / y / y);
    352 	if (ix <= BIAS + LDBL_MAX_EXP / 2 - CUTOFF)
    353 		return (x / (x * x + y * y));
    354 	scale = 1;
    355 	SET_LDBL_EXPSIGN(scale, 0x7fff - ix);
    356 	x *= scale;
    357 	y *= scale;
    358 	return (x / (x * x + y * y) * scale);
    359 }
    360 
    361 long double complex
    362 catanhl(long double complex z)
    363 {
    364 	long double x, y, ax, ay, rx, ry;
    365 
    366 	x = creall(z);
    367 	y = cimagl(z);
    368 	ax = fabsl(x);
    369 	ay = fabsl(y);
    370 
    371 	if (y == 0 && ax <= 1)
    372 		return (CMPLXL(atanhl(x), y));
    373 
    374 	if (x == 0)
    375 		return (CMPLXL(x, atanl(y)));
    376 
    377 	if (isnan(x) || isnan(y)) {
    378 		if (isinf(x))
    379 			return (CMPLXL(copysignl(0, x), y + y));
    380 		if (isinf(y))
    381 			return (CMPLXL(copysignl(0, x),
    382 			    copysignl(pio2_hi + pio2_lo, y)));
    383 		return (CMPLXL(nan_mix(x, y), nan_mix(x, y)));
    384 	}
    385 
    386 	if (ax > RECIP_EPSILON || ay > RECIP_EPSILON)
    387 		return (CMPLXL(real_part_reciprocal(x, y),
    388 		    copysignl(pio2_hi + pio2_lo, y)));
    389 
    390 	if (ax < SQRT_3_EPSILON / 2 && ay < SQRT_3_EPSILON / 2) {
    391 		raise_inexact();
    392 		return (z);
    393 	}
    394 
    395 	if (ax == 1 && ay < LDBL_EPSILON)
    396 		rx = (m_ln2 - logl(ay)) / 2;
    397 	else
    398 		rx = log1pl(4 * ax / sum_squares(ax - 1, ay)) / 4;
    399 
    400 	if (ax == 1)
    401 		ry = atan2l(2, -ay) / 2;
    402 	else if (ay < LDBL_EPSILON)
    403 		ry = atan2l(2 * ay, (1 - ax) * (1 + ax)) / 2;
    404 	else
    405 		ry = atan2l(2 * ay, (1 - ax) * (1 + ax) - ay * ay) / 2;
    406 
    407 	return (CMPLXL(copysignl(rx, x), copysignl(ry, y)));
    408 }
    409 
    410 long double complex
    411 catanl(long double complex z)
    412 {
    413 	long double complex w;
    414 
    415 	w = catanhl(CMPLXL(cimagl(z), creall(z)));
    416 	return (CMPLXL(cimagl(w), creall(w)));
    417 }
    418