1/* $NetBSD: catrigf.c,v 1.2 2022/04/19 20:32:16 rillig Exp $ */ 2/*- 3 * Copyright (c) 2012 Stephen Montgomery-Smith <stephen@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#if 0 44__FBSDID("$FreeBSD: head/lib/msun/src/catrigf.c 275819 2014-12-16 09:21:56Z ed $"); 45#endif 46__RCSID("$NetBSD: catrigf.c,v 1.2 2022/04/19 20:32:16 rillig Exp $"); 47 48#include "namespace.h" 49#ifdef __weak_alias 50__weak_alias(casinf, _casinf) 51#endif 52#ifdef __weak_alias 53__weak_alias(catanf, _catanf) 54#endif 55 56 57#include <complex.h> 58#include <float.h> 59 60#include "math.h" 61#include "math_private.h" 62 63#undef isinf 64#define isinf(x) (fabsf(x) == INFINITY) 65#undef isnan 66#define isnan(x) ((x) != (x)) 67#define raise_inexact() do { volatile float junk __unused = /*LINTED*/1 + tiny; } while (0) 68#undef signbit 69#define signbit(x) (__builtin_signbitf(x)) 70 71static const float 72A_crossover = 10, 73B_crossover = 0.6417, 74FOUR_SQRT_MIN = 0x1p-61, 75QUARTER_SQRT_MAX = 0x1p61, 76m_e = 2.7182818285e0, /* 0xadf854.0p-22 */ 77m_ln2 = 6.9314718056e-1, /* 0xb17218.0p-24 */ 78pio2_hi = 1.5707962513e0, /* 0xc90fda.0p-23 */ 79RECIP_EPSILON = 1 / FLT_EPSILON, 80SQRT_3_EPSILON = 5.9801995673e-4, /* 0x9cc471.0p-34 */ 81SQRT_6_EPSILON = 8.4572793338e-4, /* 0xddb3d7.0p-34 */ 82SQRT_MIN = 0x1p-63; 83 84static const volatile float 85pio2_lo = 7.5497899549e-8, /* 0xa22169.0p-47 */ 86tiny = 0x1p-100; 87 88static float complex clog_for_large_values(float complex z); 89 90static inline float 91f(float a, float b, float hypot_a_b) 92{ 93 if (b < 0) 94 return ((hypot_a_b - b) / 2); 95 if (b == 0) 96 return (a / 2); 97 return (a * a / (hypot_a_b + b) / 2); 98} 99 100static inline void 101do_hard_work(float x, float y, float *rx, int *B_is_usable, float *B, 102 float *sqrt_A2my2, float *new_y) 103{ 104 float R, S, A; 105 float Am1, Amy; 106 107 R = hypotf(x, y + 1); 108 S = hypotf(x, y - 1); 109 110 A = (R + S) / 2; 111 if (A < 1) 112 A = 1; 113 114 if (A < A_crossover) { 115 if (y == 1 && x < FLT_EPSILON * FLT_EPSILON / 128) { 116 *rx = sqrtf(x); 117 } else if (x >= FLT_EPSILON * fabsf(y - 1)) { 118 Am1 = f(x, 1 + y, R) + f(x, 1 - y, S); 119 *rx = log1pf(Am1 + sqrtf(Am1 * (A + 1))); 120 } else if (y < 1) { 121 *rx = x / sqrtf((1 - y) * (1 + y)); 122 } else { 123 *rx = log1pf((y - 1) + sqrtf((y - 1) * (y + 1))); 124 } 125 } else { 126 *rx = logf(A + sqrtf(A * A - 1)); 127 } 128 129 *new_y = y; 130 131 if (y < FOUR_SQRT_MIN) { 132 *B_is_usable = 0; 133 *sqrt_A2my2 = A * (2 / FLT_EPSILON); 134 *new_y = y * (2 / FLT_EPSILON); 135 return; 136 } 137 138 *B = y / A; 139 *B_is_usable = 1; 140 141 if (*B > B_crossover) { 142 *B_is_usable = 0; 143 if (y == 1 && x < FLT_EPSILON / 128) { 144 *sqrt_A2my2 = sqrtf(x) * sqrtf((A + y) / 2); 145 } else if (x >= FLT_EPSILON * fabsf(y - 1)) { 146 Amy = f(x, y + 1, R) + f(x, y - 1, S); 147 *sqrt_A2my2 = sqrtf(Amy * (A + y)); 148 } else if (y > 1) { 149 *sqrt_A2my2 = x * (4 / FLT_EPSILON / FLT_EPSILON) * y / 150 sqrtf((y + 1) * (y - 1)); 151 *new_y = y * (4 / FLT_EPSILON / FLT_EPSILON); 152 } else { 153 *sqrt_A2my2 = sqrtf((1 - y) * (1 + y)); 154 } 155 } 156} 157 158float complex 159casinhf(float complex z) 160{ 161 float x, y, ax, ay, rx, ry, B, sqrt_A2my2, new_y; 162 int B_is_usable; 163 float complex w; 164 165 x = crealf(z); 166 y = cimagf(z); 167 ax = fabsf(x); 168 ay = fabsf(y); 169 170 if (isnan(x) || isnan(y)) { 171 if (isinf(x)) 172 return (CMPLXF(x, y + y)); 173 if (isinf(y)) 174 return (CMPLXF(y, x + x)); 175 if (y == 0) 176 return (CMPLXF(x + x, y)); 177 return (CMPLXF(x + 0.0L + (y + 0), x + 0.0L + (y + 0))); 178 } 179 180 if (ax > RECIP_EPSILON || ay > RECIP_EPSILON) { 181 if (signbit(x) == 0) 182 w = clog_for_large_values(z) + m_ln2; 183 else 184 w = clog_for_large_values(-z) + m_ln2; 185 return (CMPLXF(copysignf(crealf(w), x), 186 copysignf(cimagf(w), y))); 187 } 188 189 if (x == 0 && y == 0) 190 return (z); 191 192 raise_inexact(); 193 194 if (ax < SQRT_6_EPSILON / 4 && ay < SQRT_6_EPSILON / 4) 195 return (z); 196 197 do_hard_work(ax, ay, &rx, &B_is_usable, &B, &sqrt_A2my2, &new_y); 198 if (B_is_usable) 199 ry = asinf(B); 200 else 201 ry = atan2f(new_y, sqrt_A2my2); 202 return (CMPLXF(copysignf(rx, x), copysignf(ry, y))); 203} 204 205float complex 206casinf(float complex z) 207{ 208 float complex w = casinhf(CMPLXF(cimagf(z), crealf(z))); 209 210 return (CMPLXF(cimagf(w), crealf(w))); 211} 212 213float complex 214cacosf(float complex z) 215{ 216 float x, y, ax, ay, rx, ry, B, sqrt_A2mx2, new_x; 217 int sx, sy; 218 int B_is_usable; 219 float complex w; 220 221 x = crealf(z); 222 y = cimagf(z); 223 sx = signbit(x); 224 sy = signbit(y); 225 ax = fabsf(x); 226 ay = fabsf(y); 227 228 if (isnan(x) || isnan(y)) { 229 if (isinf(x)) 230 return (CMPLXF(y + y, -INFINITY)); 231 if (isinf(y)) 232 return (CMPLXF(x + x, -y)); 233 if (x == 0) 234 return (CMPLXF(pio2_hi + pio2_lo, y + y)); 235 return (CMPLXF(x + 0.0L + (y + 0), x + 0.0L + (y + 0))); 236 } 237 238 if (ax > RECIP_EPSILON || ay > RECIP_EPSILON) { 239 w = clog_for_large_values(z); 240 rx = fabsf(cimagf(w)); 241 ry = crealf(w) + m_ln2; 242 if (sy == 0) 243 ry = -ry; 244 return (CMPLXF(rx, ry)); 245 } 246 247 if (x == 1 && y == 0) 248 return (CMPLXF(0, -y)); 249 250 raise_inexact(); 251 252 if (ax < SQRT_6_EPSILON / 4 && ay < SQRT_6_EPSILON / 4) 253 return (CMPLXF(pio2_hi - (x - pio2_lo), -y)); 254 255 do_hard_work(ay, ax, &ry, &B_is_usable, &B, &sqrt_A2mx2, &new_x); 256 if (B_is_usable) { 257 if (sx == 0) 258 rx = acosf(B); 259 else 260 rx = acosf(-B); 261 } else { 262 if (sx == 0) 263 rx = atan2f(sqrt_A2mx2, new_x); 264 else 265 rx = atan2f(sqrt_A2mx2, -new_x); 266 } 267 if (sy == 0) 268 ry = -ry; 269 return (CMPLXF(rx, ry)); 270} 271 272float complex 273cacoshf(float complex z) 274{ 275 float complex w; 276 float rx, ry; 277 278 w = cacosf(z); 279 rx = crealf(w); 280 ry = cimagf(w); 281 if (isnan(rx) && isnan(ry)) 282 return (CMPLXF(ry, rx)); 283 if (isnan(rx)) 284 return (CMPLXF(fabsf(ry), rx)); 285 if (isnan(ry)) 286 return (CMPLXF(ry, ry)); 287 return (CMPLXF(fabsf(ry), copysignf(rx, cimagf(z)))); 288} 289 290static float complex 291clog_for_large_values(float complex z) 292{ 293 float x, y; 294 float ax, ay, t; 295 296 x = crealf(z); 297 y = cimagf(z); 298 ax = fabsf(x); 299 ay = fabsf(y); 300 if (ax < ay) { 301 t = ax; 302 ax = ay; 303 ay = t; 304 } 305 306 if (ax > FLT_MAX / 2) 307 return (CMPLXF(logf(hypotf(x / m_e, y / m_e)) + 1, 308 atan2f(y, x))); 309 310 if (ax > QUARTER_SQRT_MAX || ay < SQRT_MIN) 311 return (CMPLXF(logf(hypotf(x, y)), atan2f(y, x))); 312 313 return (CMPLXF(logf(ax * ax + ay * ay) / 2, atan2f(y, x))); 314} 315 316static inline float 317sum_squares(float x, float y) 318{ 319 320 if (y < SQRT_MIN) 321 return (x * x); 322 323 return (x * x + y * y); 324} 325 326static inline float 327real_part_reciprocal(float x, float y) 328{ 329 float scale; 330 uint32_t hx, hy; 331 int32_t ix, iy; 332 333 GET_FLOAT_WORD(hx, x); 334 ix = hx & 0x7f800000; 335 GET_FLOAT_WORD(hy, y); 336 iy = hy & 0x7f800000; 337#define BIAS (FLT_MAX_EXP - 1) 338#define CUTOFF (FLT_MANT_DIG / 2 + 1) 339 if (ix - iy >= CUTOFF << 23 || isinf(x)) 340 return (1 / x); 341 if (iy - ix >= CUTOFF << 23) 342 return (x / y / y); 343 if (ix <= (BIAS + FLT_MAX_EXP / 2 - CUTOFF) << 23) 344 return (x / (x * x + y * y)); 345 SET_FLOAT_WORD(scale, 0x7f800000 - ix); 346 x *= scale; 347 y *= scale; 348 return (x / (x * x + y * y) * scale); 349} 350 351float complex 352catanhf(float complex z) 353{ 354 float x, y, ax, ay, rx, ry; 355 356 x = crealf(z); 357 y = cimagf(z); 358 ax = fabsf(x); 359 ay = fabsf(y); 360 361 if (y == 0 && ax <= 1) 362 return (CMPLXF(atanhf(x), y)); 363 364 if (x == 0) 365 return (CMPLXF(x, atanf(y))); 366 367 if (isnan(x) || isnan(y)) { 368 if (isinf(x)) 369 return (CMPLXF(copysignf(0, x), y + y)); 370 if (isinf(y)) 371 return (CMPLXF(copysignf(0, x), 372 copysignf(pio2_hi + pio2_lo, y))); 373 return (CMPLXF(x + 0.0L + (y + 0), x + 0.0L + (y + 0))); 374 } 375 376 if (ax > RECIP_EPSILON || ay > RECIP_EPSILON) 377 return (CMPLXF(real_part_reciprocal(x, y), 378 copysignf(pio2_hi + pio2_lo, y))); 379 380 if (ax < SQRT_3_EPSILON / 2 && ay < SQRT_3_EPSILON / 2) { 381 raise_inexact(); 382 return (z); 383 } 384 385 if (ax == 1 && ay < FLT_EPSILON) 386 rx = (m_ln2 - logf(ay)) / 2; 387 else 388 rx = log1pf(4 * ax / sum_squares(ax - 1, ay)) / 4; 389 390 if (ax == 1) 391 ry = atan2f(2, -ay) / 2; 392 else if (ay < FLT_EPSILON) 393 ry = atan2f(2 * ay, (1 - ax) * (1 + ax)) / 2; 394 else 395 ry = atan2f(2 * ay, (1 - ax) * (1 + ax) - ay * ay) / 2; 396 397 return (CMPLXF(copysignf(rx, x), copysignf(ry, y))); 398} 399 400float complex 401catanf(float complex z) 402{ 403 float complex w = catanhf(CMPLXF(cimagf(z), crealf(z))); 404 405 return (CMPLXF(cimagf(w), crealf(w))); 406} 407