1
0

sqrtf.c 1.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. /* origin: FreeBSD /usr/src/lib/msun/src/e_sqrtf.c */
  2. /*
  3. * Conversion to float by Ian Lance Taylor, Cygnus Support, [email protected].
  4. */
  5. /*
  6. * ====================================================
  7. * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
  8. *
  9. * Developed at SunPro, a Sun Microsystems, Inc. business.
  10. * Permission to use, copy, modify, and distribute this
  11. * software is freely granted, provided that this notice
  12. * is preserved.
  13. * ====================================================
  14. */
  15. #include "libm.h"
  16. static const float tiny = 1.0e-30;
  17. float sqrtf(float x)
  18. {
  19. float z;
  20. int32_t sign = (int)0x80000000;
  21. int32_t ix,s,q,m,t,i;
  22. uint32_t r;
  23. GET_FLOAT_WORD(ix, x);
  24. /* take care of Inf and NaN */
  25. if ((ix&0x7f800000) == 0x7f800000)
  26. return x*x + x; /* sqrt(NaN)=NaN, sqrt(+inf)=+inf, sqrt(-inf)=sNaN */
  27. /* take care of zero */
  28. if (ix <= 0) {
  29. if ((ix&~sign) == 0)
  30. return x; /* sqrt(+-0) = +-0 */
  31. if (ix < 0)
  32. return (x-x)/(x-x); /* sqrt(-ve) = sNaN */
  33. }
  34. /* normalize x */
  35. m = ix>>23;
  36. if (m == 0) { /* subnormal x */
  37. for (i = 0; (ix&0x00800000) == 0; i++)
  38. ix<<=1;
  39. m -= i - 1;
  40. }
  41. m -= 127; /* unbias exponent */
  42. ix = (ix&0x007fffff)|0x00800000;
  43. if (m&1) /* odd m, double x to make it even */
  44. ix += ix;
  45. m >>= 1; /* m = [m/2] */
  46. /* generate sqrt(x) bit by bit */
  47. ix += ix;
  48. q = s = 0; /* q = sqrt(x) */
  49. r = 0x01000000; /* r = moving bit from right to left */
  50. while (r != 0) {
  51. t = s + r;
  52. if (t <= ix) {
  53. s = t+r;
  54. ix -= t;
  55. q += r;
  56. }
  57. ix += ix;
  58. r >>= 1;
  59. }
  60. /* use floating add to find out rounding direction */
  61. if (ix != 0) {
  62. z = 1.0f - tiny; /* raise inexact flag */
  63. if (z >= 1.0f) {
  64. z = 1.0f + tiny;
  65. if (z > 1.0f)
  66. q += 2;
  67. else
  68. q += q & 1;
  69. }
  70. }
  71. ix = (q>>1) + 0x3f000000;
  72. ix += m << 23;
  73. SET_FLOAT_WORD(z, ix);
  74. return z;
  75. }