New module 'frexp'.
[gnulib.git] / lib / frexp.c
1 /* Split a double into fraction and mantissa.
2    Copyright (C) 2007 Free Software Foundation, Inc.
3
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; either version 2, or (at your option)
7    any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License along
15    with this program; if not, write to the Free Software Foundation,
16    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
17
18 #include <config.h>
19
20 #if !(defined USE_LONG_DOUBLE && !HAVE_LONG_DOUBLE)
21
22 /* Specification.  */
23 # include <math.h>
24
25 # include <float.h>
26 # ifdef USE_LONG_DOUBLE
27 #  include "isnanl-nolibm.h"
28 # else
29 #  include "isnan.h"
30 # endif
31
32 /* This file assumes FLT_RADIX = 2.  If FLT_RADIX is a power of 2 greater
33    than 2, or not even a power of 2, some rounding errors can occur, so that
34    then the returned mantissa is only guaranteed to be <= 1.0, not < 1.0.  */
35
36 # ifdef USE_LONG_DOUBLE
37 #  define FUNC frexpl
38 #  define DOUBLE long double
39 #  define ISNAN isnanl
40 #  define L_(literal) literal##L
41 # else
42 #  define FUNC frexp
43 #  define DOUBLE double
44 #  define ISNAN isnan
45 #  define L_(literal) literal
46 # endif
47
48 DOUBLE
49 FUNC (DOUBLE x, int *exp)
50 {
51   int sign;
52   int exponent;
53
54   /* Test for NaN, infinity, and zero.  */
55   if (ISNAN (x) || x + x == x)
56     {
57       *exp = 0;
58       return x;
59     }
60
61   sign = 0;
62   if (x < 0)
63     {
64       x = - x;
65       sign = -1;
66     }
67
68   if (0)
69     {
70       /* Implementation contributed by Paolo Bonzini.
71          Disabled because it's under GPL and doesn't pass the tests.  */
72
73       /* Since the exponent is an 'int', it fits in 64 bits.  Therefore the
74          loops are executed no more than 64 times.  */
75       DOUBLE exponents[64];
76       DOUBLE *next;
77       int bit;
78
79       exponent = 0;
80       if (x >= L_(1.0))
81         {
82           for (next = exponents, exponents[0] = L_(2.0), bit = 1;
83                *next <= x + x;
84                bit <<= 1, next[1] = next[0] * next[0], next++);
85
86           for (; next >= exponents; bit >>= 1, next--)
87             if (x + x >= *next)
88               {
89                 x /= *next;
90                 exponent |= bit;
91               }
92         }
93       else if (x < L_(0.5))
94         {
95           for (next = exponents, exponents[0] = L_(0.5), bit = 1;
96                *next > x;
97                bit <<= 1, next[1] = next[0] * next[0], next++);
98
99           for (; next >= exponents; bit >>= 1, next--)
100             if (x < *next)
101               {
102                 x /= *next;
103                 exponent |= bit;
104               }
105           exponent = - exponent;
106         }
107     }
108   else
109     {
110       /* Implementation contributed by Bruno Haible.  */
111
112       /* Since the exponent is an 'int', it fits in 64 bits.  Therefore the
113          loops are executed no more than 64 times.  */
114       DOUBLE pow2[64]; /* pow2[i] = 2^2^i */
115       DOUBLE powh[64]; /* powh[i] = 2^-2^i */
116       int i;
117
118       exponent = 0;
119       if (x >= L_(1.0))
120         {
121           /* A positive exponent.  */
122           DOUBLE pow2_i; /* = pow2[i] */
123           DOUBLE powh_i; /* = powh[i] */
124
125           /* Invariants: pow2_i = 2^2^i, powh_i = 2^-2^i,
126              x * 2^exponent = argument, x >= 1.0.  */
127           for (i = 0, pow2_i = L_(2.0), powh_i = L_(0.5);
128                ;
129                i++, pow2_i = pow2_i * pow2_i, powh_i = powh_i * powh_i)
130             {
131               if (x >= pow2_i)
132                 {
133                   exponent += (1 << i);
134                   x *= powh_i;
135                 }
136               else
137                 break;
138
139               pow2[i] = pow2_i;
140               powh[i] = powh_i;
141             }
142           /* Avoid making x too small, as it could become a denormalized
143              number and thus lose precision.  */
144           while (i > 0 && x < pow2[i - 1])
145             {
146               i--;
147               powh_i = powh[i];
148             }
149           exponent += (1 << i);
150           x *= powh_i;
151           /* Here 2^-2^i <= x < 1.0.  */
152         }
153       else
154         {
155           /* A negative or zero exponent.  */
156           DOUBLE pow2_i; /* = pow2[i] */
157           DOUBLE powh_i; /* = powh[i] */
158
159           /* Invariants: pow2_i = 2^2^i, powh_i = 2^-2^i,
160              x * 2^exponent = argument, x < 1.0.  */
161           for (i = 0, pow2_i = L_(2.0), powh_i = L_(0.5);
162                ;
163                i++, pow2_i = pow2_i * pow2_i, powh_i = powh_i * powh_i)
164             {
165               if (x < powh_i)
166                 {
167                   exponent -= (1 << i);
168                   x *= pow2_i;
169                 }
170               else
171                 break;
172
173               pow2[i] = pow2_i;
174               powh[i] = powh_i;
175             }
176           /* Here 2^-2^i <= x < 1.0.  */
177         }
178
179       /* Invariants: x * 2^exponent = argument, and 2^-2^i <= x < 1.0.  */
180       while (i > 0)
181         {
182           i--;
183           if (x < powh[i])
184             {
185               exponent -= (1 << i);
186               x *= pow2[i];
187             }
188         }
189       /* Here 0.5 <= x < 1.0.  */
190     }
191
192   *exp = exponent;
193   return (sign < 0 ? - x : x);
194 }
195
196 #else
197
198 /* This declaration is solely to ensure that after preprocessing
199    this file is never empty.  */
200 typedef int dummy;
201
202 #endif