Imported Upstream version 1.3.14
[debian/gzip] / lib / frexp.c
1 /* Split a double into fraction and mantissa.
2    Copyright (C) 2007-2008 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 3 of the License, or
7    (at your option) 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
15    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
16
17 /* Written by Paolo Bonzini <bonzini@gnu.org>, 2003, and
18    Bruno Haible <bruno@clisp.org>, 2007.  */
19
20 #include <config.h>
21
22 /* Specification.  */
23 #include <math.h>
24
25 #include <float.h>
26 #ifdef USE_LONG_DOUBLE
27 # include "isnanl-nolibm.h"
28 # include "fpucw.h"
29 #else
30 # include "isnand-nolibm.h"
31 #endif
32
33 /* This file assumes FLT_RADIX = 2.  If FLT_RADIX is a power of 2 greater
34    than 2, or not even a power of 2, some rounding errors can occur, so that
35    then the returned mantissa is only guaranteed to be <= 1.0, not < 1.0.  */
36
37 #ifdef USE_LONG_DOUBLE
38 # define FUNC frexpl
39 # define DOUBLE long double
40 # define ISNAN isnanl
41 # define DECL_ROUNDING DECL_LONG_DOUBLE_ROUNDING
42 # define BEGIN_ROUNDING() BEGIN_LONG_DOUBLE_ROUNDING ()
43 # define END_ROUNDING() END_LONG_DOUBLE_ROUNDING ()
44 # define L_(literal) literal##L
45 #else
46 # define FUNC frexp
47 # define DOUBLE double
48 # define ISNAN isnand
49 # define DECL_ROUNDING
50 # define BEGIN_ROUNDING()
51 # define END_ROUNDING()
52 # define L_(literal) literal
53 #endif
54
55 DOUBLE
56 FUNC (DOUBLE x, int *expptr)
57 {
58   int sign;
59   int exponent;
60   DECL_ROUNDING
61
62   /* Test for NaN, infinity, and zero.  */
63   if (ISNAN (x) || x + x == x)
64     {
65       *expptr = 0;
66       return x;
67     }
68
69   sign = 0;
70   if (x < 0)
71     {
72       x = - x;
73       sign = -1;
74     }
75
76   BEGIN_ROUNDING ();
77
78   {
79     /* Since the exponent is an 'int', it fits in 64 bits.  Therefore the
80        loops are executed no more than 64 times.  */
81     DOUBLE pow2[64]; /* pow2[i] = 2^2^i */
82     DOUBLE powh[64]; /* powh[i] = 2^-2^i */
83     int i;
84
85     exponent = 0;
86     if (x >= L_(1.0))
87       {
88         /* A positive exponent.  */
89         DOUBLE pow2_i; /* = pow2[i] */
90         DOUBLE powh_i; /* = powh[i] */
91
92         /* Invariants: pow2_i = 2^2^i, powh_i = 2^-2^i,
93            x * 2^exponent = argument, x >= 1.0.  */
94         for (i = 0, pow2_i = L_(2.0), powh_i = L_(0.5);
95              ;
96              i++, pow2_i = pow2_i * pow2_i, powh_i = powh_i * powh_i)
97           {
98             if (x >= pow2_i)
99               {
100                 exponent += (1 << i);
101                 x *= powh_i;
102               }
103             else
104               break;
105
106             pow2[i] = pow2_i;
107             powh[i] = powh_i;
108           }
109         /* Avoid making x too small, as it could become a denormalized
110            number and thus lose precision.  */
111         while (i > 0 && x < pow2[i - 1])
112           {
113             i--;
114             powh_i = powh[i];
115           }
116         exponent += (1 << i);
117         x *= powh_i;
118         /* Here 2^-2^i <= x < 1.0.  */
119       }
120     else
121       {
122         /* A negative or zero exponent.  */
123         DOUBLE pow2_i; /* = pow2[i] */
124         DOUBLE powh_i; /* = powh[i] */
125
126         /* Invariants: pow2_i = 2^2^i, powh_i = 2^-2^i,
127            x * 2^exponent = argument, x < 1.0.  */
128         for (i = 0, pow2_i = L_(2.0), powh_i = L_(0.5);
129              ;
130              i++, pow2_i = pow2_i * pow2_i, powh_i = powh_i * powh_i)
131           {
132             if (x < powh_i)
133               {
134                 exponent -= (1 << i);
135                 x *= pow2_i;
136               }
137             else
138               break;
139
140             pow2[i] = pow2_i;
141             powh[i] = powh_i;
142           }
143         /* Here 2^-2^i <= x < 1.0.  */
144       }
145
146     /* Invariants: x * 2^exponent = argument, and 2^-2^i <= x < 1.0.  */
147     while (i > 0)
148       {
149         i--;
150         if (x < powh[i])
151           {
152             exponent -= (1 << i);
153             x *= pow2[i];
154           }
155       }
156     /* Here 0.5 <= x < 1.0.  */
157   }
158
159   if (sign < 0)
160     x = - x;
161
162   END_ROUNDING ();
163
164   *expptr = exponent;
165   return x;
166 }