frexp.c 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. /* Split a double into fraction and mantissa.
  2. Copyright (C) 2007-2023 Free Software Foundation, Inc.
  3. This file is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU Lesser General Public License as
  5. published by the Free Software Foundation; either version 2.1 of the
  6. License, or (at your option) any later version.
  7. This file 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 Lesser General Public License for more details.
  11. You should have received a copy of the GNU Lesser General Public License
  12. along with this program. If not, see <https://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. }