ctanh.c 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. /* origin: FreeBSD /usr/src/lib/msun/src/s_ctanh.c */
  2. /*-
  3. * Copyright (c) 2011 David Schultz
  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 unmodified, this list of conditions, and the following
  11. * disclaimer.
  12. * 2. Redistributions in binary form must reproduce the above copyright
  13. * notice, this list of conditions and the following disclaimer in the
  14. * documentation and/or other materials provided with the distribution.
  15. *
  16. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  17. * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  18. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  19. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  20. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  21. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  22. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  23. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  24. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  25. * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26. */
  27. /*
  28. * Hyperbolic tangent of a complex argument z = x + i y.
  29. *
  30. * The algorithm is from:
  31. *
  32. * W. Kahan. Branch Cuts for Complex Elementary Functions or Much
  33. * Ado About Nothing's Sign Bit. In The State of the Art in
  34. * Numerical Analysis, pp. 165 ff. Iserles and Powell, eds., 1987.
  35. *
  36. * Method:
  37. *
  38. * Let t = tan(x)
  39. * beta = 1/cos^2(y)
  40. * s = sinh(x)
  41. * rho = cosh(x)
  42. *
  43. * We have:
  44. *
  45. * tanh(z) = sinh(z) / cosh(z)
  46. *
  47. * sinh(x) cos(y) + i cosh(x) sin(y)
  48. * = ---------------------------------
  49. * cosh(x) cos(y) + i sinh(x) sin(y)
  50. *
  51. * cosh(x) sinh(x) / cos^2(y) + i tan(y)
  52. * = -------------------------------------
  53. * 1 + sinh^2(x) / cos^2(y)
  54. *
  55. * beta rho s + i t
  56. * = ----------------
  57. * 1 + beta s^2
  58. *
  59. * Modifications:
  60. *
  61. * I omitted the original algorithm's handling of overflow in tan(x) after
  62. * verifying with nearpi.c that this can't happen in IEEE single or double
  63. * precision. I also handle large x differently.
  64. */
  65. #include "libm.h"
  66. double complex ctanh(double complex z)
  67. {
  68. double x, y;
  69. double t, beta, s, rho, denom;
  70. uint32_t hx, ix, lx;
  71. x = creal(z);
  72. y = cimag(z);
  73. EXTRACT_WORDS(hx, lx, x);
  74. ix = hx & 0x7fffffff;
  75. /*
  76. * ctanh(NaN + i 0) = NaN + i 0
  77. *
  78. * ctanh(NaN + i y) = NaN + i NaN for y != 0
  79. *
  80. * The imaginary part has the sign of x*sin(2*y), but there's no
  81. * special effort to get this right.
  82. *
  83. * ctanh(+-Inf +- i Inf) = +-1 +- 0
  84. *
  85. * ctanh(+-Inf + i y) = +-1 + 0 sin(2y) for y finite
  86. *
  87. * The imaginary part of the sign is unspecified. This special
  88. * case is only needed to avoid a spurious invalid exception when
  89. * y is infinite.
  90. */
  91. if (ix >= 0x7ff00000) {
  92. if ((ix & 0xfffff) | lx) /* x is NaN */
  93. return cpack(x, (y == 0 ? y : x * y));
  94. SET_HIGH_WORD(x, hx - 0x40000000); /* x = copysign(1, x) */
  95. return cpack(x, copysign(0, isinf(y) ? y : sin(y) * cos(y)));
  96. }
  97. /*
  98. * ctanh(x + i NAN) = NaN + i NaN
  99. * ctanh(x +- i Inf) = NaN + i NaN
  100. */
  101. if (!isfinite(y))
  102. return cpack(y - y, y - y);
  103. /*
  104. * ctanh(+-huge + i +-y) ~= +-1 +- i 2sin(2y)/exp(2x), using the
  105. * approximation sinh^2(huge) ~= exp(2*huge) / 4.
  106. * We use a modified formula to avoid spurious overflow.
  107. */
  108. if (ix >= 0x40360000) { /* x >= 22 */
  109. double exp_mx = exp(-fabs(x));
  110. return cpack(copysign(1, x), 4 * sin(y) * cos(y) * exp_mx * exp_mx);
  111. }
  112. /* Kahan's algorithm */
  113. t = tan(y);
  114. beta = 1.0 + t * t; /* = 1 / cos^2(y) */
  115. s = sinh(x);
  116. rho = sqrt(1 + s * s); /* = cosh(x) */
  117. denom = 1 + beta * s * s;
  118. return cpack((beta * rho * s) / denom, t / denom);
  119. }