1/* Test mpfr_get_ld_2exp.
2
3Copyright 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc.
4Contributed by the AriC and Caramel 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 <float.h>
26
27#include "mpfr-test.h"
28
29/* Check that hardware rounding doesn't make mpfr_get_ld_2exp return a value
30   outside its defined range. */
31static void
32check_round (void)
33{
34  static const unsigned long data[] = {1, 32, 53, 54, 63, 64, 65, 127, 128, 256, 512 };
35  mpfr_t  f;
36  long double  got;
37  long    got_exp;
38  int     i, rnd_mode, neg;
39
40  mpfr_init2 (f, 1024L);
41
42  for (rnd_mode = 0; rnd_mode < MPFR_RND_MAX ; rnd_mode++)
43    {
44      for (i = 0; i < (int) numberof (data); i++)
45        {
46          mpfr_set_ui (f, 1L, MPFR_RNDZ);
47          mpfr_mul_2exp (f, f, data[i], MPFR_RNDZ);
48          mpfr_sub_ui (f, f, 1L, MPFR_RNDZ);
49
50          for (neg = 0; neg <= 1; neg++)
51            {
52              got = mpfr_get_ld_2exp (&got_exp, f, (mpfr_rnd_t) rnd_mode);
53
54              if (neg == 0
55                  ? (got < 0.5 || got >= 1.0)
56                  : (got <= -1.0 || got > -0.5))
57                {
58                  printf  ("mpfr_get_ld_2exp wrong on 2**%lu-1\n", data[i]);
59                  printf  ("result out of range, expect 0.5 <= got < 1.0\n");
60                  printf  ("   rnd_mode = %d\n", rnd_mode);
61                  printf  ("   data[i]  = %lu\n", data[i]);
62                  printf  ("   f    ");
63                  mpfr_out_str (stdout, 2, 0, f, MPFR_RNDN);
64                  printf  ("\n");
65                  d_trace ("   got  ", got);
66                  printf  ("   got exp  %ld\n", got_exp);
67                  exit(1);
68                }
69
70              mpfr_neg (f, f, MPFR_RNDZ);
71            }
72        }
73    }
74
75  mpfr_clear (f);
76}
77
78
79static void
80check_inf_nan (void)
81{
82  /* only if nans and infs are available */
83#if _GMP_IEEE_FLOATS
84  mpfr_t  x;
85  double  d;
86  long    exp;
87
88  mpfr_init2 (x, 123);
89
90  mpfr_set_inf (x, 1);
91  d = (double) mpfr_get_ld_2exp (&exp, x, MPFR_RNDZ);
92  ASSERT_ALWAYS (d > 0);
93  ASSERT_ALWAYS (DOUBLE_ISINF (d));
94
95  mpfr_set_inf (x, -1);
96  d = (double) mpfr_get_ld_2exp (&exp, x, MPFR_RNDZ);
97  ASSERT_ALWAYS (d < 0);
98  ASSERT_ALWAYS (DOUBLE_ISINF (d));
99
100  mpfr_set_nan (x);
101  d = (double) mpfr_get_ld_2exp (&exp, x, MPFR_RNDZ);
102  ASSERT_ALWAYS (DOUBLE_ISNAN (d));
103
104  mpfr_clear (x);
105#endif
106}
107
108static void
109bug20090520 (void)
110{
111  mpfr_t x;
112  long double d, e;
113  int i;
114
115  mpfr_init (x);
116  mpfr_set_ui (x, 1, MPFR_RNDN);
117  d = 1.0;
118  mpfr_div_2exp (x, x, 16383, MPFR_RNDN);
119  for (i = 0; i < 16383; i++)
120    d *= 0.5;
121  e = mpfr_get_ld (x, MPFR_RNDN);
122  if (e != d)
123    {
124      printf ("mpfr_get_ld(1e-16383) failed\n");
125      printf ("expected %.20Le\n", d);
126      printf ("got      %.20Le\n", e);
127      exit (1);
128    }
129  mpfr_clear (x);
130}
131
132int
133main (void)
134{
135  tests_start_mpfr ();
136  mpfr_test_init ();
137
138  bug20090520 ();
139
140  check_round ();
141  check_inf_nan ();
142
143  tests_end_mpfr ();
144  return 0;
145}
146