z_log.c 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. #include "f2c.h"
  2. #ifdef KR_headers
  3. double log(), f__cabs(), atan2();
  4. #define ANSI(x) ()
  5. #else
  6. #define ANSI(x) x
  7. #undef abs
  8. #include "math.h"
  9. #ifdef __cplusplus
  10. extern "C" {
  11. #endif
  12. extern double f__cabs(double, double);
  13. #endif
  14. #ifndef NO_DOUBLE_EXTENDED
  15. #ifndef GCC_COMPARE_BUG_FIXED
  16. #ifndef Pre20000310
  17. #ifdef Comment
  18. Some versions of gcc, such as 2.95.3 and 3.0.4, are buggy under -O2 or -O3:
  19. on IA32 (Intel 80x87) systems, they may do comparisons on values computed
  20. in extended-precision registers. This can lead to the test "s > s0" that
  21. was used below being carried out incorrectly. The fix below cannot be
  22. spoiled by overzealous optimization, since the compiler cannot know
  23. whether gcc_bug_bypass_diff_F2C will be nonzero. (We expect it always
  24. to be zero. The weird name is unlikely to collide with anything.)
  25. An example (provided by Ulrich Jakobus) where the bug fix matters is
  26. double complex a, b
  27. a = (.1099557428756427618354862829619, .9857360542953131909982289471372)
  28. b = log(a)
  29. An alternative to the fix below would be to use 53-bit rounding precision,
  30. but the means of specifying this 80x87 feature are highly unportable.
  31. #endif /*Comment*/
  32. #define BYPASS_GCC_COMPARE_BUG
  33. double (*gcc_bug_bypass_diff_F2C) ANSI((double*,double*));
  34. static double
  35. #ifdef KR_headers
  36. diff1(a,b) double *a, *b;
  37. #else
  38. diff1(double *a, double *b)
  39. #endif
  40. { return *a - *b; }
  41. #endif /*Pre20000310*/
  42. #endif /*GCC_COMPARE_BUG_FIXED*/
  43. #endif /*NO_DOUBLE_EXTENDED*/
  44. #ifdef KR_headers
  45. VOID z_log(r, z) doublecomplex *r, *z;
  46. #else
  47. void z_log(doublecomplex *r, doublecomplex *z)
  48. #endif
  49. {
  50. double s, s0, t, t2, u, v;
  51. double zi = z->i, zr = z->r;
  52. #ifdef BYPASS_GCC_COMPARE_BUG
  53. double (*diff) ANSI((double*,double*));
  54. #endif
  55. r->i = atan2(zi, zr);
  56. #ifdef Pre20000310
  57. r->r = log( f__cabs( zr, zi ) );
  58. #else
  59. if (zi < 0)
  60. zi = -zi;
  61. if (zr < 0)
  62. zr = -zr;
  63. if (zr < zi) {
  64. t = zi;
  65. zi = zr;
  66. zr = t;
  67. }
  68. t = zi/zr;
  69. s = zr * sqrt(1 + t*t);
  70. /* now s = f__cabs(zi,zr), and zr = |zr| >= |zi| = zi */
  71. if ((t = s - 1) < 0)
  72. t = -t;
  73. if (t > .01)
  74. r->r = log(s);
  75. else {
  76. #ifdef Comment
  77. log(1+x) = x - x^2/2 + x^3/3 - x^4/4 + - ...
  78. = x(1 - x/2 + x^2/3 -+...)
  79. [sqrt(y^2 + z^2) - 1] * [sqrt(y^2 + z^2) + 1] = y^2 + z^2 - 1, so
  80. sqrt(y^2 + z^2) - 1 = (y^2 + z^2 - 1) / [sqrt(y^2 + z^2) + 1]
  81. #endif /*Comment*/
  82. #ifdef BYPASS_GCC_COMPARE_BUG
  83. if (!(diff = gcc_bug_bypass_diff_F2C))
  84. diff = diff1;
  85. #endif
  86. t = ((zr*zr - 1.) + zi*zi) / (s + 1);
  87. t2 = t*t;
  88. s = 1. - 0.5*t;
  89. u = v = 1;
  90. do {
  91. s0 = s;
  92. u *= t2;
  93. v += 2;
  94. s += u/v - t*u/(v+1);
  95. }
  96. #ifdef BYPASS_GCC_COMPARE_BUG
  97. while(s - s0 > 1e-18 || (*diff)(&s,&s0) > 0.);
  98. #else
  99. while(s > s0);
  100. #endif
  101. r->r = s*t;
  102. }
  103. #endif
  104. }
  105. #ifdef __cplusplus
  106. }
  107. #endif