1/* Test file for mpfr_get_d
2
3Copyright 1999, 2000, 2001, 2002, 2003, 2004, 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 <float.h>
26
27#include "mpfr-test.h"
28
29static int
30check_denorms (void)
31{
32  mpfr_rnd_t rnd_mode;
33  mpfr_t x;
34  double d, d2, dd, f;
35  int fail = 0, k, n;
36
37  mpfr_init2 (x, GMP_NUMB_BITS);
38
39  rnd_mode = MPFR_RNDN;
40  for (k = -17; k <= 17; k += 2)
41    {
42      d = (double) k * DBL_MIN; /* k * 2^(-1022) */
43      f = 1.0;
44      mpfr_set_si (x, k, MPFR_RNDN);
45      mpfr_div_2exp (x, x, 1022, MPFR_RNDN); /* k * 2^(-1022) */
46      for (n = 0; n <= 58; n++)
47        {
48          d2 = d * f;
49          dd = mpfr_get_d (x, rnd_mode);
50          if (d2 != dd) /* should be k * 2^(-1022-n) for n < 53 */
51            {
52              printf ("Wrong result for %d * 2^(%d), rnd_mode %d\n",
53                      k, -1022-n, rnd_mode);
54              printf ("got %.20e instead of %.20e\n", dd, d2);
55              fail = 1;
56            }
57          f *= 0.5;
58          mpfr_div_2exp (x, x, 1, MPFR_RNDN);
59        }
60    }
61
62  mpfr_set_str_binary (x, "1e-1074");
63  dd = mpfr_get_d (x, MPFR_RNDA);
64  d2 = DBL_MIN; /* 2^(-1022) */
65  for (k = 0; k < 52; k++)
66    d2 *= 0.5;  /* 2^(-1074) */
67  /* we first check that d2 is not zero (it could happen on a platform with
68     no subnormals) */
69  if (d2 != 0.0 && dd != d2)
70    {
71      printf ("Error for x=1e-1074, RNDA\n");
72      exit (1);
73    }
74
75  mpfr_set_str_binary (x, "1e-1075");
76  dd = mpfr_get_d (x, MPFR_RNDA);
77  if (d2 != 0.0 && dd != d2)
78    {
79      printf ("Error for x=1e-1075, RNDA\n");
80      printf ("expected %.16e\n", d2);
81      printf ("got      %.16e\n", dd);
82      exit (1);
83    }
84
85  mpfr_clear (x);
86  return fail;
87}
88
89static void
90check_inf_nan (void)
91{
92  /* only if nans and infs are available */
93#if _GMP_IEEE_FLOATS
94  mpfr_t  x;
95  double  d;
96
97  mpfr_init2 (x, 123);
98
99  mpfr_set_inf (x, 1);
100  d = mpfr_get_d (x, MPFR_RNDZ);
101  ASSERT_ALWAYS (d > 0);
102  ASSERT_ALWAYS (DOUBLE_ISINF (d));
103
104  mpfr_set_inf (x, -1);
105  d = mpfr_get_d (x, MPFR_RNDZ);
106  ASSERT_ALWAYS (d < 0);
107  ASSERT_ALWAYS (DOUBLE_ISINF (d));
108
109  mpfr_set_nan (x);
110  d = mpfr_get_d (x, MPFR_RNDZ);
111  ASSERT_ALWAYS (DOUBLE_ISNAN (d));
112
113  mpfr_clear (x);
114#endif
115}
116
117static void
118check_max (void)
119{
120  double d, e;
121  mpfr_t u;
122
123  d = 1.0;
124  while (d < (DBL_MAX / 2.0))
125    d += d;
126  mpfr_init (u);
127  if (mpfr_set_d (u, d, MPFR_RNDN) == 0)
128    {
129      /* If setting is exact */
130      e = (mpfr_get_d1) (u);
131      if (e != d)
132        {
133          printf ("get_d(set_d)(1): %1.20e != %1.20e\n", d, e);
134          exit (1);
135        }
136    }
137
138  mpfr_set_str_binary (u, "-1E1024");
139  d = mpfr_get_d (u, MPFR_RNDZ);
140  MPFR_ASSERTN(d == -DBL_MAX);
141  d = mpfr_get_d (u, MPFR_RNDU);
142  MPFR_ASSERTN(d == -DBL_MAX);
143  d = mpfr_get_d (u, MPFR_RNDN);
144  MPFR_ASSERTN(DOUBLE_ISINF(d) && d < 0.0);
145  d = mpfr_get_d (u, MPFR_RNDD);
146  MPFR_ASSERTN(DOUBLE_ISINF(d) && d < 0.0);
147
148  mpfr_set_str_binary (u, "1E1024");
149  d = mpfr_get_d (u, MPFR_RNDZ);
150  MPFR_ASSERTN(d == DBL_MAX);
151  d = mpfr_get_d (u, MPFR_RNDD);
152  MPFR_ASSERTN(d == DBL_MAX);
153  d = mpfr_get_d (u, MPFR_RNDN);
154  MPFR_ASSERTN(DOUBLE_ISINF(d) && d > 0.0);
155  d = mpfr_get_d (u, MPFR_RNDU);
156  MPFR_ASSERTN(DOUBLE_ISINF(d) && d > 0.0);
157
158  mpfr_clear (u);
159}
160
161static void
162check_min(void)
163{
164  double d, e;
165  mpfr_t u;
166
167  d = 1.0; while (d > (DBL_MIN * 2.0)) d /= 2.0;
168  mpfr_init(u);
169  if (mpfr_set_d(u, d, MPFR_RNDN) == 0)
170    {
171      /* If setting is exact */
172      e = mpfr_get_d1(u);
173      if (e != d)
174        {
175          printf("get_d(set_d)(2): %1.20e != %1.20e\n", d, e);
176          exit(1);
177        }
178    }
179  mpfr_clear(u);
180}
181
182int
183main (void)
184{
185  tests_start_mpfr ();
186  mpfr_test_init ();
187
188#ifndef MPFR_DOUBLE_SPEC
189  printf ("Warning! The MPFR_DOUBLE_SPEC macro is not defined. This means\n"
190          "that you do not have a conforming C implementation and problems\n"
191          "may occur with conversions between MPFR numbers and standard\n"
192          "floating-point types. Please contact the MPFR team.\n");
193#elif MPFR_DOUBLE_SPEC == 0
194  /*
195  printf ("The type 'double' of your C implementation does not seem to\n"
196          "correspond to the IEEE-754 double precision. Though code has\n"
197          "been written to support such implementations, tests have been\n"
198          "done only on IEEE-754 double-precision implementations and\n"
199          "conversions between MPFR numbers and standard floating-point\n"
200          "types may be inaccurate. You may wish to contact the MPFR team\n"
201          "for further testing.\n");
202  */
203  printf ("The type 'double' of your C implementation does not seem to\n"
204          "correspond to the IEEE-754 double precision. Such particular\n"
205          "implementations are not supported yet, and conversions between\n"
206          "MPFR numbers and standard floating-point types may be very\n"
207          "inaccurate.\n");
208  printf ("FLT_RADIX    = %ld\n", (long) FLT_RADIX);
209  printf ("DBL_MANT_DIG = %ld\n", (long) DBL_MANT_DIG);
210  printf ("DBL_MIN_EXP  = %ld\n", (long) DBL_MIN_EXP);
211  printf ("DBL_MAX_EXP  = %ld\n", (long) DBL_MAX_EXP);
212#endif
213
214  if (check_denorms ())
215    exit (1);
216
217  check_inf_nan ();
218  check_min();
219  check_max();
220
221  tests_end_mpfr ();
222  return 0;
223}
224