unity.c 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. /* unity.c
  2. *
  3. * Relative error approximations for function arguments near
  4. * unity.
  5. *
  6. * log1p(x) = log(1+x)
  7. * expm1(x) = exp(x) - 1
  8. * cosm1(x) = cos(x) - 1
  9. *
  10. */
  11. #include <math.h>
  12. #ifdef ANSIPROT
  13. extern int isnan (double);
  14. extern int isfinite (double);
  15. extern double log ( double );
  16. extern double polevl ( double, void *, int );
  17. extern double p1evl ( double, void *, int );
  18. extern double exp ( double );
  19. extern double cos ( double );
  20. #else
  21. double log(), polevl(), p1evl(), exp(), cos();
  22. int isnan(), isfinite();
  23. #endif
  24. extern double INFINITY;
  25. /* log1p(x) = log(1 + x) */
  26. /* Coefficients for log(1+x) = x - x**2/2 + x**3 P(x)/Q(x)
  27. * 1/sqrt(2) <= x < sqrt(2)
  28. * Theoretical peak relative error = 2.32e-20
  29. */
  30. static double LP[] = {
  31. 4.5270000862445199635215E-5,
  32. 4.9854102823193375972212E-1,
  33. 6.5787325942061044846969E0,
  34. 2.9911919328553073277375E1,
  35. 6.0949667980987787057556E1,
  36. 5.7112963590585538103336E1,
  37. 2.0039553499201281259648E1,
  38. };
  39. static double LQ[] = {
  40. /* 1.0000000000000000000000E0,*/
  41. 1.5062909083469192043167E1,
  42. 8.3047565967967209469434E1,
  43. 2.2176239823732856465394E2,
  44. 3.0909872225312059774938E2,
  45. 2.1642788614495947685003E2,
  46. 6.0118660497603843919306E1,
  47. };
  48. #define SQRTH 0.70710678118654752440
  49. #define SQRT2 1.41421356237309504880
  50. double log1p(x)
  51. double x;
  52. {
  53. double z;
  54. z = 1.0 + x;
  55. if( (z < SQRTH) || (z > SQRT2) )
  56. return( log(z) );
  57. z = x*x;
  58. z = -0.5 * z + x * ( z * polevl( x, LP, 6 ) / p1evl( x, LQ, 6 ) );
  59. return (x + z);
  60. }
  61. /* expm1(x) = exp(x) - 1 */
  62. /* e^x = 1 + 2x P(x^2)/( Q(x^2) - P(x^2) )
  63. * -0.5 <= x <= 0.5
  64. */
  65. static double EP[3] = {
  66. 1.2617719307481059087798E-4,
  67. 3.0299440770744196129956E-2,
  68. 9.9999999999999999991025E-1,
  69. };
  70. static double EQ[4] = {
  71. 3.0019850513866445504159E-6,
  72. 2.5244834034968410419224E-3,
  73. 2.2726554820815502876593E-1,
  74. 2.0000000000000000000897E0,
  75. };
  76. double expm1(x)
  77. double x;
  78. {
  79. double r, xx;
  80. #ifdef NANS
  81. if( isnan(x) )
  82. return(x);
  83. #endif
  84. #ifdef INFINITIES
  85. if( x == INFINITY )
  86. return(INFINITY);
  87. if( x == -INFINITY )
  88. return(-1.0);
  89. #endif
  90. if( (x < -0.5) || (x > 0.5) )
  91. return( exp(x) - 1.0 );
  92. xx = x * x;
  93. r = x * polevl( xx, EP, 2 );
  94. r = r/( polevl( xx, EQ, 3 ) - r );
  95. return (r + r);
  96. }
  97. /* cosm1(x) = cos(x) - 1 */
  98. static double coscof[7] = {
  99. 4.7377507964246204691685E-14,
  100. -1.1470284843425359765671E-11,
  101. 2.0876754287081521758361E-9,
  102. -2.7557319214999787979814E-7,
  103. 2.4801587301570552304991E-5,
  104. -1.3888888888888872993737E-3,
  105. 4.1666666666666666609054E-2,
  106. };
  107. extern double PIO4;
  108. double cosm1(x)
  109. double x;
  110. {
  111. double xx;
  112. if( (x < -PIO4) || (x > PIO4) )
  113. return( cos(x) - 1.0 );
  114. xx = x * x;
  115. xx = -0.5*xx + xx * xx * polevl( xx, coscof, 6 );
  116. return xx;
  117. }