1/* Test file for mpfr_get_f.
2
3Copyright 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
4Contributed by the Arenaire and Cacao projects, INRIA.
5
6This file is part of the GNU MPFR Library.
7
8The GNU MPFR Library is free software; you can redistribute it and/or modify
9it under the terms of the GNU Lesser General Public License as published by
10the Free Software Foundation; either version 3 of the License, or (at your
11option) any later version.
12
13The GNU MPFR Library is distributed in the hope that it will be useful, but
14WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
16License for more details.
17
18You should have received a copy of the GNU Lesser General Public License
19along with the GNU MPFR Library; see the file COPYING.LESSER.  If not, see
20http://www.gnu.org/licenses/ or write to the Free Software Foundation, Inc.,
2151 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. */
22
23#include <stdio.h>
24#include <stdlib.h>
25#include <limits.h>
26
27#include "mpfr-test.h"
28
29/* Test that there is no lost of accuracy when converting a mpfr_t number
30   into a mpf_t number (test with various precisions and exponents). */
31static void
32prec_test (void)
33{
34  int px, py;
35
36  for (py = 3; py <= 136; py++)
37    {
38      mpfr_t y1, y2, y3;
39
40      mpfr_init2 (y1, py);
41      mpfr_init2 (y2, py);
42      mpfr_init2 (y3, py);
43
44      for (px = 32; px <= 160; px += 32)
45        {
46          mpf_t x1, x2, x3;
47          int e;
48
49          mpf_init (x1);
50          mpf_init (x2);
51          mpf_init (x3);
52          mpfr_set_ui_2exp (y1, 1, py - 1, MPFR_RNDN);
53          mpfr_get_f (x1, y1, MPFR_RNDN);  /* exact (power of 2) */
54          mpf_set (x2, x1);
55          mpfr_set (y2, y1, MPFR_RNDN);
56
57          for (e = py - 2; e >= 0; e--)
58            {
59              int inex;
60              mpf_div_2exp (x2, x2, 1);
61              mpf_add (x1, x1, x2);
62              mpfr_div_2exp (y2, y2, 1, MPFR_RNDN);
63              inex = mpfr_add (y1, y1, y2, MPFR_RNDN);
64              MPFR_ASSERTN (inex == 0);
65              mpfr_set_f (y3, x1, MPFR_RNDN);
66              if (! mpfr_equal_p (y1, y3))
67                break;
68              inex = mpfr_get_f (x3, y3, MPFR_RNDN);
69              if (mpf_cmp (x1, x3) != 0)
70                {
71                  printf ("Error in prec_test (px = %d, py = %d, e = %d)\n",
72                          px, py, e);
73                  printf ("x1 = ");
74                  mpf_out_str (stdout, 16, 0, x1);
75                  printf ("\nx2 = ");
76                  mpf_out_str (stdout, 16, 0, x2);
77                  printf ("\n");
78                  exit (1);
79                }
80              if (inex != 0)
81                {
82                  printf ("Error in prec_test (px = %d, py = %d, e = %d)\n",
83                          px, py, e);
84                  printf ("wrong ternary value got: %+d, expected: 0\n",
85                          inex);
86                  exit (1);
87                }
88            }
89
90          mpf_clear (x1);
91          mpf_clear (x2);
92          mpf_clear (x3);
93        }
94
95      mpfr_clear (y1);
96      mpfr_clear (y2);
97      mpfr_clear (y3);
98    }
99}
100
101static void
102special_test (void)
103{
104  int inex;
105  mpf_t x;
106  mpfr_t y;
107
108  mpfr_init (y);
109  mpf_init (x);
110
111  mpfr_set_nan (y);
112  mpfr_clear_flags ();
113  mpfr_get_f (x, y, MPFR_RNDN);
114  if (! mpfr_erangeflag_p ())
115    {
116      printf ("Error: mpfr_get_f(NaN) should raise erange flag\n");
117      exit (1);
118    }
119
120  mpfr_set_inf (y, +1);
121  mpfr_clear_flags ();
122  inex = mpfr_get_f (x, y, MPFR_RNDN);
123  if (inex >= 0)
124    {
125      printf ("Error: mpfr_get_f(+Inf) should return a negative ternary"
126              "value\n");
127      exit (1);
128    }
129  if (! mpfr_erangeflag_p ())
130    {
131      printf ("Error: mpfr_get_f(+Inf) should raise erange flag\n");
132      exit (1);
133    }
134
135  mpfr_set_inf (y, -1);
136  mpfr_clear_flags ();
137  inex = mpfr_get_f (x, y, MPFR_RNDN);
138  if (inex <= 0)
139    {
140      printf ("Error: mpfr_get_f(-Inf) should return a positive ternary"
141              "value\n");
142      exit (1);
143    }
144  if (! mpfr_erangeflag_p ())
145    {
146      printf ("Error: mpfr_get_f(-Inf) should raise erange flag\n");
147      exit (1);
148    }
149
150  mpfr_set_ui (y, 0, MPFR_RNDN);
151  if (mpfr_get_f (x, y, MPFR_RNDN) != 0 || mpf_cmp_ui (x, 0))
152    {
153      printf ("Error: mpfr_get_f(+0) fails\n");
154      exit (1);
155    }
156
157  mpfr_set_ui (y, 0, MPFR_RNDN);
158  mpfr_neg (y, y, MPFR_RNDN);
159  if (mpfr_get_f (x, y, MPFR_RNDN) != 0 || mpf_cmp_ui (x, 0))
160    {
161      printf ("Error: mpfr_get_f(-0) fails\n");
162      exit (1);
163    }
164
165  mpfr_clear (y);
166  mpf_clear (x);
167}
168
169static void
170ternary_test (void)
171{
172  int prec;
173  int rnd;
174  int inex, expected_inex;
175  mpf_t x;
176  mpfr_t y;
177
178  mpf_init2 (x, 256);
179  mpfr_init2 (y, 256);
180
181  for (prec = 2; prec <= 256; prec++)
182    {
183
184      mpf_set_prec (x, prec);
185      mpfr_set_prec (y, PREC (x) * GMP_NUMB_BITS + 1);
186
187      /* y == 1 */
188      mpfr_set_ui_2exp (y, 1, prec, MPFR_RNDN);
189
190      RND_LOOP (rnd)
191      {
192        inex = mpfr_get_f (x, y, (mpfr_rnd_t) rnd);
193
194        if (inex != 0 || mpfr_cmp_f (y, x) !=0)
195          {
196            printf ("Error in mpfr_get_f (x, y, %s)\nx = ",
197                    mpfr_print_rnd_mode ((mpfr_rnd_t) rnd));
198            mpf_out_str (stdout, 2, 0, x);
199            printf ("\ny = ");
200            mpfr_dump (y);
201            if (inex != 0)
202              printf ("got ternary value = %+d, expected: 0\n", inex);
203
204            exit (1);
205          }
206      }
207
208      /* y == 1 + epsilon */
209      mpfr_nextbelow (y);
210
211      RND_LOOP (rnd)
212      {
213        switch (rnd)
214          {
215          case MPFR_RNDU: case MPFR_RNDA:
216          case MPFR_RNDN:
217            expected_inex = +1;
218            break;
219          default :
220            expected_inex = -1;
221          }
222
223        inex = mpfr_get_f (x, y, (mpfr_rnd_t) rnd);
224
225        if (! SAME_SIGN (expected_inex, inex)
226            || SAME_SIGN (expected_inex, mpfr_cmp_f (y, x)))
227          {
228            printf ("Error in mpfr_get_f (x, y, %s)\nx = ",
229                    mpfr_print_rnd_mode ((mpfr_rnd_t) rnd));
230            mpf_out_str (stdout, 2, 0, x);
231            printf ("\ny = ");
232            mpfr_dump (y);
233            if (! SAME_SIGN (expected_inex, inex))
234              printf ("got ternary value = %+d, expected: %+d\n",
235                      inex, expected_inex);
236
237            exit (1);
238          }
239      }
240
241      /* y == positive random float */
242      mpfr_random2 (y, MPFR_LIMB_SIZE (y), 1024, RANDS);
243
244      RND_LOOP (rnd)
245      {
246        inex = mpfr_get_f (x, y, (mpfr_rnd_t) rnd);
247
248        if (! SAME_SIGN (inex, -mpfr_cmp_f (y, x)))
249          {
250            printf ("Error in mpfr_get_f (x, y, %s)\nx = ",
251                    mpfr_print_rnd_mode ((mpfr_rnd_t) rnd));
252            mpf_out_str (stdout, 2, 0, x);
253            printf ("\ny = ");
254            mpfr_dump (y);
255            printf ("got ternary value = %+d, expected: %+d\n",
256                    inex, -mpfr_cmp_f (y, x));
257
258            exit (1);
259          }
260      }
261    }
262
263  mpf_clear (x);
264  mpfr_clear (y);
265}
266
267int
268main (void)
269{
270  mpf_t x;
271  mpfr_t y, z;
272  unsigned long i;
273  mpfr_exp_t e;
274  int inex;
275
276  tests_start_mpfr ();
277
278  mpfr_init (y);
279  mpfr_init (z);
280  mpf_init (x);
281
282  i = 1;
283  while (i)
284    {
285      mpfr_set_ui (y, i, MPFR_RNDN);
286      if (mpfr_get_f (x, y, MPFR_RNDN) != 0 || mpf_cmp_ui (x, i))
287        {
288          printf ("Error: mpfr_get_f(%lu) fails\n", i);
289          exit (1);
290        }
291      if (i <= - (unsigned long) LONG_MIN)
292        {
293          long j = i < - (unsigned long) LONG_MIN ? - (long) i : LONG_MIN;
294          mpfr_set_si (y, j, MPFR_RNDN);
295          if (mpfr_get_f (x, y, MPFR_RNDN) != 0 || mpf_cmp_si (x, j))
296            {
297              printf ("Error: mpfr_get_f(-%lu) fails\n", i);
298              exit (1);
299            }
300        }
301      i *= 2;
302    }
303
304  /* same tests, but with a larger precision for y, which requires to
305     round it */
306  mpfr_set_prec (y, 100);
307  i = 1;
308  while (i)
309    {
310      mpfr_set_ui (y, i, MPFR_RNDN);
311      inex = mpfr_get_f (x, y, MPFR_RNDN);
312      if (! SAME_SIGN (inex, - mpfr_cmp_f (y, x)) || mpf_cmp_ui (x, i))
313        {
314          printf ("Error: mpfr_get_f(%lu) fails\n", i);
315          exit (1);
316        }
317      mpfr_set_si (y, (signed long) -i, MPFR_RNDN);
318      inex = mpfr_get_f (x, y, MPFR_RNDN);
319      if (! SAME_SIGN (inex, - mpfr_cmp_f (y, x))
320          || mpf_cmp_si (x, (signed long) -i))
321        {
322          printf ("Error: mpfr_get_f(-%lu) fails\n", i);
323          exit (1);
324        }
325      i *= 2;
326    }
327
328  /* bug reported by Jim White */
329  for (e = 0; e <= 2 * GMP_NUMB_BITS; e++)
330    {
331      /* test with 2^(-e) */
332      mpfr_set_ui (y, 1, MPFR_RNDN);
333      mpfr_div_2exp (y, y, e, MPFR_RNDN);
334      inex = mpfr_get_f (x, y, MPFR_RNDN);
335      mpf_mul_2exp (x, x, e);
336      if (inex != 0 || mpf_cmp_ui (x, 1) != 0)
337        {
338          printf ("Error: mpfr_get_f(x,y,MPFR_RNDN) fails\n");
339          printf ("y=");
340          mpfr_dump (y);
341          printf ("x=");
342          mpf_div_2exp (x, x, e);
343          mpf_out_str (stdout, 2, 0, x);
344          exit (1);
345        }
346
347      /* test with 2^(e) */
348      mpfr_set_ui (y, 1, MPFR_RNDN);
349      mpfr_mul_2exp (y, y, e, MPFR_RNDN);
350      inex = mpfr_get_f (x, y, MPFR_RNDN);
351      mpf_div_2exp (x, x, e);
352      if (inex != 0 || mpf_cmp_ui (x, 1) != 0)
353        {
354          printf ("Error: mpfr_get_f(x,y,MPFR_RNDN) fails\n");
355          printf ("y=");
356          mpfr_dump (y);
357          printf ("x=");
358          mpf_mul_2exp (x, x, e);
359          mpf_out_str (stdout, 2, 0, x);
360          exit (1);
361        }
362    }
363
364  /* Bug reported by Yury Lukach on 2006-04-05 */
365  mpfr_set_prec (y, 32);
366  mpfr_set_prec (z, 32);
367  mpf_set_prec (x, 32);
368  mpfr_set_ui_2exp (y, 0xc1234567, -30, MPFR_RNDN);
369  mpfr_get_f (x, y, MPFR_RNDN);
370  inex = mpfr_set_f (z, x, MPFR_RNDN);
371  if (inex != 0 || ! mpfr_equal_p (y, z))
372    {
373      printf ("Error in mpfr_get_f:\n  inex = %d, y = ", inex);
374      mpfr_dump (z);
375      printf ("Expected:\n  inex = 0, y = ");
376      mpfr_dump (y);
377      exit (1);
378    }
379
380  mpfr_clear (y);
381  mpfr_clear (z);
382  mpf_clear (x);
383
384  special_test ();
385  prec_test ();
386  ternary_test ();
387
388  tests_end_mpfr ();
389  return 0;
390}
391