Assume 'long double' exists.
[gnulib.git] / lib / printf-frexp.c
1 /* Split a double into fraction and mantissa, for hexadecimal printf.
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 /* Specification.  */
21 #ifdef USE_LONG_DOUBLE
22 # include "printf-frexpl.h"
23 #else
24 # include "printf-frexp.h"
25 #endif
26
27 #include <float.h>
28 #include <math.h>
29 #ifdef USE_LONG_DOUBLE
30 # include "fpucw.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 <= 2.0, not < 2.0.  */
36
37 #ifdef USE_LONG_DOUBLE
38 # define FUNC printf_frexpl
39 # define DOUBLE long double
40 # define MIN_EXP LDBL_MIN_EXP
41 # if HAVE_FREXPL_IN_LIBC && HAVE_LDEXPL_IN_LIBC
42 #  define USE_FREXP_LDEXP
43 #  define FREXP frexpl
44 #  define LDEXP ldexpl
45 # endif
46 # define DECL_ROUNDING DECL_LONG_DOUBLE_ROUNDING
47 # define BEGIN_ROUNDING() BEGIN_LONG_DOUBLE_ROUNDING ()
48 # define END_ROUNDING() END_LONG_DOUBLE_ROUNDING ()
49 # define L_(literal) literal##L
50 #else
51 # define FUNC printf_frexp
52 # define DOUBLE double
53 # define MIN_EXP DBL_MIN_EXP
54 # if HAVE_FREXP_IN_LIBC && HAVE_LDEXP_IN_LIBC
55 #  define USE_FREXP_LDEXP
56 #  define FREXP frexp
57 #  define LDEXP ldexp
58 # endif
59 # define DECL_ROUNDING
60 # define BEGIN_ROUNDING()
61 # define END_ROUNDING()
62 # define L_(literal) literal
63 #endif
64
65 DOUBLE
66 FUNC (DOUBLE x, int *exp)
67 {
68   int exponent;
69   DECL_ROUNDING
70
71   BEGIN_ROUNDING ();
72
73 #ifdef USE_FREXP_LDEXP
74   /* frexp and ldexp are usually faster than the loop below.  */
75   x = FREXP (x, &exponent);
76
77   x = x + x;
78   exponent -= 1;
79
80   if (exponent < MIN_EXP - 1)
81     {
82       x = LDEXP (x, exponent - (MIN_EXP - 1));
83       exponent = MIN_EXP - 1;
84     }
85 #else
86   {
87     /* Since the exponent is an 'int', it fits in 64 bits.  Therefore the
88        loops are executed no more than 64 times.  */
89     DOUBLE pow2[64]; /* pow2[i] = 2^2^i */
90     DOUBLE powh[64]; /* powh[i] = 2^-2^i */
91     int i;
92
93     exponent = 0;
94     if (x >= L_(1.0))
95       {
96         /* A nonnegative exponent.  */
97         {
98           DOUBLE pow2_i; /* = pow2[i] */
99           DOUBLE powh_i; /* = powh[i] */
100
101           /* Invariants: pow2_i = 2^2^i, powh_i = 2^-2^i,
102              x * 2^exponent = argument, x >= 1.0.  */
103           for (i = 0, pow2_i = L_(2.0), powh_i = L_(0.5);
104                ;
105                i++, pow2_i = pow2_i * pow2_i, powh_i = powh_i * powh_i)
106             {
107               if (x >= pow2_i)
108                 {
109                   exponent += (1 << i);
110                   x *= powh_i;
111                 }
112               else
113                 break;
114
115               pow2[i] = pow2_i;
116               powh[i] = powh_i;
117             }
118         }
119         /* Here 1.0 <= x < 2^2^i.  */
120       }
121     else
122       {
123         /* A negative exponent.  */
124         {
125           DOUBLE pow2_i; /* = pow2[i] */
126           DOUBLE powh_i; /* = powh[i] */
127
128           /* Invariants: pow2_i = 2^2^i, powh_i = 2^-2^i,
129              x * 2^exponent = argument, x < 1.0, exponent >= MIN_EXP - 1.  */
130           for (i = 0, pow2_i = L_(2.0), powh_i = L_(0.5);
131                ;
132                i++, pow2_i = pow2_i * pow2_i, powh_i = powh_i * powh_i)
133             {
134               if (exponent - (1 << i) < MIN_EXP - 1)
135                 break;
136
137               exponent -= (1 << i);
138               x *= pow2_i;
139               if (x >= L_(1.0))
140                 break;
141
142               pow2[i] = pow2_i;
143               powh[i] = powh_i;
144             }
145         }
146         /* Here either x < 1.0 and exponent - 2^i < MIN_EXP - 1 <= exponent,
147            or 1.0 <= x < 2^2^i and exponent >= MIN_EXP - 1.  */
148
149         if (x < L_(1.0))
150           /* Invariants: x * 2^exponent = argument, x < 1.0 and
151              exponent - 2^i < MIN_EXP - 1 <= exponent.  */
152           while (i > 0)
153             {
154               i--;
155               if (exponent - (1 << i) >= MIN_EXP - 1)
156                 {
157                   exponent -= (1 << i);
158                   x *= pow2[i];
159                   if (x >= L_(1.0))
160                     break;
161                 }
162             }
163
164         /* Here either x < 1.0 and exponent = MIN_EXP - 1,
165            or 1.0 <= x < 2^2^i and exponent >= MIN_EXP - 1.  */
166       }
167
168     /* Invariants: x * 2^exponent = argument, and
169        either x < 1.0 and exponent = MIN_EXP - 1,
170        or 1.0 <= x < 2^2^i and exponent >= MIN_EXP - 1.  */
171     while (i > 0)
172       {
173         i--;
174         if (x >= pow2[i])
175           {
176             exponent += (1 << i);
177             x *= powh[i];
178           }
179       }
180     /* Here either x < 1.0 and exponent = MIN_EXP - 1,
181        or 1.0 <= x < 2.0 and exponent >= MIN_EXP - 1.  */
182   }
183 #endif
184
185   END_ROUNDING ();
186
187   *exp = exponent;
188   return x;
189 }