this repo has no description
at fixPythonPipStalling 2328 lines 80 kB view raw
1/* 2 * Copyright (c) 2002 Apple Computer, Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * The contents of this file constitute Original Code as defined in and 7 * are subject to the Apple Public Source License Version 1.1 (the 8 * "License"). You may not use this file except in compliance with the 9 * License. Please obtain a copy of the License at 10 * http://www.apple.com/publicsource and read it before using this file. 11 * 12 * This Original Code and all software distributed under the License are 13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER 14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the 17 * License for the specific language governing rights and limitations 18 * under the License. 19 * 20 * @APPLE_LICENSE_HEADER_END@ 21 */ 22 /**************************************************************************** 23** File: complex.c 24** 25** Contains: C source code for implementations of floating-point 26** (double) complex functions defined in header file 27** "complex.h" for PowerPC Macintoshes in native mode. 28** Transcendental function algorithms are based on the 29** paper "Branch Cuts for Complex Elementary Functions" 30** by W. Kahan, May 17, 1987, and on Pascal and C source 31** code for the SANE 80-/96-bit extended type by Kenton 32** Hanson and Paul Finlayson, respectively. 33** 34** 35** Written by: Jon Okada, SANEitation Engineer, ext. 4-4838 36** 37** Copyright: c 1987-1993 by Apple Computer, Inc., all rights reserved. 38** 39** Change History (most recent first): 40** 41** 25 Aug 93 ali Changed clog to cLog to avoid clashing with the 42** stream i/o definition clog. 43** 14 Jul 93 ali Added #pragma fenv_access on 44** 22 Feb 93 ali Added a nomaf #pragma. 45** 05 Feb 93 JPO Modified calls to feclearexcept and feraiseexcept 46** to reflect changes in "fenv.h". 47** 18 Dec 92 JPO First created. 48** 49****************************************************************************/ 50 51#pragma option nomaf 52#pragma STDC FENV_ACCESS ON 53 54#include "math.h" 55#include "complex.h" 56#include "fenv.h" 57#include "fp_private.h" 58 59#define Real(z) (__real__ z) 60#define Imag(z) (__imag__ z) 61 62/**************************************************************************** 63 CONSTANTS used by complex functions 64 65#include <stdio.h> 66#include <math.h> 67#include <float.h> 68main() 69{ 70 71float FPKASINHOM4f = asinhf(nextafterf(INFINITY,0.0f))/4.0f; 72float FPKTHETAf = sqrtf(nextafterf(INFINITY,0.0f))/4.0f; 73float FPKRHOf = 1.0f/FPKTHETAf; 74float FPKLOVEREf = FLT_MIN/FLT_EPSILON; 75 76printf("FPKASINHOM4 %16.7e %x\n", FPKASINHOM4f, *(int *)(&FPKASINHOM4f)); 77printf("FPKTHETA %16.7e %x\n", FPKTHETAf, *(int *)(&FPKTHETAf)); 78printf("FPKRHO %16.7e %x\n", FPKRHOf, *(int *)(&FPKRHOf)); 79printf("FPKLOVERE %16.7e %x\n", FPKLOVEREf, *(int *)(&FPKLOVEREf)); 80} 81 82****************************************************************************/ 83static const /* underflow threshold / round threshold */ 84 hexdouble FPKLOVERE = HEXDOUBLE(0x03600000,0x00000000); 85 86static const /* underflow threshold / round threshold */ 87 hexsingle FPKLOVEREf = { 0xc000000 }; 88 89static const /* exp(709.0) */ 90 hexdouble FPKEXP709 = HEXDOUBLE(0x7fdd422d,0x2be5dc9b); 91 92static const /* asinh(nextafterd(+infinity,0.0))/4.0 */ 93 hexdouble FPKASINHOM4 = HEXDOUBLE(0x406633ce,0x8fb9f87e); 94 95static const /* asinh(nextafterf(+infinity,0.0))/4.0 */ 96 hexsingle FPKASINHOM4f = { 0x41b2d4fc }; 97 98static const /* sqrt(nextafterd(+infinity,0.0))/4.0 */ 99 hexdouble FPKTHETA = HEXDOUBLE(0x5fcfffff,0xffffffff); 100 101static const /* sqrt(nextafterf(+infinity,0.0))/4.0 */ 102 hexsingle FPKTHETAf = { 0x5e7fffff }; 103 104static const /* 4.0/sqrt(nextafterd(+infinity,0.0)) */ 105 hexdouble FPKRHO = HEXDOUBLE(0x20100000,0x00000000); 106 107static const /* 4.0/sqrt(nextafterf(+infinity,0.0)) */ 108 hexsingle FPKRHOf = { 0x20800001 }; 109 110static 111double complex xdivc( double x, double complex y ) /* returns (real x) / (complex y) */ 112{ 113 double complex z; 114 double r, denom; 115 116 if ( fabs(Real(y)) >= fabs(Imag(y)) ) { /* |Real(y)| >= |Imag(y)| */ 117 if (fabs(Real(y)) == INFINITY) { /* Imag(y) and Real(y) are infinite */ 118 Real(z) = copysign(0.0,Real(y)); 119 Imag(z) = copysign(0.0,-Imag(y)); 120 } 121 else { /* |Real(y)| >= finite |Imag(y)| */ 122 r = Imag(y)/Real(y); 123 denom = Real(y) + Imag(y)*r; 124 Real(z) = x/denom; 125 Imag(z) = (-x*r)/denom; 126 } 127 } 128 129 else { /* |Real(y)| !>= |Imag(y)| */ 130 r = Real(y)/Imag(y); 131 denom = r*Real(y) + Imag(y); 132 Real(z) = (r*x)/denom; 133 Imag(z) = -x/denom; 134 } 135 136 return z; 137} 138 139static 140float complex xdivcf( float x, float complex y ) /* returns (real x) / (complex y) */ 141{ 142 float complex z; 143 float r, denom; 144 145 if ( fabsf(Real(y)) >= fabsf(Imag(y)) ) { /* |Real(y)| >= |Imag(y)| */ 146 if (fabsf(Real(y)) == INFINITY) { /* Imag(y) and Real(y) are infinite */ 147 Real(z) = copysignf(0.0f,Real(y)); 148 Imag(z) = copysignf(0.0f,-Imag(y)); 149 } 150 else { /* |Real(y)| >= finite |Imag(y)| */ 151 r = Imag(y)/Real(y); 152 denom = Real(y) + Imag(y)*r; 153 Real(z) = x/denom; 154 Imag(z) = (-x*r)/denom; 155 } 156 } 157 158 else { /* |Real(y)| !>= |Imag(y)| */ 159 r = Real(y)/Imag(y); 160 denom = r*Real(y) + Imag(y); 161 Real(z) = (r*x)/denom; 162 Imag(z) = -x/denom; 163 } 164 165 return z; 166} 167 168 169#if (__WANT_LONG_DOUBLE_FORMAT__ - 0L == 128L) 170 171static 172long double complex xdivcl( long double x, long double complex y ) /* returns (real x) / (complex y) */ 173{ 174 long double complex z; 175 long double r, denom; 176 177 if ( fabsl(Real(y)) >= fabsl(Imag(y)) ) { /* |Real(y)| >= |Imag(y)| */ 178 if (fabsl(Real(y)) == INFINITY) { /* Imag(y) and Real(y) are infinite */ 179 Real(z) = copysignl(0.0L,Real(y)); 180 Imag(z) = copysignl(0.0L,-Imag(y)); 181 } 182 else { /* |Real(y)| >= finite |Imag(y)| */ 183 r = Imag(y)/Real(y); 184 denom = Real(y) + Imag(y)*r; 185 Real(z) = x/denom; 186 Imag(z) = (-x*r)/denom; 187 } 188 } 189 190 else { /* |Real(y)| !>= |Imag(y)| */ 191 r = Real(y)/Imag(y); 192 denom = r*Real(y) + Imag(y); 193 Real(z) = (r*x)/denom; 194 Imag(z) = -x/denom; 195 } 196 197 return z; 198} 199#endif 200 201/**************************************************************************** 202 double cabs(double complex z) returns the absolute value (magnitude) of its 203 complex argument z, avoiding spurious overflow, underflow, and invalid 204 exceptions. The algorithm is from Kahan's paper. 205 206 CONSTANTS: FPKSQT2 = sqrt(2.0) to double precision 207 FPKR2P1 = sqrt(2.0) + 1.0 to double precision 208 FPKT2P1 = sqrt(2.0) + 1.0 - FPKR2P1 to double precision, so 209 that FPKR2P1 + FPKT2P1 = sqrt(2.0) + 1.0 to double 210 double precision. 211 212 Calls: fpclassify, fabs, sqrt, feholdexcept, fesetround, feclearexcept, 213 and feupdateenv. 214****************************************************************************/ 215 216extern double cabs( double complex ); 217float cabsf( float complex z ){ return (float) cabs((double complex) z); } 218 219#if (__WANT_LONG_DOUBLE_FORMAT__ - 0L == 128L) 220 221static const long double FPKEXP709L = 8.2184074615549721892413723865978e+307L; 222 223#define M_FPKT2P1Q -.0000000000000000000000000000000000014303281246230519268233202620092676L 224 225long double cabsl ( long double complex z ) 226{ 227 long double a,b,s,t; 228 fenv_t env; 229 long double FPR_inf = INFINITY; 230 231 a = fabsl(Real(z)); 232 b = fabsl(Imag(z)); 233 234 if (unlikely( (a == FPR_inf) || (b == FPR_inf) )) 235 return FPR_inf; 236 237 if (unlikely( (a != a) || (b != b) )) 238 return __FABS ( a + b ); 239 240 if (unlikely((a == 0.0L) || (b == 0.0L) )) 241 return __FABS ( a + b ); 242 243 /* both components of z are finite, nonzero */ 244 { 245 (void)feholdexcept(&env); /* save environment, clear flags */ 246 (void)fesetround(FE_TONEAREST); /* set default rounding */ 247 248 s = 0.0L; 249 if (a < b) /* order a >= b */ 250 { 251 t = a; 252 a = b; 253 b = t; 254 } 255 t = a - b; /* magnitude difference */ 256 257 if (t != a) /* b not negligible relative to a */ 258 { 259 if (t > b) /* a - b > b */ 260 { 261 s = a/b; 262 s += sqrtl(1.0L + s*s); 263 } 264 else /* a - b <= b */ 265 { 266 s = t/b; 267 t = (2.0L + s)*s; 268 s = ((M_FPKT2P1Q+t/(M_SQRT2+sqrt(2.0L+t)))+s)+(1.0L + M_SQRT2); 269 } 270 271 s = b/s; /* may spuriously underflow */ 272 feclearexcept(FE_UNDERFLOW); 273 } 274 275 feupdateenv(&env); /* restore environment */ 276 return (a + s); /* deserved overflow occurs here */ 277 } /* finite, nonzero case */ 278} 279#endif 280 281/**************************************************************************** 282 double carg(double complex z) returns the argument (in radians) of its 283 complex argument z. The algorithm is from Kahan's paper. 284 285 The argument of a complex number z = x + i*y is defined as atan2(y,x) 286 for finite x and y. 287 288 CONSTANTS: FPKPI2 = pi/2.0 to double precision 289 FPKPI = pi to double precision 290 291 Calls: fpclassify, copysign, fabs, atan 292****************************************************************************/ 293 294double carg ( double complex z ) 295{ 296 double a,b,argr; 297 int clre,clim; 298 299 a = Real(z); 300 b = Imag(z); 301 clre = fpclassify(a); 302 clim = fpclassify(b); 303 304 if ((clre == FP_ZERO) && (clim == FP_ZERO)) { /* zero real and imag parts */ 305 a = copysign(1.0, a); 306 } 307 308 if ((clre == FP_INFINITE) && (clim == FP_INFINITE)) { /* both parts INF */ 309 a = copysign(1.0, a); 310 b = copysign(1.0, b); 311 } 312 313 if (fabs(b) > fabs(a)) /* |imag| > |real| */ 314 argr = copysign(M_PI_2, b) - atan(a/b); 315 316 else { 317 if (a < 0.0) /* |real| >= |imag| */ 318 argr = copysign(M_PI, b) + atan(b/a); 319 else 320 argr = atan(b/a); 321 } 322 323 return argr; 324} 325 326float cargf ( float complex z ) 327{ 328 float a,b,argr; 329 int clre,clim; 330 331 a = Real(z); 332 b = Imag(z); 333 clre = fpclassify(a); 334 clim = fpclassify(b); 335 336 if ((clre == FP_ZERO) && (clim == FP_ZERO)) { /* zero real and imag parts */ 337 a = copysignf(1.0f, a); 338 } 339 340 if ((clre == FP_INFINITE) && (clim == FP_INFINITE)) { /* both parts INF */ 341 a = copysignf(1.0f, a); 342 b = copysignf(1.0f, b); 343 } 344 345 if (fabsf(b) > fabsf(a)) /* |imag| > |real| */ 346 argr = copysignf((float) M_PI_2, b) - atanf(a/b); 347 348 else { 349 if (a < 0.0f) /* |real| >= |imag| */ 350 argr = copysignf((float) M_PI, b) + atanf(b/a); 351 else 352 argr = atanf(b/a); 353 } 354 355 return argr; 356} 357 358#if (__WANT_LONG_DOUBLE_FORMAT__ - 0L == 128L) 359 360long double cargl ( long double complex z ) 361{ 362 long double a,b,argr; 363 int clre,clim; 364 365 a = Real(z); 366 b = Imag(z); 367 clre = fpclassify(a); 368 clim = fpclassify(b); 369 370 if ((clre == FP_ZERO) && (clim == FP_ZERO)) { /* zero real and imag parts */ 371 a = copysignl(1.0L, a); 372 } 373 374 if ((clre == FP_INFINITE) && (clim == FP_INFINITE)) { /* both parts INF */ 375 a = copysignl(1.0L, a); 376 b = copysignl(1.0L, b); 377 } 378 379 if (fabsl(b) > fabsl(a)) /* |imag| > |real| */ 380 argr = copysignl(M_PI_2, b) - atanl(a/b); 381 382 else { 383 if (a < 0.0L) /* |real| >= |imag| */ 384 argr = copysignl(M_PI, b) + atanl(b/a); 385 else 386 argr = atanl(b/a); 387 } 388 389 return argr; 390} 391#endif 392 393/**************************************************************************** 394 static double cssqs(double complex z, long int *k) returns rho = |z/(2^*k)|^2 395 with scale factor *k set to avoid overflow/underflow. Algorithm is 396 from the Kahan paper. 397 398 CONSTANTS: FPKINF = +infinity 399 FPKLOVERE = (double underflow threshold)/(double round threshold) 400 = (4.0*nextafterd(1.0,0.0)/nextafterd(INF,0.0)) 401 /(1.0 - nextafterd(1.0,0) 402 403 Calls: fabs, logb, scalb, fmax, feholdexcept, fetestexcept, feclearexcept, 404 and feupdateenv. 405 406 Called by: csqrt and clog. 407****************************************************************************/ 408 409static double cssqs ( double complex z, int *k) 410{ 411 double a,b,rho; 412 fenv_t env; 413 int iscale; 414 415 iscale = 0; 416 a = fabs(Real(z)); 417 b = fabs(Imag(z)); 418 (void)feholdexcept(&env); /* save environment, clr flags */ 419 rho = a*a + b*b; /* preliminary result */ 420 421 if ((a == INFINITY) || (b == INFINITY)) { 422 rho = INFINITY; /* +INF result if Real(z) or Imag(z) is infinite */ 423 } 424 425 else if (fetestexcept(FE_OVERFLOW) || (fetestexcept(FE_UNDERFLOW) && (rho < FPKLOVERE.d))) { 426 iscale = ilogb(fmax(a,b)); /* scaling necessary */ 427 a = scalbn(a,-iscale); 428 b = scalbn(b,-iscale); 429 rho = a*a + b*b; /* re-calculate scaled square magnitude */ 430 } 431 432 feclearexcept(FE_OVERFLOW + FE_UNDERFLOW); 433 feupdateenv(&env); /* restore environment */ 434 *k = iscale; /* store scale value */ 435 return (rho); 436} 437 438static float cssqsf ( float complex z, int *k) 439{ 440 float a,b,rho; 441 fenv_t env; 442 int iscale; 443 444 iscale = 0; 445 a = fabsf(Real(z)); 446 b = fabsf(Imag(z)); 447 (void)feholdexcept(&env); /* save environment, clr flags */ 448 rho = a*a + b*b; /* preliminary result */ 449 450 if ((a == INFINITY) || (b == INFINITY)) { 451 rho = INFINITY; /* +INF result if Real(z) or Imag(z) is infinite */ 452 } 453 454 else if (fetestexcept(FE_OVERFLOW) || (fetestexcept(FE_UNDERFLOW) && (rho < FPKLOVEREf.fval))) { 455 iscale = logbf(fmaxf(a,b)); /* scaling necessary */ 456 a = scalbnf(a,-iscale); 457 b = scalbnf(b,-iscale); 458 rho = a*a + b*b; /* re-calculate scaled square magnitude */ 459 } 460 461 feclearexcept(FE_OVERFLOW + FE_UNDERFLOW); 462 feupdateenv(&env); /* restore environment */ 463 *k = iscale; /* store scale value */ 464 return (rho); 465} 466 467#if (__WANT_LONG_DOUBLE_FORMAT__ - 0L == 128L) 468 469static long double cssqsl ( long double complex z, int *k) 470{ 471 long double a,b,rho; 472 fenv_t env; 473 int iscale; 474 475 iscale = 0; 476 a = fabsl(Real(z)); 477 b = fabsl(Imag(z)); 478 (void)feholdexcept(&env); /* save environment, clr flags */ 479 rho = a*a + b*b; /* preliminary result */ 480 481 if ((a == INFINITY) || (b == INFINITY)) { 482 rho = INFINITY; /* +INF result if Real(z) or Imag(z) is infinite */ 483 } 484 485 else if (fetestexcept(FE_OVERFLOW) || (fetestexcept(FE_UNDERFLOW) && (rho < FPKLOVERE.d))) { 486 iscale = logbl(fmaxl(a,b)); /* scaling necessary */ 487 a = scalbnl(a,-iscale); 488 b = scalbnl(b,-iscale); 489 rho = a*a + b*b; /* re-calculate scaled square magnitude */ 490 } 491 492 feclearexcept(FE_OVERFLOW + FE_UNDERFLOW); 493 feupdateenv(&env); /* restore environment */ 494 *k = iscale; /* store scale value */ 495 return (rho); 496} 497#endif 498 499/**************************************************************************** 500 double complex csqrt(double complex z) returns the complex square root of its argument. 501 The algorithm, which is from the Kahan paper, uses the following 502 identities: 503 504 sqrt(x + i*y) = sqrt((|z| + Real(z))/2) + i*sqrt((|z| - Real(z))/2) and 505 sqrt(x - i*y) = sqrt((|z| + Real(z))/2) - i*sqrt((|z| - Real(z))/2), 506 507 where y is positive and x may be positive or negative. 508 509 CONSTANTS: FPKINF = +infinity 510 511 Calls: cssqs, scalb, fabs, sqrt, copysign. 512****************************************************************************/ 513 514double complex csqrt ( double complex z ) 515{ 516 double rho,x,y; 517 double complex w; 518 int k; 519 520 rho = cssqs(z,&k); /* scaled square magnitude */ 521 522 if (Real(z) == Real(z)) 523 rho = scalbn(fabs(Real(z)),-k) + sqrt(rho); /* scaled |Real(z)| + |z| */ 524 525 if (k%2) /* k is odd */ 526 k = (k-1)/2; 527 else { /* k is even */ 528 k = k/2 - 1; 529 rho = rho + rho; 530 } 531 532 rho = scalbn(sqrt(rho),k); /* sqrt((|Real(z)| + |z|)/2) */ 533 x = rho; 534 y = Imag(z); 535 536 if (rho != 0.0) { 537 if (fabs(y) != INFINITY) 538 y = (y/rho)*0.5; /* signbit(Imag(z))*sqrt((|z|-|Real(z)|)/2 */ 539 if (Real(z) < 0.0) { 540 x = fabs(y); 541 y = copysign(rho,Imag(z)); 542 } 543 } 544 545 Real(w) = x; 546 Imag(w) = y; 547 return w; 548} 549 550float complex csqrtf ( float complex z ) 551{ 552 float rho,x,y; 553 float complex w; 554 int k; 555 556 rho = cssqsf(z,&k); /* scaled square magnitude */ 557 558 if (Real(z) == Real(z)) 559 rho = scalbnf(fabsf(Real(z)),-k) + sqrtf(rho); /* scaled |Real(z)| + |z| */ 560 561 if (k%2) /* k is odd */ 562 k = (k-1)/2; 563 else { /* k is even */ 564 k = k/2 - 1; 565 rho = rho + rho; 566 } 567 568 rho = scalbnf(sqrtf(rho),k); /* sqrt((|Real(z)| + |z|)/2) */ 569 x = rho; 570 y = Imag(z); 571 572 if (rho != 0.0f) { 573 if (fabsf(y) != INFINITY) 574 y = (y/rho)*0.5f; /* signbit(Imag(z))*sqrt((|z|-|Real(z)|)/2 */ 575 if (Real(z) < 0.0f) { 576 x = fabsf(y); 577 y = copysignf(rho,Imag(z)); 578 } 579 } 580 581 Real(w) = x; 582 Imag(w) = y; 583 return w; 584} 585 586#if (__WANT_LONG_DOUBLE_FORMAT__ - 0L == 128L) 587 588long double complex csqrtl ( long double complex z ) 589{ 590 long double rho,x,y; 591 long double complex w; 592 int k; 593 594 rho = cssqsl(z,&k); /* scaled square magnitude */ 595 596 if (Real(z) == Real(z)) 597 rho = scalbnl(fabsl(Real(z)),-k) + sqrtl(rho); /* scaled |Real(z)| + |z| */ 598 599 if (k%2) /* k is odd */ 600 k = (k-1)/2; 601 else { /* k is even */ 602 k = k/2 - 1; 603 rho = rho + rho; 604 } 605 606 rho = scalbnl(sqrtl(rho),k); /* sqrt((|Real(z)| + |z|)/2) */ 607 x = rho; 608 y = Imag(z); 609 610 if (rho != 0.0L) { 611 if (fabsl(y) != INFINITY) 612 y = (y/rho)*0.5L; /* signbit(Imag(z))*sqrt((|z|-|Real(z)|)/2 */ 613 if (Real(z) < 0.0L) { 614 x = fabsl(y); 615 y = copysignl(rho,Imag(z)); 616 } 617 } 618 619 Real(w) = x; 620 Imag(w) = y; 621 return w; 622} 623#endif 624 625/**************************************************************************** 626 double complex clog(double complex z) returns the complex natural logarithm of its 627 argument. The algorithm, which is from the Kahan paper, avoids spurious 628 underflow or overflow. 629 630 CONSTANTS: FPKSQRTHALF = sqrt(0.5) to double precision 631 FPKLOG2 = log(2.0) to double precision 632 633 Calls: fabs, cssqs, log1p, log, carg. 634****************************************************************************/ 635 636double complex clog ( double complex z ) 637{ 638 double rho,dmax,dmin,temp; 639 double complex w; 640 int k; 641 642 dmax = fabs(Real(z)); /* order real and imaginary parts of z by magnitude */ 643 dmin = fabs(Imag(z)); 644 if (dmax < dmin) { 645 temp = dmax; 646 dmax = dmin; 647 dmin = temp; 648 } 649 650 rho = cssqs(z,&k); /* scaled |z*z| */ 651 652 if ((k == 0) && (dmax > M_SQRT1_2) && ((dmax <= 1.25) || (rho < 3.0))) 653 Real(w) = log1p((dmax - 1.0)*(dmax + 1.0) + dmin*dmin)*0.5; /* |z| near 1.0 */ 654 else 655 Real(w) = log(rho)*0.5 + k*M_LN2; /* more naive approximation */ 656 657 Imag(w) = carg(z); /* imaginary part of logarithm */ 658 659 return w; 660} 661 662float complex clogf ( float complex z ) 663{ 664 float rho,dmax,dmin,temp; 665 float complex w; 666 int k; 667 668 dmax = fabsf(Real(z)); /* order real and imaginary parts of z by magnitude */ 669 dmin = fabsf(Imag(z)); 670 if (dmax < dmin) { 671 temp = dmax; 672 dmax = dmin; 673 dmin = temp; 674 } 675 676 rho = cssqsf(z,&k); /* scaled |z*z| */ 677 678 if ((k == 0) && (dmax > M_SQRT1_2) && ((dmax <= 1.25f) || (rho < 3.0f))) 679 Real(w) = log1pf((dmax - 1.0f)*(dmax + 1.0f) + dmin*dmin)*0.5f; /* |z| near 1.0 */ 680 else 681 Real(w) = logf(rho)*0.5f + (float)((double)k*M_LN2); /* more naive approximation */ 682 683 Imag(w) = cargf(z); /* imaginary part of logarithm */ 684 685 return w; 686} 687 688#if (__WANT_LONG_DOUBLE_FORMAT__ - 0L == 128L) 689 690long double complex clogl ( long double complex z ) 691{ 692 long double rho,dmax,dmin,temp; 693 long double complex w; 694 int k; 695 696 dmax = fabsl(Real(z)); /* order real and imaginary parts of z by magnitude */ 697 dmin = fabsl(Imag(z)); 698 if (dmax < dmin) { 699 temp = dmax; 700 dmax = dmin; 701 dmin = temp; 702 } 703 704 rho = cssqsl(z,&k); /* scaled |z*z| */ 705 706 if ((k == 0) && (dmax > M_SQRT1_2) && ((dmax <= 1.25L) || (rho < 3.0L))) 707 Real(w) = log1pl((dmax - 1.0L)*(dmax + 1.0L) + dmin*dmin)*0.5L; /* |z| near 1.0 */ 708 else 709 Real(w) = logl(rho)*0.5L + k*M_LN2; /* more naive approximation */ 710 711 Imag(w) = cargl(z); /* imaginary part of logarithm */ 712 713 return w; 714} 715#endif 716 717/**************************************************************************** 718 static double coshmul(double x, double y) returns y*cosh(x) while 719 avoiding spurious overflow and invalid exceptions. 720 721 CONSTANTS: FPKEXP709 = exp(709.0) in double precision 722 723 Calls: cosh, exp, fpclassify, fabs, and scalb. 724 725 Called by: csin, ccos, csinh, and ccosh. 726****************************************************************************/ 727 728static double coshmul ( double x, double y ) 729{ 730 double absx, result; 731 732 absx = fabs(x); 733 if (absx <= 709.0) { /* cosh(x) is finite */ 734 return y*cosh(x); 735 } 736 737 else if (fpclassify(x) < FP_ZERO) { /* x is NaN or infinite */ 738 return (y*absx); 739 } 740 741 else if (absx > 1460.0) { /* probable overflow case */ 742 return (scalbn(y,2100)); 743 } 744 745 else { /* cosh(x) overflows but y*cosh(x) may not */ 746 result = (0.5 * FPKEXP709.d) * y; /* initialize result to cosh(709) */ 747 absx -= 709.0; /* reduce exponential argument */ 748 while (absx > 709.0) { /* exponential reduction loop */ 749 result *= FPKEXP709.d; 750 absx -= 709.0; 751 } 752 return (result*exp(absx)); /* final multiplication */ 753 } 754} 755 756static float coshmulf ( float x, float y ) 757{ 758 float absx; 759 760 absx = fabsf(x); 761 if (absx <= 89.0f) { /* coshf(x) is finite */ 762 return y*coshf(x); 763 } 764 765 else if (fpclassify(x) < FP_ZERO) { /* x is NaN or infinite */ 766 return (y*absx); 767 } 768 769 return (float)coshmul((double)x, (double)y); 770} 771 772// long double has same range as double 773#if (__WANT_LONG_DOUBLE_FORMAT__ - 0L == 128L) 774 775static long double coshmull ( long double x, long double y ) 776{ 777 long double absx, result; 778 779 absx = fabsl(x); 780 if (absx <= 709.0L) { /* cosh(x) is finite */ 781 return y*coshl(x); 782 } 783 784 else if (fpclassify(x) < FP_ZERO) { /* x is NaN or infinite */ 785 return (y*absx); 786 } 787 788 else if (absx > 1460.0L) { /* probable overflow case */ 789 return (scalbnl(y,2100)); 790 } 791 792 else { /* cosh(x) overflows but y*cosh(x) may not */ 793 long double t = FPKEXP709L; 794 795 result = (0.5L * t) * y; /* initialize result to cosh(709) */ 796 absx -= 709.0L; /* reduce exponential argument */ 797 while (absx > 709.0L) { /* exponential reduction loop */ 798 result *= t; 799 absx -= 709.0L; 800 } 801 return (result*expl(absx)); /* final multiplication */ 802 } 803} 804#endif 805 806/**************************************************************************** 807 static double sinhmul(double x, double y) returns y*sinh(x) while 808 avoiding spurious overflow and invalid exceptions. 809 810 CONSTANTS: FPKEXP709 = exp(709.0) in double precision 811 812 Calls: sinh, exp, fpclassify, fabs, and scalb. 813 814 Called by: csin, ccos, csinh, and ccosh. 815****************************************************************************/ 816 817static double sinhmul ( double x, double y ) 818{ 819 double absx, result; 820 821 absx = fabs(x); 822 if (absx <= 709.0) { /* sinh(x) is finite */ 823 return y*sinh(x); 824 } 825 826 else if (fpclassify(x) < FP_ZERO) { /* x is NaN or infinite */ 827 return (y*x); 828 } 829 830 else if (absx > 1460.0) { /* probable overflow case */ 831 return (scalbn(y,2100)); 832 } 833 834 else { /* sinh(x) overflows but y*sinh(x) may not */ 835 result = (0.5*FPKEXP709.d)*y; /* initialize result to |sinh(709)| */ 836 absx -= 709.0; /* reduce exponential argument */ 837 if (signbit(x) != 0) result = -result; /* take care of sign of result */ 838 while (absx > 709.0) { /* exponential reduction loop */ 839 result *= FPKEXP709.d; 840 absx -= 709.0; 841 } 842 return (result*exp(absx)); /* final multiplication */ 843 } 844} 845 846static float sinhmulf ( float x, float y ) 847{ 848 float absx; 849 850 absx = fabsf(x); 851 if (absx <= 709.0f) { /* sinhf(x) is finite */ 852 return y*sinhf(x); 853 } 854 855 else if (fpclassify(x) < FP_ZERO) { /* x is NaN or infinite */ 856 return (y*x); 857 } 858 859 return (float)sinhmul((double)x, (double)y); 860} 861 862#if (__WANT_LONG_DOUBLE_FORMAT__ - 0L == 128L) 863 864static long double sinhmull ( long double x, long double y ) 865{ 866 long double absx, result; 867 868 absx = fabsl(x); 869 if (absx <= 709.0L) { /* sinh(x) is finite */ 870 return y*sinhl(x); 871 } 872 873 else if (fpclassify(x) < FP_ZERO) { /* x is NaN or infinite */ 874 return (y*x); 875 } 876 877 else if (absx > 1460.0L) { /* probable overflow case */ 878 return (scalbnl(y,2100)); 879 } 880 881 else { /* sinh(x) overflows but y*sinh(x) may not */ 882 long double t = FPKEXP709L; 883 884 result = (0.5L*t)*y; /* initialize result to y*|sinh(709)| */ 885 absx -= 709.0L; /* reduce exponential argument */ 886 if (signbit(x) != 0) result = -result; /* take care of sign of result */ 887 while (absx > 709.0L) { /* exponential reduction loop */ 888 result *= t; 889 absx -= 709.0L; 890 } 891 return (result*expl(absx)); /* final multiplication */ 892 } 893} 894#endif 895 896 897/**************************************************************************** 898 double complex csin(double complex z) returns the complex sine of its argument. The 899 algorithm is based upon the identity: 900 901 sin(x + i*y) = sin(x)*cosh(y) + i*cos(x)*sinh(y). 902 903 Signaling of spurious overflows, underflows, and invalids is avoided where 904 possible. 905 906 Calls: sin, cos, coshmul, sinhmul, feholdexcept, feclearexcept, and 907 feupdateenv. 908****************************************************************************/ 909 910double complex csin ( double complex z ) 911{ 912 fenv_t env; 913 double sinval, cosval; 914 double complex w; 915 916 (void)feholdexcept(&env); /* save environment, clear flags */ 917 sinval = sin(Real(z)); /* sine of real part of argument */ 918 cosval = cos(Real(z)); /* cosine of real part of argument */ 919 Real(w) = coshmul(Imag(z),sinval); /* real result = sinval*cosh(Imag(z)) */ 920 Imag(w) = sinhmul(Imag(z),cosval); /* imag result = cosval*sinh(Imag(z)) */ 921 feclearexcept(FE_UNDERFLOW); /* underflows don't matter */ 922 feupdateenv(&env); /* update environment */ 923 return w; 924} 925 926float complex csinf ( float complex z ) 927{ 928 fenv_t env; 929 float sinval, cosval; 930 float complex w; 931 932 (void)feholdexcept(&env); /* save environment, clear flags */ 933 sinval = sinf(Real(z)); /* sine of real part of argument */ 934 cosval = cosf(Real(z)); /* cosine of real part of argument */ 935 Real(w) = coshmulf(Imag(z),sinval); /* real result = sinval*cosh(Imag(z)) */ 936 Imag(w) = sinhmulf(Imag(z),cosval); /* imag result = cosval*sinh(Imag(z)) */ 937 feclearexcept(FE_UNDERFLOW); /* underflows don't matter */ 938 feupdateenv(&env); /* update environment */ 939 return w; 940} 941 942#if (__WANT_LONG_DOUBLE_FORMAT__ - 0L == 128L) 943 944long double complex csinl ( long double complex z ) 945{ 946 fenv_t env; 947 long double sinval, cosval; 948 long double complex w; 949 950 (void)feholdexcept(&env); /* save environment, clear flags */ 951 sinval = sinl(Real(z)); /* sine of real part of argument */ 952 cosval = cosl(Real(z)); /* cosine of real part of argument */ 953 Real(w) = coshmull(Imag(z),sinval); /* real result = sinval*cosh(Imag(z)) */ 954 Imag(w) = sinhmull(Imag(z),cosval); /* imag result = cosval*sinh(Imag(z)) */ 955 feclearexcept(FE_UNDERFLOW); /* underflows don't matter */ 956 feupdateenv(&env); /* update environment */ 957 return w; 958} 959#endif 960 961/**************************************************************************** 962 double complex ccos(double complex z) returns the complex cosine of its argument. The 963 algorithm is based upon the identity: 964 965 cos(x + i*y) = cos(x)*cosh(y) - i*sin(x)*sinh(y). 966 967 Signaling of spurious overflows, underflows, and invalids is avoided where 968 possible. 969 970 Calls: sin, cos, coshmul, sinhmul, feholdexcept, feclearexcept, and 971 feupdateenv. 972****************************************************************************/ 973 974double complex ccos ( double complex z ) 975{ 976 fenv_t env; 977 double sinval, cosval; 978 double complex w; 979 980 (void)feholdexcept(&env); /* save environment, clear flags */ 981 sinval = sin(Real(z)); /* sine of real part of argument */ 982 cosval = cos(Real(z)); /* cosine of real part of argument */ 983 Real(w) = coshmul(Imag(z),cosval); /* real result = cosval*cosh(Imag(z)) */ 984 Imag(w) = sinhmul(Imag(z),-sinval); /* imag result = -sinval*sinh(Imag(z)) */ 985 feclearexcept(FE_UNDERFLOW); /* underflows don't matter */ 986 feupdateenv(&env); /* update environment */ 987 return w; 988} 989 990float complex ccosf ( float complex z ) 991{ 992 fenv_t env; 993 float sinval, cosval; 994 float complex w; 995 996 (void)feholdexcept(&env); /* save environment, clear flags */ 997 sinval = sinf(Real(z)); /* sine of real part of argument */ 998 cosval = cosf(Real(z)); /* cosine of real part of argument */ 999 Real(w) = coshmulf(Imag(z),cosval); /* real result = cosval*cosh(Imag(z)) */ 1000 Imag(w) = sinhmulf(Imag(z),-sinval); /* imag result = -sinval*sinh(Imag(z)) */ 1001 feclearexcept(FE_UNDERFLOW); /* underflows don't matter */ 1002 feupdateenv(&env); /* update environment */ 1003 return w; 1004} 1005 1006#if (__WANT_LONG_DOUBLE_FORMAT__ - 0L == 128L) 1007 1008long double complex ccosl ( long double complex z ) 1009{ 1010 fenv_t env; 1011 long double sinval, cosval; 1012 long double complex w; 1013 1014 (void)feholdexcept(&env); /* save environment, clear flags */ 1015 sinval = sinl(Real(z)); /* sine of real part of argument */ 1016 cosval = cosl(Real(z)); /* cosine of real part of argument */ 1017 Real(w) = coshmull(Imag(z),cosval); /* real result = cosval*cosh(Imag(z)) */ 1018 Imag(w) = sinhmull(Imag(z),-sinval); /* imag result = -sinval*sinh(Imag(z)) */ 1019 feclearexcept(FE_UNDERFLOW); /* underflows don't matter */ 1020 feupdateenv(&env); /* update environment */ 1021 return w; 1022} 1023#endif 1024 1025 1026/**************************************************************************** 1027 double complex csinh(double complex z) returns the complex hyperbolic sine of its 1028 argument. The algorithm is based upon the identity: 1029 1030 sinh(x + i*y) = cos(y)*sinh(x) + i*sin(y)*cosh(x). 1031 1032 Signaling of spurious overflows, underflows, and invalids is avoided where 1033 possible. 1034 1035 Calls: sin, cos, coshmul, sinhmul, feholdexcept, feclearexcept, and 1036 feupdateenv. 1037****************************************************************************/ 1038 1039double complex csinh ( double complex z ) 1040{ 1041 fenv_t env; 1042 double sinval, cosval; 1043 double complex w; 1044 1045 (void)feholdexcept(&env); /* save environment, clear flags */ 1046 sinval = sin(Imag(z)); /* sine of imaginary part of argument */ 1047 cosval = cos(Imag(z)); /* cosine of imaginary part of argument */ 1048 Real(w) = sinhmul(Real(z),cosval); /* real result = cosval*sinh(Real(z)) */ 1049 Imag(w) = coshmul(Real(z),sinval); /* imag result = sinval*cosh(Real(z)) */ 1050 feclearexcept(FE_UNDERFLOW); /* underflows don't matter */ 1051 feupdateenv(&env); /* update environment */ 1052 return w; 1053} 1054 1055float complex csinhf ( float complex z ) 1056{ 1057 fenv_t env; 1058 float sinval, cosval; 1059 float complex w; 1060 1061 (void)feholdexcept(&env); /* save environment, clear flags */ 1062 sinval = sinf(Imag(z)); /* sine of imaginary part of argument */ 1063 cosval = cosf(Imag(z)); /* cosine of imaginary part of argument */ 1064 Real(w) = sinhmulf(Real(z),cosval); /* real result = cosval*sinh(Real(z)) */ 1065 Imag(w) = coshmulf(Real(z),sinval); /* imag result = sinval*cosh(Real(z)) */ 1066 feclearexcept(FE_UNDERFLOW); /* underflows don't matter */ 1067 feupdateenv(&env); /* update environment */ 1068 return w; 1069} 1070 1071#if (__WANT_LONG_DOUBLE_FORMAT__ - 0L == 128L) 1072 1073long double complex csinhl ( long double complex z ) 1074{ 1075 fenv_t env; 1076 long double sinval, cosval; 1077 long double complex w; 1078 1079 (void)feholdexcept(&env); /* save environment, clear flags */ 1080 sinval = sinl(Imag(z)); /* sine of imaginary part of argument */ 1081 cosval = cosl(Imag(z)); /* cosine of imaginary part of argument */ 1082 Real(w) = sinhmull(Real(z),cosval); /* real result = cosval*sinh(Real(z)) */ 1083 Imag(w) = coshmull(Real(z),sinval); /* imag result = sinval*cosh(Real(z)) */ 1084 feclearexcept(FE_UNDERFLOW); /* underflows don't matter */ 1085 feupdateenv(&env); /* update environment */ 1086 return w; 1087} 1088#endif 1089 1090 1091/**************************************************************************** 1092 double complex ccosh(double complex z) returns the complex hyperbolic cosine of its 1093 argument. The algorithm is based upon the identity: 1094 1095 cosh(x + i*y) = cos(y)*cosh(x) + i*sin(y)*sinh(x). 1096 1097 Signaling of spurious overflows, underflows, and invalids is avoided where 1098 possible. 1099 1100 Calls: sin, cos, coshmul, sinhmul, feholdexcept, feclearexcept, and 1101 feupdateenv. 1102****************************************************************************/ 1103 1104double complex ccosh ( double complex z ) 1105{ 1106 fenv_t env; 1107 double sinval, cosval; 1108 double complex w; 1109 1110 (void)feholdexcept(&env); /* save environment, clear flags */ 1111 sinval = sin(Imag(z)); /* sine of imaginary part of argument */ 1112 cosval = cos(Imag(z)); /* cosine of imaginary part of argument */ 1113 Real(w) = coshmul(Real(z),cosval); /* real result = cosval*cosh(Real(z)) */ 1114 Imag(w) = sinhmul(Real(z),sinval); /* imag result = sinval*sinh(Real(z)) */ 1115 feclearexcept(FE_UNDERFLOW); /* underflows don't matter */ 1116 feupdateenv(&env); /* update environment */ 1117 return w; 1118} 1119 1120float complex ccoshf ( float complex z ) 1121{ 1122 fenv_t env; 1123 float sinval, cosval; 1124 float complex w; 1125 1126 (void)feholdexcept(&env); /* save environment, clear flags */ 1127 sinval = sinf(Imag(z)); /* sine of imaginary part of argument */ 1128 cosval = cosf(Imag(z)); /* cosine of imaginary part of argument */ 1129 Real(w) = coshmulf(Real(z),cosval); /* real result = cosval*cosh(Real(z)) */ 1130 Imag(w) = sinhmulf(Real(z),sinval); /* imag result = sinval*sinh(Real(z)) */ 1131 feclearexcept(FE_UNDERFLOW); /* underflows don't matter */ 1132 feupdateenv(&env); /* update environment */ 1133 return w; 1134} 1135 1136#if (__WANT_LONG_DOUBLE_FORMAT__ - 0L == 128L) 1137 1138long double complex ccoshl ( long double complex z ) 1139{ 1140 fenv_t env; 1141 long double sinval, cosval; 1142 long double complex w; 1143 1144 (void)feholdexcept(&env); /* save environment, clear flags */ 1145 sinval = sinl(Imag(z)); /* sine of imaginary part of argument */ 1146 cosval = cosl(Imag(z)); /* cosine of imaginary part of argument */ 1147 Real(w) = coshmull(Real(z),cosval); /* real result = cosval*cosh(Real(z)) */ 1148 Imag(w) = sinhmull(Real(z),sinval); /* imag result = sinval*sinh(Real(z)) */ 1149 feclearexcept(FE_UNDERFLOW); /* underflows don't matter */ 1150 feupdateenv(&env); /* update environment */ 1151 return w; 1152} 1153#endif 1154 1155 1156/**************************************************************************** 1157 double complex cexp(double complex z) returns the complex exponential of its 1158 argument. The algorithm is based upon the identity: 1159 1160 exp(x + i*y) = cos(y)*exp(x) + i*sin(y)*exp(x). 1161 1162 Signaling of spurious overflows and invalids is avoided where 1163 possible. 1164 1165 CONSTANTS: FPKEXP709 = exp(709.0) to double precision 1166 1167 Calls: sin, cos, exp, fpclassify, and scalb. 1168 1169 Called by: cepwry, cxpwri, cxpwre, and cxpwry 1170****************************************************************************/ 1171 1172double complex cexp ( double complex z ) 1173{ 1174 double sinval, cosval, expval, exparg; 1175 double complex w; 1176 1177 sinval = sin(Imag(z)); /* sine of imaginary part of argument */ 1178 cosval = cos(Imag(z)); /* cosine of imaginary part of argument */ 1179 1180 if (Real(z) <= 709.0) { /* exp(Real(z)) is finite */ 1181 expval = exp(Real(z)); /* evaluate exponential */ 1182 Real(w) = cosval*expval; /* real result = cos(Imag(z))*exp(Real(z)) */ 1183 Imag(w) = sinval*expval; /* imag result = sin(Imag(z))*exp(Real(z)) */ 1184 } 1185 1186 else if (fpclassify(Real(z)) < FP_ZERO) { /* Real(z) = +INF or a NaN */ 1187 Real(w) = cosval*Real(z); /* deserved invalid may occur */ 1188 Imag(w) = sinval*Real(z); /* deserved invalid may occur */ 1189 } 1190 1191 else if (Real(z) > 1460.0) { /* probable overflow case */ 1192 Real(w) = scalbn(cosval,2100); 1193 Imag(w) = scalbn(sinval,2100); 1194 } 1195 1196 else { /* exp(Real(z)) overflows but product with sin or cos may not */ 1197 Real(w) = cosval*FPKEXP709.d; /* initialize real result */ 1198 Imag(w) = sinval*FPKEXP709.d; /* initialize imag result */ 1199 exparg = Real(z) - 709.0; /* initialize reduced exponent argument */ 1200 while (exparg > 709.0) { /* exponential reduction loop */ 1201 Real(w) *= FPKEXP709.d; 1202 Imag(w) *= FPKEXP709.d; 1203 exparg -= 709.0; 1204 } 1205 expval = exp(exparg); /* final exponential value */ 1206 Real(w) *= expval; /* final multiplication steps */ 1207 Imag(w) *= expval; 1208 } 1209 1210 return w; /* done */ 1211} 1212 1213float complex cexpf ( float complex z ) 1214{ 1215 float sinval, cosval, expval; 1216 float complex w; 1217 1218 sinval = sinf(Imag(z)); /* sine of imaginary part of argument */ 1219 cosval = cosf(Imag(z)); /* cosine of imaginary part of argument */ 1220 1221 if (Real(z) <= 88.0f) { /* exp(Real(z)) is finite */ 1222 expval = expf(Real(z)); /* evaluate exponential */ 1223 Real(w) = cosval*expval; /* real result = cos(Imag(z))*exp(Real(z)) */ 1224 Imag(w) = sinval*expval; /* imag result = sin(Imag(z))*exp(Real(z)) */ 1225 } 1226 1227 else // Handle edge cases in double 1228 w = (float complex)cexp((double complex)z); 1229 1230 return w; /* done */ 1231} 1232 1233#if (__WANT_LONG_DOUBLE_FORMAT__ - 0L == 128L) 1234 1235// long double has same range as double 1236long double complex cexpl ( long double complex z ) 1237{ 1238 long double sinval, cosval, expval, exparg; 1239 long double complex w; 1240 1241 sinval = sinl(Imag(z)); /* sine of imaginary part of argument */ 1242 cosval = cosl(Imag(z)); /* cosine of imaginary part of argument */ 1243 1244 if (Real(z) <= 709.0L) { /* exp(Real(z)) is finite */ 1245 expval = expl(Real(z)); /* evaluate exponential */ 1246 Real(w) = cosval*expval; /* real result = cos(Imag(z))*exp(Real(z)) */ 1247 Imag(w) = sinval*expval; /* imag result = sin(Imag(z))*exp(Real(z)) */ 1248 } 1249 1250 else if (fpclassify(Real(z)) < FP_ZERO) { /* Real(z) = +INF or a NaN */ 1251 Real(w) = cosval*Real(z); /* deserved invalid may occur */ 1252 Imag(w) = sinval*Real(z); /* deserved invalid may occur */ 1253 } 1254 1255 else if (Real(z) > 1460.0L) { /* probable overflow case */ 1256 Real(w) = scalbnl(cosval,2100); 1257 Imag(w) = scalbnl(sinval,2100); 1258 } 1259 1260 else { /* exp(Real(z)) overflows but product with sin or cos may not */ 1261 long double t = FPKEXP709L; 1262 1263 Real(w) = cosval*t; /* initialize real result */ 1264 Imag(w) = sinval*t; /* initialize imag result */ 1265 exparg = Real(z) - 709.0L; /* initialize reduced exponent argument */ 1266 while (exparg > 709.0) { /* exponential reduction loop */ 1267 Real(w) *= t; 1268 Imag(w) *= t; 1269 exparg -= 709.0L; 1270 } 1271 expval = expl(exparg); /* final exponential value */ 1272 Real(w) *= expval; /* final multiplication steps */ 1273 Imag(w) *= expval; 1274 } 1275 1276 return w; /* done */ 1277} 1278#endif 1279 1280/**************************************************************************** 1281 double complex cpow(double complex x, double complex y) returns the complex result of x^y. 1282 The algorithm is based upon the identity: 1283 1284 x^y = cexp(y*clog(x)). 1285 1286 Calls: clog, cexp. 1287****************************************************************************/ 1288 1289double complex cpow ( double complex x, double complex y ) /* (complex x)^(complex y) */ 1290{ 1291 double complex logval,z; 1292 1293 logval = clog(x); /* complex logarithm of x */ 1294 Real(z) = Real(y)*Real(logval) - Imag(y)*Imag(logval); /* multiply by y */ 1295 Imag(z) = Real(y)*Imag(logval) + Imag(y)*Real(logval); 1296 return (cexp(z)); /* return complex exponential */ 1297} 1298 1299float complex cpowf ( float complex x, float complex y ) /* (complex x)^(complex y) */ 1300{ 1301 float complex logval,z; 1302 1303 logval = clogf(x); /* complex logarithm of x */ 1304 Real(z) = Real(y)*Real(logval) - Imag(y)*Imag(logval); /* multiply by y */ 1305 Imag(z) = Real(y)*Imag(logval) + Imag(y)*Real(logval); 1306 return (cexpf(z)); /* return complex exponential */ 1307} 1308 1309#if (__WANT_LONG_DOUBLE_FORMAT__ - 0L == 128L) 1310 1311long double complex cpowl ( long double complex x, long double complex y ) /* (complex x)^(complex y) */ 1312{ 1313 long double complex logval,z; 1314 1315 logval = clogl(x); /* complex logarithm of x */ 1316 Real(z) = Real(y)*Real(logval) - Imag(y)*Imag(logval); /* multiply by y */ 1317 Imag(z) = Real(y)*Imag(logval) + Imag(y)*Real(logval); 1318 return (cexpl(z)); /* return complex exponential */ 1319} 1320#endif 1321 1322/**************************************************************************** 1323 double complex ctanh(double complex x) returns the complex hyperbolic tangent of its 1324 argument. The algorithm is from Kahan's paper and is based on the 1325 identity: 1326 1327 tanh(x+i*y) = (sinh(2*x) + i*sin(2*y))/(cosh(2*x) + cos(2*y)) 1328 = (cosh(x)*sinh(x)*cscsq + i*tan(y))/(1+cscsq*sinh(x)*sinh(x)), 1329 1330 where cscsq = 1/(cos(y)*cos(y). For large values of ze.re, spurious 1331 overflow and invalid signaling is avoided. 1332 1333 CONSTANTS: FPKASINHOM4 = asinh(nextafterd(+infinity,0.0))/4.0 to double 1334 precision 1335 FPKINF = +infinity 1336 1337 Calls: tan, sinh, sqrt, fabs, feholdexcept, feraiseexcept, feclearexcept, 1338 and feupdateenv. 1339****************************************************************************/ 1340 1341double complex ctanh( double complex z ) 1342{ 1343 fenv_t env; 1344 double tanval, beta, sinhval, coshval, denom; 1345 double complex w; 1346 1347 (void)feholdexcept(&env); /* save environment and clear flags */ 1348 1349 if (fabs(Real(z)) > FPKASINHOM4.d) { /* avoid overflow for large |Real(z)| */ 1350 Real(w) = copysign(1.0,Real(z)); /* real result has unit magnitude */ 1351 Imag(w) = copysign(0.0,Imag(z)); /* imag result is signed zero */ 1352 if (fabs(Real(z)) != INFINITY) /* set inexact for finite Real(z) */ 1353 feraiseexcept(FE_INEXACT); 1354 feupdateenv(&env); /* update environment */ 1355 } /* end large |Real(z)| case */ 1356 1357 1358 else { /* usual case */ 1359 tanval = tan(Imag(z)); /* evaluate tangent */ 1360 feclearexcept(FE_DIVBYZERO); /* in case tangent is infinite */ 1361 feupdateenv(&env); /* update environment */ 1362 beta = 1.0 + tanval*tanval; /* 1/(cos(Imag(z)))^2 */ 1363 sinhval = sinh(Real(z)); /* evaluate sinh */ 1364 coshval = sqrt(1.0+sinhval*sinhval); /* evaluate cosh */ 1365 1366 if (fabs(tanval) == INFINITY) { /* infinite tangent */ 1367 Real(w) = coshval/sinhval; 1368 Imag(w) = 1.0/tanval; 1369 } 1370 1371 else { /* finite tangent */ 1372 denom = 1.0 + beta*sinhval*sinhval; 1373 Real(w) = beta*coshval*sinhval/denom; 1374 Imag(w) = tanval/denom; 1375 } 1376 } /* end usual case */ 1377 1378 return w; /* done */ 1379} 1380 1381float complex ctanhf( float complex z ) 1382{ 1383 fenv_t env; 1384 float tanval, beta, sinhval, coshval, denom; 1385 float complex w; 1386 1387 (void)feholdexcept(&env); /* save environment and clear flags */ 1388 1389 if (fabsf(Real(z)) > FPKASINHOM4f.fval) { /* avoid overflow for large |Real(z)| */ 1390 Real(w) = copysignf(1.0f,Real(z)); /* real result has unit magnitude */ 1391 Imag(w) = copysignf(0.0f,Imag(z)); /* imag result is signed zero */ 1392 if (fabsf(Real(z)) != INFINITY) /* set inexact for finite Real(z) */ 1393 feraiseexcept(FE_INEXACT); 1394 feupdateenv(&env); /* update environment */ 1395 } /* end large |Real(z)| case */ 1396 1397 1398 else { /* usual case */ 1399 tanval = tanf(Imag(z)); /* evaluate tangent */ 1400 feclearexcept(FE_DIVBYZERO); /* in case tangent is infinite */ 1401 feupdateenv(&env); /* update environment */ 1402 beta = 1.0f + tanval*tanval; /* 1/(cos(Imag(z)))^2 */ 1403 sinhval = sinhf(Real(z)); /* evaluate sinh */ 1404 coshval = sqrtf(1.0f+sinhval*sinhval); /* evaluate cosh */ 1405 1406 if (fabs(tanval) == INFINITY) { /* infinite tangent */ 1407 Real(w) = coshval/sinhval; 1408 Imag(w) = 1.0f/tanval; 1409 } 1410 1411 else { /* finite tangent */ 1412 denom = 1.0f + beta*sinhval*sinhval; 1413 Real(w) = beta*coshval*sinhval/denom; 1414 Imag(w) = tanval/denom; 1415 } 1416 } /* end usual case */ 1417 1418 return w; /* done */ 1419} 1420 1421#if (__WANT_LONG_DOUBLE_FORMAT__ - 0L == 128L) 1422 1423long double complex ctanhl( long double complex z ) 1424{ 1425 fenv_t env; 1426 long double tanval, beta, sinhval, coshval, denom; 1427 long double complex w; 1428 1429 (void)feholdexcept(&env); /* save environment and clear flags */ 1430 1431 if (fabsl(Real(z)) > FPKASINHOM4.d) { /* avoid overflow for large |Real(z)| */ 1432 Real(w) = copysignl(1.0L,Real(z)); /* real result has unit magnitude */ 1433 Imag(w) = copysignl(0.0L,Imag(z)); /* imag result is signed zero */ 1434 if (fabsl(Real(z)) != INFINITY) /* set inexact for finite Real(z) */ 1435 feraiseexcept(FE_INEXACT); 1436 feupdateenv(&env); /* update environment */ 1437 } /* end large |Real(z)| case */ 1438 1439 1440 else { /* usual case */ 1441 tanval = tanl(Imag(z)); /* evaluate tangent */ 1442 feclearexcept(FE_DIVBYZERO); /* in case tangent is infinite */ 1443 feupdateenv(&env); /* update environment */ 1444 beta = 1.0L + tanval*tanval; /* 1/(cos(Imag(z)))^2 */ 1445 sinhval = sinhl(Real(z)); /* evaluate sinh */ 1446 coshval = sqrtl(1.0L+sinhval*sinhval); /* evaluate cosh */ 1447 1448 if (fabsl(tanval) == INFINITY) { /* infinite tangent */ 1449 Real(w) = coshval/sinhval; 1450 Imag(w) = 1.0L/tanval; 1451 } 1452 1453 else { /* finite tangent */ 1454 denom = 1.0L + beta*sinhval*sinhval; 1455 Real(w) = beta*coshval*sinhval/denom; 1456 Imag(w) = tanval/denom; 1457 } 1458 } /* end usual case */ 1459 1460 return w; /* done */ 1461} 1462#endif 1463 1464/**************************************************************************** 1465 double complex ctan(double complex x) returns the complex hyperbolic tangent of its 1466 argument. The algorithm is from Kahan's paper and is based on the 1467 identity: 1468 1469 tan(x + i*y) = (sin(2*x) + i*sinh(2*y))/(cos(2*x) + cosh(2*y)) 1470 = (tan(x)+i*cosh(y)*sinh(y)*cscsq)/(1+cscsq*sinh(y)*sinh(y)), 1471 1472 where cscsq = 1/(cos(x)*cos(x). For large values of ze.im, spurious 1473 overflow and invalid signaling is avoided. 1474 1475 CONSTANTS: FPKASINHOM4 = asinh(nextafterd(+infinity,0.0))/4.0 to double 1476 precision 1477 FPKINF = +infinity 1478 1479 Calls: tan, sinh, sqrt, fabs, feholdexcept, feraiseexcept, feclearexcept, 1480 and feupdateenv. 1481****************************************************************************/ 1482 1483double complex ctan( double complex z ) 1484{ 1485 fenv_t env; 1486 double tanval, beta, sinhval, coshval, denom; 1487 double complex w; 1488 1489 (void)feholdexcept(&env); /* save environment and clear flags */ 1490 1491 if (fabs(Imag(z)) > FPKASINHOM4.d) { /* avoid overflow for large |Imag(z)| */ 1492 Real(w) = copysign(0.0,Real(z)); /* real result has zero magnitude */ 1493 Imag(w) = copysign(1.0,Imag(z)); /* imag result has unit magnitude */ 1494 if (fabs(Imag(z)) != INFINITY) /* set inexact for finite Real(z) */ 1495 feraiseexcept(FE_INEXACT); 1496 feupdateenv(&env); /* update environment */ 1497 } /* end large |Real(z)| case */ 1498 1499 1500 else { /* usual case */ 1501 tanval = tan(Real(z)); /* evaluate tangent */ 1502 feclearexcept(FE_DIVBYZERO); /* in case tangent is infinite */ 1503 feupdateenv(&env); /* update environment */ 1504 beta = 1.0 + tanval*tanval; /* 1/(cos(Real(z)))^2 */ 1505 sinhval = sinh(Imag(z)); /* evaluate sinh */ 1506 coshval = sqrt(1.0+sinhval*sinhval); /* evaluate cosh */ 1507 1508 if (fabs(tanval) == INFINITY) { /* infinite tangent */ 1509 Real(w) = 1.0/tanval; 1510 Imag(w) = coshval/sinhval; 1511 } 1512 1513 else { /* finite tangent */ 1514 denom = 1.0 + beta*sinhval*sinhval; 1515 Real(w) = tanval/denom; 1516 Imag(w) = beta*coshval*sinhval/denom; 1517 } 1518 } /* end usual case */ 1519 1520 return w; /* done */ 1521} 1522 1523float complex ctanf( float complex z ) 1524{ 1525 fenv_t env; 1526 float tanval, beta, sinhval, coshval, denom; 1527 float complex w; 1528 1529 (void)feholdexcept(&env); /* save environment and clear flags */ 1530 1531 if (fabsf(Imag(z)) > FPKASINHOM4f.fval) { /* avoid overflow for large |Imag(z)| */ 1532 Real(w) = copysignf(0.0f,Real(z)); /* real result has zero magnitude */ 1533 Imag(w) = copysignf(1.0f,Imag(z)); /* imag result has unit magnitude */ 1534 if (fabsf(Imag(z)) != INFINITY) /* set inexact for finite Real(z) */ 1535 feraiseexcept(FE_INEXACT); 1536 feupdateenv(&env); /* update environment */ 1537 } /* end large |Real(z)| case */ 1538 1539 1540 else { /* usual case */ 1541 tanval = tanf(Real(z)); /* evaluate tangent */ 1542 feclearexcept(FE_DIVBYZERO); /* in case tangent is infinite */ 1543 feupdateenv(&env); /* update environment */ 1544 beta = 1.0f + tanval*tanval; /* 1/(cos(Real(z)))^2 */ 1545 sinhval = sinhf(Imag(z)); /* evaluate sinh */ 1546 coshval = sqrtf(1.0f+sinhval*sinhval); /* evaluate cosh */ 1547 1548 if (fabsf(tanval) == INFINITY) { /* infinite tangent */ 1549 Real(w) = 1.0f/tanval; 1550 Imag(w) = coshval/sinhval; 1551 } 1552 1553 else { /* finite tangent */ 1554 denom = 1.0f + beta*sinhval*sinhval; 1555 Real(w) = tanval/denom; 1556 Imag(w) = beta*coshval*sinhval/denom; 1557 } 1558 } /* end usual case */ 1559 1560 return w; /* done */ 1561} 1562 1563#if (__WANT_LONG_DOUBLE_FORMAT__ - 0L == 128L) 1564 1565long double complex ctanl( long double complex z ) 1566{ 1567 fenv_t env; 1568 long double tanval, beta, sinhval, coshval, denom; 1569 long double complex w; 1570 1571 (void)feholdexcept(&env); /* save environment and clear flags */ 1572 1573 if (fabsl(Imag(z)) > FPKASINHOM4.d) { /* avoid overflow for large |Imag(z)| */ 1574 Real(w) = copysignl(0.0L,Real(z)); /* real result has zero magnitude */ 1575 Imag(w) = copysignl(1.0L,Imag(z)); /* imag result has unit magnitude */ 1576 if (fabsl(Imag(z)) != INFINITY) /* set inexact for finite Real(z) */ 1577 feraiseexcept(FE_INEXACT); 1578 feupdateenv(&env); /* update environment */ 1579 } /* end large |Real(z)| case */ 1580 1581 1582 else { /* usual case */ 1583 tanval = tanl(Real(z)); /* evaluate tangent */ 1584 feclearexcept(FE_DIVBYZERO); /* in case tangent is infinite */ 1585 feupdateenv(&env); /* update environment */ 1586 beta = 1.0L + tanval*tanval; /* 1/(cos(Real(z)))^2 */ 1587 sinhval = sinhl(Imag(z)); /* evaluate sinh */ 1588 coshval = sqrtl(1.0L+sinhval*sinhval); /* evaluate cosh */ 1589 1590 if (fabsl(tanval) == INFINITY) { /* infinite tangent */ 1591 Real(w) = 1.0L/tanval; 1592 Imag(w) = coshval/sinhval; 1593 } 1594 1595 else { /* finite tangent */ 1596 denom = 1.0L + beta*sinhval*sinhval; 1597 Real(w) = tanval/denom; 1598 Imag(w) = beta*coshval*sinhval/denom; 1599 } 1600 } /* end usual case */ 1601 1602 return w; /* done */ 1603} 1604#endif 1605 1606/**************************************************************************** 1607 double complex casin(double complex z) returns the complex inverse sine of its 1608 argument. The algorithm is from Kahan's paper and is based on the 1609 formulae: 1610 1611 real(casin(z)) = atan (real(z)/real(csqrt(1.0-z)*csqrt(1.0+z))) 1612 imag(casin(z)) = arcsinh(imag(csqrt(1.0-cconj(z))*csqrt(1.0+z))) 1613 1614 Calls: arcsinh, csqrt, atan, feholdexcept, feclearexcept, feupdateenv. 1615****************************************************************************/ 1616 1617double complex casin ( double complex z ) 1618{ 1619 double complex zp1, zm, zm1, w; 1620 fenv_t env; 1621 1622 Real(zp1) = 1.0 + Real(z); /* evaluate zp1 = csqrt(1.0+z) */ 1623 Imag(zp1) = Imag(z); 1624 zp1 = csqrt(zp1); 1625 1626 Real(zm) = 1.0 - Real(z); /* evaluate zm1 = csqrt(1.0-z) */ 1627 Imag(zm) = -Imag(z); 1628 zm1 = csqrt(zm); 1629 1630 (void)feholdexcept(&env); /* save environ., clr flags/enables */ 1631 Real(w) = atan(Real(z)/(Real(zp1)*Real(zm1) -Imag(zp1)*Imag(zm1))); /* real result */ 1632 feclearexcept(FE_DIVBYZERO); /* clear spurious DIVBYZERO exception */ 1633 feupdateenv(&env); /* restore environment with new flags */ 1634 1635 Imag(zm) = Imag(z); /* evaluate zm1 = csqrt(1.0-cconj(z)) */ 1636 zm1 = csqrt(zm); 1637 1638 Imag(w) = asinh(Real(zp1)*Imag(zm1) + Imag(zp1)*Real(zm1)); /* imag result */ 1639 1640 return w; 1641} 1642 1643float complex casinf ( float complex z ) 1644{ 1645 float complex zp1, zm, zm1, w; 1646 fenv_t env; 1647 1648 Real(zp1) = 1.0f + Real(z); /* evaluate zp1 = csqrt(1.0+z) */ 1649 Imag(zp1) = Imag(z); 1650 zp1 = csqrtf(zp1); 1651 1652 Real(zm) = 1.0f - Real(z); /* evaluate zm1 = csqrt(1.0-z) */ 1653 Imag(zm) = -Imag(z); 1654 zm1 = csqrtf(zm); 1655 1656 (void)feholdexcept(&env); /* save environ., clr flags/enables */ 1657 Real(w) = atanf(Real(z)/(Real(zp1)*Real(zm1) -Imag(zp1)*Imag(zm1))); /* real result */ 1658 feclearexcept(FE_DIVBYZERO); /* clear spurious DIVBYZERO exception */ 1659 feupdateenv(&env); /* restore environment with new flags */ 1660 1661 Imag(zm) = Imag(z); /* evaluate zm1 = csqrt(1.0-cconj(z)) */ 1662 zm1 = csqrtf(zm); 1663 1664 Imag(w) = asinhf(Real(zp1)*Imag(zm1) + Imag(zp1)*Real(zm1)); /* imag result */ 1665 1666 return w; 1667} 1668 1669#if (__WANT_LONG_DOUBLE_FORMAT__ - 0L == 128L) 1670 1671long double complex casinl ( long double complex z ) 1672{ 1673 long double complex zp1, zm, zm1, w; 1674 fenv_t env; 1675 1676 Real(zp1) = 1.0L + Real(z); /* evaluate zp1 = csqrt(1.0+z) */ 1677 Imag(zp1) = Imag(z); 1678 zp1 = csqrtl(zp1); 1679 1680 Real(zm) = 1.0L - Real(z); /* evaluate zm1 = csqrt(1.0-z) */ 1681 Imag(zm) = -Imag(z); 1682 zm1 = csqrtl(zm); 1683 1684 (void)feholdexcept(&env); /* save environ., clr flags/enables */ 1685 Real(w) = atanl(Real(z)/(Real(zp1)*Real(zm1) -Imag(zp1)*Imag(zm1))); /* real result */ 1686 feclearexcept(FE_DIVBYZERO); /* clear spurious DIVBYZERO exception */ 1687 feupdateenv(&env); /* restore environment with new flags */ 1688 1689 Imag(zm) = Imag(z); /* evaluate zm1 = csqrt(1.0-cconj(z)) */ 1690 zm1 = csqrtl(zm); 1691 1692 Imag(w) = asinhl(Real(zp1)*Imag(zm1) + Imag(zp1)*Real(zm1)); /* imag result */ 1693 1694 return w; 1695} 1696#endif 1697 1698/**************************************************************************** 1699 double complex casinh(double complex z) returns the complex inverse hyperbolic sine of 1700 its argument. The algorithm is from Kahan's paper and is based on the 1701 formula: 1702 1703 casinh(z) = -i*casin(i*z). 1704 1705 Calls: arcsinh, csqrt, atan, feholdexcept, feclearexcept, feupdateenv. 1706****************************************************************************/ 1707 1708double complex casinh ( double complex z ) 1709{ 1710 double complex zp1, zm, zm1, w; 1711 fenv_t env; 1712 1713 Real(zp1) = 1.0 - Imag(z); /* evaluate zp1 = csqrt(1.0+i*z) */ 1714 Imag(zp1) = Real(z); 1715 zp1 = csqrt(zp1); 1716 1717 Real(zm) = 1.0 + Imag(z); /* evaluate zm1 = csqrt(1.0-cconj(i*z)) */ 1718 Imag(zm) = Real(z); 1719 zm1 = csqrt(zm); 1720 1721 Real(w) = asinh(Real(zp1)*Imag(zm1) + Imag(zp1)*Real(zm1)); /* imag result */ 1722 1723 Imag(zm) = -Real(z); /* evaluate zm1 = csqrt(1.0-cconj(z)) */ 1724 zm1 = csqrt(zm); 1725 1726 (void)feholdexcept(&env); /* save environ., clr flags/enables */ 1727 Imag(w) = atan(Imag(z)/(Real(zp1)*Real(zm1) -Imag(zp1)*Imag(zm1))); /* real result */ 1728 feclearexcept(FE_DIVBYZERO); /* clear spurious DIVBYZERO exception */ 1729 feupdateenv(&env); /* restore environment with new flags */ 1730 1731 return w; 1732} 1733 1734float complex casinhf ( float complex z ) 1735{ 1736 float complex zp1, zm, zm1, w; 1737 fenv_t env; 1738 1739 Real(zp1) = 1.0f - Imag(z); /* evaluate zp1 = csqrt(1.0+i*z) */ 1740 Imag(zp1) = Real(z); 1741 zp1 = csqrt(zp1); 1742 1743 Real(zm) = 1.0f + Imag(z); /* evaluate zm1 = csqrt(1.0-cconj(i*z)) */ 1744 Imag(zm) = Real(z); 1745 zm1 = csqrtf(zm); 1746 1747 Real(w) = asinhf(Real(zp1)*Imag(zm1) + Imag(zp1)*Real(zm1)); /* imag result */ 1748 1749 Imag(zm) = -Real(z); /* evaluate zm1 = csqrt(1.0-cconj(z)) */ 1750 zm1 = csqrtf(zm); 1751 1752 (void)feholdexcept(&env); /* save environ., clr flags/enables */ 1753 Imag(w) = atanf(Imag(z)/(Real(zp1)*Real(zm1) -Imag(zp1)*Imag(zm1))); /* real result */ 1754 feclearexcept(FE_DIVBYZERO); /* clear spurious DIVBYZERO exception */ 1755 feupdateenv(&env); /* restore environment with new flags */ 1756 1757 return w; 1758} 1759 1760#if (__WANT_LONG_DOUBLE_FORMAT__ - 0L == 128L) 1761 1762long double complex casinhl ( long double complex z ) 1763{ 1764 long double complex zp1, zm, zm1, w; 1765 fenv_t env; 1766 1767 Real(zp1) = 1.0L - Imag(z); /* evaluate zp1 = csqrt(1.0+i*z) */ 1768 Imag(zp1) = Real(z); 1769 zp1 = csqrtl(zp1); 1770 1771 Real(zm) = 1.0L + Imag(z); /* evaluate zm1 = csqrt(1.0-cconj(i*z)) */ 1772 Imag(zm) = Real(z); 1773 zm1 = csqrtl(zm); 1774 1775 Real(w) = asinhl(Real(zp1)*Imag(zm1) + Imag(zp1)*Real(zm1)); /* imag result */ 1776 1777 Imag(zm) = -Real(z); /* evaluate zm1 = csqrt(1.0-cconj(z)) */ 1778 zm1 = csqrtl(zm); 1779 1780 (void)feholdexcept(&env); /* save environ., clr flags/enables */ 1781 Imag(w) = atanl(Imag(z)/(Real(zp1)*Real(zm1) -Imag(zp1)*Imag(zm1))); /* real result */ 1782 feclearexcept(FE_DIVBYZERO); /* clear spurious DIVBYZERO exception */ 1783 feupdateenv(&env); /* restore environment with new flags */ 1784 1785 return w; 1786} 1787#endif 1788 1789/**************************************************************************** 1790 double complex cacos(double complex z) returns the complex inverse cosine of its 1791 argument. The algorithm is from Kahan's paper and is based on the 1792 formulae: 1793 1794 real(cacos(z)) = 2.0*atan(real(csqrt(1.0-z)/real(csqrt(1.0+z)))) 1795 imag(cacos(z)) = arcsinh(imag(csqrt(1.0-z)*csqrt(cconj(1.0+z)))) 1796 1797 Calls: arcsinh, csqrt, atan, feholdexcept, feclearexcept, feupdateenv. 1798****************************************************************************/ 1799 1800double complex cacos ( double complex z ) 1801{ 1802 double complex zp, zp1, zm1, w; 1803 fenv_t env; 1804 1805 Real(zp) = 1.0 + Real(z); /* zp1 = csqrt(1.0 + z) */ 1806 Imag(zp) = Imag(z); 1807 zp1 = csqrt(zp); 1808 1809 Real(zm1) = 1.0 - Real(z); /* zm1 = csqrt(1.0 - z) */ 1810 Imag(zm1) = -Imag(z); 1811 zm1 = csqrt(zm1); 1812 1813 (void)feholdexcept(&env); /* save environment, clr flags/enables */ 1814 Real(w) = 2.0*atan(Real(zm1)/Real(zp1)); /* real result */ 1815 feclearexcept(FE_DIVBYZERO); /* clr possible spurious div-by-zero flag */ 1816 feupdateenv(&env); /* update environment with new flags */ 1817 1818 Imag(zp) = -Imag(z); /* zp1 = csqrt(1.0 + cconj(z)) */ 1819 zp1 = csqrt(zp); 1820 1821 Imag(w) = asinh(Real(zp1)*Imag(zm1) + Imag(zp1)*Real(zm1)); /* imag result */ 1822 1823 return w; 1824} 1825 1826float complex cacosf ( float complex z ) 1827{ 1828 float complex zp, zp1, zm1, w; 1829 fenv_t env; 1830 1831 Real(zp) = 1.0f + Real(z); /* zp1 = csqrt(1.0 + z) */ 1832 Imag(zp) = Imag(z); 1833 zp1 = csqrtf(zp); 1834 1835 Real(zm1) = 1.0f - Real(z); /* zm1 = csqrt(1.0 - z) */ 1836 Imag(zm1) = -Imag(z); 1837 zm1 = csqrtf(zm1); 1838 1839 (void)feholdexcept(&env); /* save environment, clr flags/enables */ 1840 Real(w) = 2.0f*atanf(Real(zm1)/Real(zp1)); /* real result */ 1841 feclearexcept(FE_DIVBYZERO); /* clr possible spurious div-by-zero flag */ 1842 feupdateenv(&env); /* update environment with new flags */ 1843 1844 Imag(zp) = -Imag(z); /* zp1 = csqrt(1.0 + cconj(z)) */ 1845 zp1 = csqrtf(zp); 1846 1847 Imag(w) = asinhf(Real(zp1)*Imag(zm1) + Imag(zp1)*Real(zm1)); /* imag result */ 1848 1849 return w; 1850} 1851 1852#if (__WANT_LONG_DOUBLE_FORMAT__ - 0L == 128L) 1853 1854long double complex cacosl ( long double complex z ) 1855{ 1856 long double complex zp, zp1, zm1, w; 1857 fenv_t env; 1858 1859 Real(zp) = 1.0L + Real(z); /* zp1 = csqrt(1.0 + z) */ 1860 Imag(zp) = Imag(z); 1861 zp1 = csqrtl(zp); 1862 1863 Real(zm1) = 1.0L - Real(z); /* zm1 = csqrt(1.0 - z) */ 1864 Imag(zm1) = -Imag(z); 1865 zm1 = csqrtl(zm1); 1866 1867 (void)feholdexcept(&env); /* save environment, clr flags/enables */ 1868 Real(w) = 2.0L*atanl(Real(zm1)/Real(zp1)); /* real result */ 1869 feclearexcept(FE_DIVBYZERO); /* clr possible spurious div-by-zero flag */ 1870 feupdateenv(&env); /* update environment with new flags */ 1871 1872 Imag(zp) = -Imag(z); /* zp1 = csqrt(1.0 + cconj(z)) */ 1873 zp1 = csqrtl(zp); 1874 1875 Imag(w) = asinhl(Real(zp1)*Imag(zm1) + Imag(zp1)*Real(zm1)); /* imag result */ 1876 1877 return w; 1878} 1879#endif 1880 1881 1882/**************************************************************************** 1883 double complex cacosh(double complex z) returns the complex inverse hyperbolic`cosine 1884 of its argument. The algorithm is from Kahan's paper and is based on the 1885 formulae: 1886 1887 real(cacosh(z)) = arcsinh(real(csqrt(cconj(z)-1.0)*csqrt(z+1.0))) 1888 imag(cacosh(z)) = 2.0*atan(imag(csqrt(z-1.0)/real(csqrt(z+1.0)))) 1889 1890 Calls: arcsinh, csqrt, atan, feholdexcept, feclearexcept, feupdateenv. 1891****************************************************************************/ 1892 1893double complex cacosh ( double complex z ) 1894{ 1895 double complex zp1, zm, zm1, w; 1896 fenv_t env; 1897 1898 Real(zp1) = Real(z) + 1.0; /* zp1 = csqrt(z + 1.0) */ 1899 Imag(zp1) = Imag(z); 1900 zp1 = csqrt(zp1); 1901 1902 Real(zm) = Real(z) - 1.0; /* zm1 = csqrt(z - 1.0) */ 1903 Imag(zm) = Imag(z); 1904 zm1 = csqrt(zm); 1905 1906 (void)feholdexcept(&env); /* save environment, clr flags/enables */ 1907 Imag(w) = 2.0*atan(Imag(zm1)/Real(zp1)); /* imag result */ 1908 feclearexcept(FE_DIVBYZERO); /* clr possible spurious div-by-zero flag */ 1909 feupdateenv(&env); /* restore environment with new flags */ 1910 1911 Imag(zm) = -Imag(z); /* zm1 = csqrt(cconj(z) - 1.0) */ 1912 zm1 = csqrt(zm); 1913 1914 Real(w) = asinh(Real(zp1)*Real(zm1) - Imag(zp1)*Imag(zm1)); /* real result */ 1915 1916 return w; 1917} 1918 1919float complex cacoshf ( float complex z ) 1920{ 1921 float complex zp1, zm, zm1, w; 1922 fenv_t env; 1923 1924 Real(zp1) = Real(z) + 1.0f; /* zp1 = csqrt(z + 1.0) */ 1925 Imag(zp1) = Imag(z); 1926 zp1 = csqrtf(zp1); 1927 1928 Real(zm) = Real(z) - 1.0f; /* zm1 = csqrt(z - 1.0) */ 1929 Imag(zm) = Imag(z); 1930 zm1 = csqrtf(zm); 1931 1932 (void)feholdexcept(&env); /* save environment, clr flags/enables */ 1933 Imag(w) = 2.0f*atanf(Imag(zm1)/Real(zp1)); /* imag result */ 1934 feclearexcept(FE_DIVBYZERO); /* clr possible spurious div-by-zero flag */ 1935 feupdateenv(&env); /* restore environment with new flags */ 1936 1937 Imag(zm) = -Imag(z); /* zm1 = csqrt(cconj(z) - 1.0) */ 1938 zm1 = csqrtf(zm); 1939 1940 Real(w) = asinhf(Real(zp1)*Real(zm1) - Imag(zp1)*Imag(zm1)); /* real result */ 1941 1942 return w; 1943} 1944 1945#if (__WANT_LONG_DOUBLE_FORMAT__ - 0L == 128L) 1946 1947long double complex cacoshl ( long double complex z ) 1948{ 1949 long double complex zp1, zm, zm1, w; 1950 fenv_t env; 1951 1952 Real(zp1) = Real(z) + 1.0L; /* zp1 = csqrt(z + 1.0) */ 1953 Imag(zp1) = Imag(z); 1954 zp1 = csqrtl(zp1); 1955 1956 Real(zm) = Real(z) - 1.0L; /* zm1 = csqrt(z - 1.0) */ 1957 Imag(zm) = Imag(z); 1958 zm1 = csqrtl(zm); 1959 1960 (void)feholdexcept(&env); /* save environment, clr flags/enables */ 1961 Imag(w) = 2.0L*atanl(Imag(zm1)/Real(zp1)); /* imag result */ 1962 feclearexcept(FE_DIVBYZERO); /* clr possible spurious div-by-zero flag */ 1963 feupdateenv(&env); /* restore environment with new flags */ 1964 1965 Imag(zm) = -Imag(z); /* zm1 = csqrt(cconj(z) - 1.0) */ 1966 zm1 = csqrtl(zm); 1967 1968 Real(w) = asinhl(Real(zp1)*Real(zm1) - Imag(zp1)*Imag(zm1)); /* real result */ 1969 1970 return w; 1971} 1972#endif 1973 1974/**************************************************************************** 1975 double complex catan(double complex z) returns the complex inverse tangent 1976 of its argument. The algorithm is from Kahan's paper and is based on 1977 the formula: 1978 1979 catan(z) = i*(clog(1.0-i*z) - clog(1+i*z))/2.0. 1980 1981 CONSTANTS: FPKTHETA = sqrt(nextafterd(+INF,0.0))/4.0 1982 FPKRHO = 1.0/FPKTHETA 1983 FPKPI2 = pi/2.0 1984 FPKPI = pi 1985 1986 Calls: copysign, fabs, xdivc, sqrt, log, atan, log1p, and carg. 1987****************************************************************************/ 1988 1989double complex catan ( double complex z ) 1990{ 1991 double complex ctemp, w; 1992 double t1, t2, xi, eta, beta; 1993 1994 xi = -Imag(z); 1995 beta = copysign(1.0,xi); /* copes with unsigned zero */ 1996 1997 Imag(z) = -beta*Real(z); /* transform real & imag components */ 1998 Real(z) = beta*xi; 1999 2000 if ((Real(z) > FPKTHETA.d) || (fabs(Imag(z)) > FPKTHETA.d)) { 2001 xi = copysign(M_PI_2,Imag(z)); /* avoid spurious overflow */ 2002 ctemp = xdivc(1.0,z); 2003 eta = Real(ctemp); 2004 } 2005 2006 else if (Real(z) == 1.0) { 2007 t1 = fabs(Imag(z)) + FPKRHO.d; 2008 xi = log(sqrt(sqrt(4.0 + t1*t1))/sqrt(fabs(Imag(z)))); 2009 eta = 0.5*copysign(M_PI-atan(2.0/(fabs(Imag(z))+FPKRHO.d)),Imag(z)); 2010 } 2011 2012 else { /* usual case */ 2013 t2 = fabs(Imag(z)) + FPKRHO.d; 2014 t1 = 1.0 - Real(z); 2015 t2 = t2*t2; 2016 xi = 0.25*log1p(4.0*Real(z)/(t1*t1 + t2)); 2017 Real(ctemp) = (1.0 - Real(z))*(1.0 + Real(z)) - t2; 2018 Imag(ctemp) = Imag(z) + Imag(z); 2019 eta = 0.5*carg(ctemp); 2020 } 2021 2022 Real(w) = -beta*eta; /* fix up signs of result */ 2023 Imag(w) = -beta*xi; 2024 return w; 2025} 2026 2027float complex catanf ( float complex z ) 2028{ 2029 float complex ctemp, w; 2030 float t1, t2, xi, eta, beta; 2031 2032 xi = -Imag(z); 2033 beta = copysignf(1.0f,xi); /* copes with unsigned zero */ 2034 2035 Imag(z) = -beta*Real(z); /* transform real & imag components */ 2036 Real(z) = beta*xi; 2037 2038 if ((Real(z) > FPKTHETAf.fval) || (fabsf(Imag(z)) > FPKTHETAf.fval)) { 2039 xi = copysignf((float) M_PI_2,Imag(z)); /* avoid spurious overflow */ 2040 ctemp = xdivcf(1.0f,z); 2041 eta = Real(ctemp); 2042 } 2043 2044 else if (Real(z) == 1.0f) { 2045 t1 = fabsf(Imag(z)) + FPKRHOf.fval; 2046 xi = logf(sqrtf(sqrtf(4.0f + t1*t1))/sqrtf(fabsf(Imag(z)))); 2047 eta = 0.5f*copysignf((float)( M_PI-atan(2.0/(fabsf(Imag(z))+FPKRHOf.fval))),Imag(z)); 2048 } 2049 2050 else { /* usual case */ 2051 t2 = fabsf(Imag(z)) + FPKRHOf.fval; 2052 t1 = 1.0f - Real(z); 2053 t2 = t2*t2; 2054 xi = 0.25f*log1pf(4.0f*Real(z)/(t1*t1 + t2)); 2055 Real(ctemp) = (1.0f - Real(z))*(1.0f + Real(z)) - t2; 2056 Imag(ctemp) = Imag(z) + Imag(z); 2057 eta = 0.5f*cargf(ctemp); 2058 } 2059 2060 Real(w) = -beta*eta; /* fix up signs of result */ 2061 Imag(w) = -beta*xi; 2062 return w; 2063} 2064 2065#if (__WANT_LONG_DOUBLE_FORMAT__ - 0L == 128L) 2066static const 2067 hexdbldbl FPKRHOl = {{0x20100000, 0x00000001, 0x9cbfffff, 0xffffffff}}; 2068 2069long double complex catanl ( long double complex z ) 2070{ 2071 long double complex ctemp, w; 2072 long double t1, t2, xi, eta, beta; 2073 2074 xi = -Imag(z); 2075 beta = copysignl(1.0L,xi); /* copes with unsigned zero */ 2076 2077 Imag(z) = -beta*Real(z); /* transform real & imag components */ 2078 Real(z) = beta*xi; 2079 2080 if ((Real(z) > FPKTHETA.d) || (fabsl(Imag(z)) > FPKTHETA.d)) { 2081 xi = copysignl(M_PI_2,Imag(z)); /* avoid spurious overflow */ 2082 ctemp = xdivcl(1.0L,z); 2083 eta = Real(ctemp); 2084 } 2085 2086 else if (Real(z) == 1.0L) { 2087 t1 = fabsl(Imag(z)) + FPKRHOl.ld; 2088 xi = logl(sqrtl(sqrtl(4.0L + t1*t1))/sqrtl(fabsl(Imag(z)))); 2089 eta = 0.5L*copysignl(M_PI-atanl(2.0L/(fabsl(Imag(z))+FPKRHOl.ld)),Imag(z)); 2090 } 2091 2092 else { /* usual case */ 2093 t2 = fabsl(Imag(z)) + FPKRHOl.ld; 2094 t1 = 1.0L - Real(z); 2095 t2 = t2*t2; 2096 xi = 0.25L*log1pl(4.0L*Real(z)/(t1*t1 + t2)); 2097 Real(ctemp) = (1.0L - Real(z))*(1.0L + Real(z)) - t2; 2098 Imag(ctemp) = Imag(z) + Imag(z); 2099 eta = 0.5L*cargl(ctemp); 2100 } 2101 2102 Real(w) = -beta*eta; /* fix up signs of result */ 2103 Imag(w) = -beta*xi; 2104 return w; 2105} 2106#endif 2107 2108/**************************************************************************** 2109 double complex catanh(double complex z) returns the complex inverse hyperbolic tangent 2110 of its argument. The algorithm is from Kahan's paper and is based on 2111 the formula: 2112 2113 catanh(z) = (clog(1.0 + z) - clog(1 - z))/2.0. 2114 2115 CONSTANTS: FPKTHETA = sqrt(nextafterd(+INF,0.0))/4.0 2116 FPKRHO = 1.0/FPKTHETA 2117 FPKPI2 = pi/2.0 2118 FPKPI = pi 2119 2120 Calls: copysign, fabs, xdivc, sqrt, log, atan, log1p, and carg. 2121****************************************************************************/ 2122 2123double complex catanh( double complex z ) 2124{ 2125 double complex ctemp, w; 2126 double t1, t2, xi, eta, beta; 2127 2128 beta = copysign(1.0,Real(z)); /* copes with unsigned zero */ 2129 2130 Imag(z) = -beta*Imag(z); /* transform real & imag components */ 2131 Real(z) = beta*Real(z); 2132 2133 if ((Real(z) > FPKTHETA.d) || (fabs(Imag(z)) > FPKTHETA.d)) { 2134 eta = copysign(M_PI_2,Imag(z)); /* avoid overflow */ 2135 ctemp = xdivc(1.0,z); 2136 xi = Real(ctemp); 2137 } 2138 2139 else if (Real(z) == 1.0) { 2140 t1 = fabs(Imag(z)) + FPKRHO.d; 2141 xi = log(sqrt(sqrt(4.0 + t1*t1))/sqrt(fabs(Imag(z)))); 2142 eta = 0.5*copysign(M_PI-atan(2.0/(fabs(Imag(z))+FPKRHO.d)),Imag(z)); 2143 } 2144 2145 else { /* usual case */ 2146 t2 = fabs(Imag(z)) + FPKRHO.d; 2147 t1 = 1.0 - Real(z); 2148 t2 = t2*t2; 2149 xi = 0.25*log1p(4.0*Real(z)/(t1*t1 + t2)); 2150 Real(ctemp) = (1.0 - Real(z))*(1.0 + Real(z)) - t2; 2151 Imag(ctemp) = Imag(z) + Imag(z); 2152 eta = 0.5*carg(ctemp); 2153 } 2154 2155 Real(w) = beta*xi; /* fix up signs of result */ 2156 Imag(w) = -beta*eta; 2157 return w; 2158} 2159 2160float complex catanhf( float complex z ) 2161{ 2162 float complex ctemp, w; 2163 float t1, t2, xi, eta, beta; 2164 2165 beta = copysignf(1.0f,Real(z)); /* copes with unsigned zero */ 2166 2167 Imag(z) = -beta*Imag(z); /* transform real & imag components */ 2168 Real(z) = beta*Real(z); 2169 2170 if ((Real(z) > FPKTHETAf.fval) || (fabsf(Imag(z)) > FPKTHETAf.fval)) { 2171 eta = copysignf((float) M_PI_2,Imag(z)); /* avoid overflow */ 2172 ctemp = xdivcf(1.0f,z); 2173 xi = Real(ctemp); 2174 } 2175 2176 else if (Real(z) == 1.0f) { 2177 t1 = fabsf(Imag(z)) + FPKRHOf.fval; 2178 xi = logf(sqrtf(sqrtf(4.0f + t1*t1))/sqrtf(fabsf(Imag(z)))); 2179 eta = 0.5f*copysignf((float)( M_PI-atan(2.0f/(fabsf(Imag(z))+FPKRHOf.fval))),Imag(z)); 2180 } 2181 2182 else { /* usual case */ 2183 t2 = fabsf(Imag(z)) + FPKRHOf.fval; 2184 t1 = 1.0f - Real(z); 2185 t2 = t2*t2; 2186 xi = 0.25f*log1pf(4.0f*Real(z)/(t1*t1 + t2)); 2187 Real(ctemp) = (1.0f - Real(z))*(1.0f + Real(z)) - t2; 2188 Imag(ctemp) = Imag(z) + Imag(z); 2189 eta = 0.5f*cargf(ctemp); 2190 } 2191 2192 Real(w) = beta*xi; /* fix up signs of result */ 2193 Imag(w) = -beta*eta; 2194 return w; 2195} 2196 2197#if (__WANT_LONG_DOUBLE_FORMAT__ - 0L == 128L) 2198long double complex catanhl( long double complex z ) 2199{ 2200 long double complex ctemp, w; 2201 long double t1, t2, xi, eta, beta; 2202 2203 beta = copysignl(1.0L,Real(z)); /* copes with unsigned zero */ 2204 2205 Imag(z) = -beta*Imag(z); /* transform real & imag components */ 2206 Real(z) = beta*Real(z); 2207 2208 if ((Real(z) > FPKTHETA.d) || (fabsl(Imag(z)) > FPKTHETA.d)) { 2209 eta = copysignl(M_PI_2,Imag(z)); /* avoid overflow */ 2210 ctemp = xdivcl(1.0L,z); 2211 xi = Real(ctemp); 2212 } 2213 2214 else if (Real(z) == 1.0L) { 2215 t1 = fabsl(Imag(z)) + FPKRHOl.ld; 2216 xi = logl(sqrtl(sqrtl(4.0L + t1*t1))/sqrtl(fabsl(Imag(z)))); 2217 eta = 0.5L*copysignl(M_PI-atanl(2.0L/(fabsl(Imag(z))+FPKRHOl.ld)),Imag(z)); 2218 } 2219 2220 else { /* usual case */ 2221 t2 = fabsl(Imag(z)) + FPKRHOl.ld; 2222 t1 = 1.0L - Real(z); 2223 t2 = t2*t2; 2224 xi = 0.25L*log1pl(4.0L*Real(z)/(t1*t1 + t2)); 2225 Real(ctemp) = (1.0L - Real(z))*(1.0L + Real(z)) - t2; 2226 Imag(ctemp) = Imag(z) + Imag(z); 2227 eta = 0.5L*cargl(ctemp); 2228 } 2229 2230 Real(w) = beta*xi; /* fix up signs of result */ 2231 Imag(w) = -beta*eta; 2232 return w; 2233} 2234#endif 2235 2236/* conj(), creal(), and cimag() are gcc built ins. */ 2237double creal( double complex z ) 2238{ 2239 return __builtin_creal(z); 2240} 2241 2242float crealf( float complex z ) 2243{ 2244 return __builtin_crealf(z); 2245} 2246 2247#if (__WANT_LONG_DOUBLE_FORMAT__ - 0L == 128L) 2248 2249long double creall( long double complex z ) 2250{ 2251 return __builtin_creall(z); 2252} 2253#endif 2254 2255double cimag( double complex z ) 2256{ 2257 return __builtin_cimag(z); 2258} 2259 2260float cimagf( float complex z ) 2261{ 2262 return __builtin_cimagf(z); 2263} 2264 2265#if (__WANT_LONG_DOUBLE_FORMAT__ - 0L == 128L) 2266 2267long double cimagl( long double complex z ) 2268{ 2269 return __builtin_cimagl(z); 2270} 2271#endif 2272 2273double complex conj( double complex z ) 2274{ 2275 return __builtin_conj(z); 2276} 2277 2278float complex conjf( float complex z ) 2279{ 2280 return __builtin_conjf(z); 2281} 2282 2283#if (__WANT_LONG_DOUBLE_FORMAT__ - 0L == 128L) 2284 2285long double complex conjl( long double complex z ) 2286{ 2287 return __builtin_conjl(z); 2288} 2289#endif 2290 2291double complex cproj( double complex z ) 2292{ 2293 static const double inf = __builtin_inf(); 2294 double u = __builtin_fabs(Real(z)); 2295 double v = __builtin_fabs(Imag(z)); 2296 2297 if (unlikely((u == inf) || (v == inf))) 2298 return inf + I*copysign(0.0, Imag(z)); 2299 else 2300 return z; 2301} 2302 2303float complex cprojf( float complex z ) 2304{ 2305 static const double inf = __builtin_inff(); 2306 float u = __builtin_fabsf(Real(z)); 2307 float v = __builtin_fabsf(Imag(z)); 2308 2309 if (unlikely((u == inf) || (v == inf))) 2310 return inf + I*copysignf(0.0f, Imag(z)); 2311 else 2312 return z; 2313} 2314 2315#if (__WANT_LONG_DOUBLE_FORMAT__ - 0L == 128L) 2316// PPC long double 2317long double complex cprojl( long double complex z ) 2318{ 2319 static const double inf = __builtin_infl(); 2320 float u = __builtin_fabsl(Real(z)); 2321 float v = __builtin_fabsl(Imag(z)); 2322 2323 if (unlikely((u == inf) || (v == inf))) 2324 return inf + I*copysignl(0.0l, Imag(z)); 2325 else 2326 return z; 2327} 2328#endif