1/* Test of splitting a 'long double' into fraction and mantissa.
2   Copyright (C) 2007-2010 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 Bruno Haible <bruno@clisp.org>, 2007.  */
18
19#include <config.h>
20
21#include <math.h>
22
23#include "signature.h"
24SIGNATURE_CHECK (frexpl, long double, (long double, int *));
25
26#include <float.h>
27
28#include "fpucw.h"
29#include "isnanl-nolibm.h"
30#include "nan.h"
31#include "macros.h"
32
33/* Avoid some warnings from "gcc -Wshadow".
34   This file doesn't use the exp() function.  */
35#undef exp
36#define exp exponent
37
38/* On MIPS IRIX machines, LDBL_MIN_EXP is -1021, but the smallest reliable
39   exponent for 'long double' is -964.  Similarly, on PowerPC machines,
40   LDBL_MIN_EXP is -1021, but the smallest reliable exponent for 'long double'
41   is -968.  For exponents below that, the precision may be truncated to the
42   precision used for 'double'.  */
43#ifdef __sgi
44# define MIN_NORMAL_EXP (LDBL_MIN_EXP + 57)
45#elif defined __ppc || defined __ppc__ || defined __powerpc || defined __powerpc__
46# define MIN_NORMAL_EXP (LDBL_MIN_EXP + 53)
47#else
48# define MIN_NORMAL_EXP LDBL_MIN_EXP
49#endif
50
51/* On HP-UX 10.20, negating 0.0L does not yield -0.0L.
52   So we use minus_zero instead.
53   IRIX cc can't put -0.0L into .data, but can compute at runtime.
54   Note that the expression -LDBL_MIN * LDBL_MIN does not work on other
55   platforms, such as when cross-compiling to PowerPC on MacOS X 10.5.  */
56#if defined __hpux || defined __sgi
57static long double
58compute_minus_zero (void)
59{
60  return -LDBL_MIN * LDBL_MIN;
61}
62# define minus_zero compute_minus_zero ()
63#else
64long double minus_zero = -0.0L;
65#endif
66
67static long double
68my_ldexp (long double x, int d)
69{
70  for (; d > 0; d--)
71    x *= 2.0L;
72  for (; d < 0; d++)
73    x *= 0.5L;
74  return x;
75}
76
77int
78main ()
79{
80  int i;
81  long double x;
82  DECL_LONG_DOUBLE_ROUNDING
83
84  BEGIN_LONG_DOUBLE_ROUNDING ();
85
86  { /* NaN.  */
87    int exp = -9999;
88    long double mantissa;
89    x = NaNl ();
90    mantissa = frexpl (x, &exp);
91    ASSERT (isnanl (mantissa));
92  }
93
94  { /* Positive infinity.  */
95    int exp = -9999;
96    long double mantissa;
97    x = 1.0L / 0.0L;
98    mantissa = frexpl (x, &exp);
99    ASSERT (mantissa == x);
100  }
101
102  { /* Negative infinity.  */
103    int exp = -9999;
104    long double mantissa;
105    x = -1.0L / 0.0L;
106    mantissa = frexpl (x, &exp);
107    ASSERT (mantissa == x);
108  }
109
110  { /* Positive zero.  */
111    int exp = -9999;
112    long double mantissa;
113    x = 0.0L;
114    mantissa = frexpl (x, &exp);
115    ASSERT (exp == 0);
116    ASSERT (mantissa == x);
117    ASSERT (!signbit (mantissa));
118  }
119
120  { /* Negative zero.  */
121    int exp = -9999;
122    long double mantissa;
123    x = minus_zero;
124    mantissa = frexpl (x, &exp);
125    ASSERT (exp == 0);
126    ASSERT (mantissa == x);
127    ASSERT (signbit (mantissa));
128  }
129
130  for (i = 1, x = 1.0L; i <= LDBL_MAX_EXP; i++, x *= 2.0L)
131    {
132      int exp = -9999;
133      long double mantissa = frexpl (x, &exp);
134      ASSERT (exp == i);
135      ASSERT (mantissa == 0.5L);
136    }
137  for (i = 1, x = 1.0L; i >= MIN_NORMAL_EXP; i--, x *= 0.5L)
138    {
139      int exp = -9999;
140      long double mantissa = frexpl (x, &exp);
141      ASSERT (exp == i);
142      ASSERT (mantissa == 0.5L);
143    }
144  for (; i >= LDBL_MIN_EXP - 100 && x > 0.0L; i--, x *= 0.5L)
145    {
146      int exp = -9999;
147      long double mantissa = frexpl (x, &exp);
148      ASSERT (exp == i);
149      ASSERT (mantissa == 0.5L);
150    }
151
152  for (i = 1, x = -1.0L; i <= LDBL_MAX_EXP; i++, x *= 2.0L)
153    {
154      int exp = -9999;
155      long double mantissa = frexpl (x, &exp);
156      ASSERT (exp == i);
157      ASSERT (mantissa == -0.5L);
158    }
159  for (i = 1, x = -1.0L; i >= MIN_NORMAL_EXP; i--, x *= 0.5L)
160    {
161      int exp = -9999;
162      long double mantissa = frexpl (x, &exp);
163      ASSERT (exp == i);
164      ASSERT (mantissa == -0.5L);
165    }
166  for (; i >= LDBL_MIN_EXP - 100 && x < 0.0L; i--, x *= 0.5L)
167    {
168      int exp = -9999;
169      long double mantissa = frexpl (x, &exp);
170      ASSERT (exp == i);
171      ASSERT (mantissa == -0.5L);
172    }
173
174  for (i = 1, x = 1.01L; i <= LDBL_MAX_EXP; i++, x *= 2.0L)
175    {
176      int exp = -9999;
177      long double mantissa = frexpl (x, &exp);
178      ASSERT (exp == i);
179      ASSERT (mantissa == 0.505L);
180    }
181  for (i = 1, x = 1.01L; i >= MIN_NORMAL_EXP; i--, x *= 0.5L)
182    {
183      int exp = -9999;
184      long double mantissa = frexpl (x, &exp);
185      ASSERT (exp == i);
186      ASSERT (mantissa == 0.505L);
187    }
188  for (; i >= LDBL_MIN_EXP - 100 && x > 0.0L; i--, x *= 0.5L)
189    {
190      int exp = -9999;
191      long double mantissa = frexpl (x, &exp);
192      ASSERT (exp == i);
193      ASSERT (mantissa >= 0.5L);
194      ASSERT (mantissa < 1.0L);
195      ASSERT (mantissa == my_ldexp (x, - exp));
196    }
197
198  for (i = 1, x = 1.73205L; i <= LDBL_MAX_EXP; i++, x *= 2.0L)
199    {
200      int exp = -9999;
201      long double mantissa = frexpl (x, &exp);
202      ASSERT (exp == i);
203      ASSERT (mantissa == 0.866025L);
204    }
205  for (i = 1, x = 1.73205L; i >= MIN_NORMAL_EXP; i--, x *= 0.5L)
206    {
207      int exp = -9999;
208      long double mantissa = frexpl (x, &exp);
209      ASSERT (exp == i);
210      ASSERT (mantissa == 0.866025L);
211    }
212  for (; i >= LDBL_MIN_EXP - 100 && x > 0.0L; i--, x *= 0.5L)
213    {
214      int exp = -9999;
215      long double mantissa = frexpl (x, &exp);
216      ASSERT (exp == i || exp == i + 1);
217      ASSERT (mantissa >= 0.5L);
218      ASSERT (mantissa < 1.0L);
219      ASSERT (mantissa == my_ldexp (x, - exp));
220    }
221
222  return 0;
223}
224