pow.c 965 B

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
  1. #include <u.h>
  2. #include <libc.h>
  3. double
  4. pow(double x, double y) /* return x ^ y (exponentiation) */
  5. {
  6. double xy, y1, ye;
  7. long i;
  8. int ex, ey, flip;
  9. if(y == 0.0)
  10. return 1.0;
  11. flip = 0;
  12. if(y < 0.){
  13. y = -y;
  14. flip = 1;
  15. }
  16. y1 = modf(y, &ye);
  17. if(y1 != 0.0){
  18. if(x <= 0.)
  19. goto zreturn;
  20. if(y1 > 0.5) {
  21. y1 -= 1.;
  22. ye += 1.;
  23. }
  24. xy = exp(y1 * log(x));
  25. }else
  26. xy = 1.0;
  27. if(ye > 0x7FFFFFFF){ /* should be ~0UL but compiler can't convert double to ulong */
  28. if(x <= 0.){
  29. zreturn:
  30. if(x==0. && !flip)
  31. return 0.;
  32. return NaN();
  33. }
  34. if(flip){
  35. if(y == .5)
  36. return 1./sqrt(x);
  37. y = -y;
  38. }else if(y == .5)
  39. return sqrt(x);
  40. return exp(y * log(x));
  41. }
  42. x = frexp(x, &ex);
  43. ey = 0;
  44. i = ye;
  45. if(i)
  46. for(;;){
  47. if(i & 1){
  48. xy *= x;
  49. ey += ex;
  50. }
  51. i >>= 1;
  52. if(i == 0)
  53. break;
  54. x *= x;
  55. ex <<= 1;
  56. if(x < .5){
  57. x += x;
  58. ex -= 1;
  59. }
  60. }
  61. if(flip){
  62. xy = 1. / xy;
  63. ey = -ey;
  64. }
  65. return ldexp(xy, ey);
  66. }