frexp.c 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. /* Split a double into fraction and mantissa.
  2. Copyright (C) 2007-2013 Free Software Foundation, Inc.
  3. This program is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation; either version 3 of the License, or
  6. (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program. If not, see <http://www.gnu.org/licenses/>. */
  13. /* Written by Paolo Bonzini <bonzini@gnu.org>, 2003, and
  14. Bruno Haible <bruno@clisp.org>, 2007. */
  15. #if ! defined USE_LONG_DOUBLE
  16. # include <config.h>
  17. #endif
  18. /* Specification. */
  19. #include <math.h>
  20. #include <float.h>
  21. #ifdef USE_LONG_DOUBLE
  22. # include "isnanl-nolibm.h"
  23. # include "fpucw.h"
  24. #else
  25. # include "isnand-nolibm.h"
  26. #endif
  27. /* This file assumes FLT_RADIX = 2. If FLT_RADIX is a power of 2 greater
  28. than 2, or not even a power of 2, some rounding errors can occur, so that
  29. then the returned mantissa is only guaranteed to be <= 1.0, not < 1.0. */
  30. #ifdef USE_LONG_DOUBLE
  31. # define FUNC frexpl
  32. # define DOUBLE long double
  33. # define ISNAN isnanl
  34. # define DECL_ROUNDING DECL_LONG_DOUBLE_ROUNDING
  35. # define BEGIN_ROUNDING() BEGIN_LONG_DOUBLE_ROUNDING ()
  36. # define END_ROUNDING() END_LONG_DOUBLE_ROUNDING ()
  37. # define L_(literal) literal##L
  38. #else
  39. # define FUNC frexp
  40. # define DOUBLE double
  41. # define ISNAN isnand
  42. # define DECL_ROUNDING
  43. # define BEGIN_ROUNDING()
  44. # define END_ROUNDING()
  45. # define L_(literal) literal
  46. #endif
  47. DOUBLE
  48. FUNC (DOUBLE x, int *expptr)
  49. {
  50. int sign;
  51. int exponent;
  52. DECL_ROUNDING
  53. /* Test for NaN, infinity, and zero. */
  54. if (ISNAN (x) || x + x == x)
  55. {
  56. *expptr = 0;
  57. return x;
  58. }
  59. sign = 0;
  60. if (x < 0)
  61. {
  62. x = - x;
  63. sign = -1;
  64. }
  65. BEGIN_ROUNDING ();
  66. {
  67. /* Since the exponent is an 'int', it fits in 64 bits. Therefore the
  68. loops are executed no more than 64 times. */
  69. DOUBLE pow2[64]; /* pow2[i] = 2^2^i */
  70. DOUBLE powh[64]; /* powh[i] = 2^-2^i */
  71. int i;
  72. exponent = 0;
  73. if (x >= L_(1.0))
  74. {
  75. /* A positive exponent. */
  76. DOUBLE pow2_i; /* = pow2[i] */
  77. DOUBLE powh_i; /* = powh[i] */
  78. /* Invariants: pow2_i = 2^2^i, powh_i = 2^-2^i,
  79. x * 2^exponent = argument, x >= 1.0. */
  80. for (i = 0, pow2_i = L_(2.0), powh_i = L_(0.5);
  81. ;
  82. i++, pow2_i = pow2_i * pow2_i, powh_i = powh_i * powh_i)
  83. {
  84. if (x >= pow2_i)
  85. {
  86. exponent += (1 << i);
  87. x *= powh_i;
  88. }
  89. else
  90. break;
  91. pow2[i] = pow2_i;
  92. powh[i] = powh_i;
  93. }
  94. /* Avoid making x too small, as it could become a denormalized
  95. number and thus lose precision. */
  96. while (i > 0 && x < pow2[i - 1])
  97. {
  98. i--;
  99. powh_i = powh[i];
  100. }
  101. exponent += (1 << i);
  102. x *= powh_i;
  103. /* Here 2^-2^i <= x < 1.0. */
  104. }
  105. else
  106. {
  107. /* A negative or zero exponent. */
  108. DOUBLE pow2_i; /* = pow2[i] */
  109. DOUBLE powh_i; /* = powh[i] */
  110. /* Invariants: pow2_i = 2^2^i, powh_i = 2^-2^i,
  111. x * 2^exponent = argument, x < 1.0. */
  112. for (i = 0, pow2_i = L_(2.0), powh_i = L_(0.5);
  113. ;
  114. i++, pow2_i = pow2_i * pow2_i, powh_i = powh_i * powh_i)
  115. {
  116. if (x < powh_i)
  117. {
  118. exponent -= (1 << i);
  119. x *= pow2_i;
  120. }
  121. else
  122. break;
  123. pow2[i] = pow2_i;
  124. powh[i] = powh_i;
  125. }
  126. /* Here 2^-2^i <= x < 1.0. */
  127. }
  128. /* Invariants: x * 2^exponent = argument, and 2^-2^i <= x < 1.0. */
  129. while (i > 0)
  130. {
  131. i--;
  132. if (x < powh[i])
  133. {
  134. exponent -= (1 << i);
  135. x *= pow2[i];
  136. }
  137. }
  138. /* Here 0.5 <= x < 1.0. */
  139. }
  140. if (sign < 0)
  141. x = - x;
  142. END_ROUNDING ();
  143. *expptr = exponent;
  144. return x;
  145. }