xref: /netbsd-src/external/lgpl3/mpfr/dist/tests/tget_d.c (revision ba125506a622fe649968631a56eba5d42ff57863)
1 /* Test file for mpfr_get_d
2 
3 Copyright 1999-2023 Free Software Foundation, Inc.
4 Contributed by the AriC and Caramba projects, INRIA.
5 
6 This file is part of the GNU MPFR Library.
7 
8 The GNU MPFR Library is free software; you can redistribute it and/or modify
9 it under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or (at your
11 option) any later version.
12 
13 The GNU MPFR Library is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
16 License for more details.
17 
18 You should have received a copy of the GNU Lesser General Public License
19 along with the GNU MPFR Library; see the file COPYING.LESSER.  If not, see
20 https://www.gnu.org/licenses/ or write to the Free Software Foundation, Inc.,
21 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. */
22 
23 #include <float.h>
24 
25 #include "mpfr-test.h"
26 #include "ieee_floats.h"
27 
28 static int
check_subnorm(void)29 check_subnorm (void)
30 {
31   mpfr_rnd_t rnd_mode;
32   mpfr_t x;
33   double d, d2, dd, f;
34   int fail = 0, k, n;
35 
36   mpfr_init2 (x, GMP_NUMB_BITS);
37 
38   rnd_mode = MPFR_RNDN;
39   for (k = -17; k <= 17; k += 2)
40     {
41       d = (double) k * DBL_MIN; /* k * 2^(-1022) */
42       f = 1.0;
43       mpfr_set_si (x, k, MPFR_RNDN);
44       mpfr_div_2ui (x, x, 1022, MPFR_RNDN); /* k * 2^(-1022) */
45       for (n = 0; n <= 58; n++)
46         {
47           d2 = d * f;
48           dd = mpfr_get_d (x, rnd_mode);
49           if (d2 != dd) /* should be k * 2^(-1022-n) for n < 53 */
50             {
51               printf ("Wrong result for %d * 2^(%d), rnd_mode %d\n",
52                       k, -1022-n, rnd_mode);
53               printf ("got %.20e instead of %.20e\n", dd, d2);
54               fail = 1;
55             }
56           f *= 0.5;
57           mpfr_div_2ui (x, x, 1, MPFR_RNDN);
58         }
59     }
60 
61   mpfr_set_str_binary (x, "1e-1074");
62   dd = mpfr_get_d (x, MPFR_RNDA);
63   d2 = DBL_MIN; /* 2^(-1022) */
64   for (k = 0; k < 52; k++)
65     d2 *= 0.5;  /* 2^(-1074) */
66   /* we first check that d2 is not zero (it could happen on a platform with
67      no subnormals) */
68   if (d2 != 0.0 && dd != d2)
69     {
70       printf ("Error for x=1e-1074, RNDA\n");
71       exit (1);
72     }
73 
74   mpfr_set_str_binary (x, "1e-1075");
75   dd = mpfr_get_d (x, MPFR_RNDA);
76   if (d2 != 0.0 && dd != d2)
77     {
78       printf ("Error for x=1e-1075, RNDA\n");
79       printf ("expected %.16e\n", d2);
80       printf ("got      %.16e\n", dd);
81       exit (1);
82     }
83 
84   mpfr_clear (x);
85   return fail;
86 }
87 
88 static void
check_inf_nan(void)89 check_inf_nan (void)
90 {
91   /* only if nans and infs are available */
92 #if !defined(MPFR_ERRDIVZERO)
93   mpfr_t  x;
94   double  d;
95 
96   mpfr_init2 (x, 123);
97 
98   mpfr_set_inf (x, 1);
99   d = mpfr_get_d (x, MPFR_RNDZ);
100   MPFR_ASSERTN (d > 0);
101   MPFR_ASSERTN (DOUBLE_ISINF (d));
102 
103   mpfr_set_inf (x, -1);
104   d = mpfr_get_d (x, MPFR_RNDZ);
105   MPFR_ASSERTN (d < 0);
106   MPFR_ASSERTN (DOUBLE_ISINF (d));
107 
108   mpfr_set_nan (x);
109   d = mpfr_get_d (x, MPFR_RNDZ);
110   if (!DOUBLE_ISNAN (d))
111     {
112       printf ("Error in check_inf_nan() for NaN, got %.17g\n", d);
113       printf ("MPFR_DBL_NAN is %.17g (should be NaN)\n", MPFR_DBL_NAN);
114       exit (1);
115     }
116 
117   mpfr_clear (x);
118 #endif
119 }
120 
121 static void
check_max(void)122 check_max (void)
123 {
124   double d, e;
125   mpfr_t u;
126 
127   d = 1.0;
128   while (d < (DBL_MAX / 2.0))
129     d += d;
130   mpfr_init (u);
131   if (mpfr_set_d (u, d, MPFR_RNDN) == 0)
132     {
133       /* If setting is exact */
134       e = (mpfr_get_d1) (u);
135       if (e != d)
136         {
137           printf ("get_d(set_d)(1): %1.20e != %1.20e\n", d, e);
138           exit (1);
139         }
140     }
141 
142   mpfr_set_str_binary (u, "-1E1024");
143   d = mpfr_get_d (u, MPFR_RNDZ);
144   MPFR_ASSERTN(d == -DBL_MAX);
145   d = mpfr_get_d (u, MPFR_RNDU);
146   MPFR_ASSERTN(d == -DBL_MAX);
147 #if !defined(MPFR_ERRDIVZERO)
148   d = mpfr_get_d (u, MPFR_RNDN);
149   MPFR_ASSERTN(DOUBLE_ISINF(d) && d < 0.0);
150   d = mpfr_get_d (u, MPFR_RNDD);
151   MPFR_ASSERTN(DOUBLE_ISINF(d) && d < 0.0);
152 #endif
153 
154   mpfr_set_str_binary (u, "1E1024");
155   d = mpfr_get_d (u, MPFR_RNDZ);
156   MPFR_ASSERTN(d == DBL_MAX);
157   d = mpfr_get_d (u, MPFR_RNDD);
158   MPFR_ASSERTN(d == DBL_MAX);
159 #if !defined(MPFR_ERRDIVZERO)
160   d = mpfr_get_d (u, MPFR_RNDN);
161   MPFR_ASSERTN(DOUBLE_ISINF(d) && d > 0.0);
162   d = mpfr_get_d (u, MPFR_RNDU);
163   MPFR_ASSERTN(DOUBLE_ISINF(d) && d > 0.0);
164 #endif
165 
166   mpfr_clear (u);
167 }
168 
169 static void
check_min(void)170 check_min(void)
171 {
172   double d, e;
173   mpfr_t u;
174 
175   d = 1.0; while (d > (DBL_MIN * 2.0)) d /= 2.0;
176   mpfr_init(u);
177   if (mpfr_set_d(u, d, MPFR_RNDN) == 0)
178     {
179       /* If setting is exact */
180       e = mpfr_get_d1(u);
181       if (e != d)
182         {
183           printf("get_d(set_d)(2): %1.20e != %1.20e\n", d, e);
184           exit(1);
185         }
186     }
187   mpfr_clear(u);
188 }
189 
190 static void
check_get_d_2exp_inf_nan(void)191 check_get_d_2exp_inf_nan (void)
192 {
193 #if !defined(MPFR_ERRDIVZERO)
194 
195   double var_d;
196   long exp;
197   mpfr_t var;
198 
199   mpfr_init2 (var, MPFR_PREC_MIN);
200 
201   mpfr_set_nan (var);
202   var_d = mpfr_get_d_2exp (&exp, var, MPFR_RNDN);
203   if (!DOUBLE_ISNAN (var_d))
204     {
205       printf ("mpfr_get_d_2exp on NaN returned a wrong value: %.17g\n",
206               var_d);
207       printf ("MPFR_DBL_NAN is %.17g (should be NaN)\n", MPFR_DBL_NAN);
208       exit (1);
209     }
210 
211   mpfr_set_zero (var, 1);
212   var_d = mpfr_get_d_2exp (&exp, var, MPFR_RNDN);
213   if (exp != 0 || var_d != 0.0)
214     {
215       printf ("mpfr_get_d_2exp on +0.0 returned a wrong value:\n"
216               " expected 0.0, got %.17g\n"
217               " exp: expected 0, got %ld\n",
218               var_d, exp);
219       exit (1);
220     }
221 
222   mpfr_set_zero (var, -1);
223   var_d = mpfr_get_d_2exp (&exp, var, MPFR_RNDN);
224   /* Note: the sign of the negative zero (when supported) is not checked. */
225   if (exp != 0 || var_d != DBL_NEG_ZERO)
226     {
227       printf ("mpfr_get_d_2exp on -0.0 returned a wrong value:\n"
228               " expected %.17g, got %.17g\n"
229               " exp: expected 0, got %ld\n",
230               DBL_NEG_ZERO, var_d, exp);
231       exit (1);
232     }
233 
234   mpfr_set_inf (var, 1);
235   var_d = mpfr_get_d_2exp (&exp, var, MPFR_RNDN);
236   if (var_d != MPFR_DBL_INFP)
237     {
238       printf ("mpfr_get_d_2exp on +Inf returned a wrong value:\n"
239               " expected %g, got %g\n", MPFR_DBL_INFP, var_d);
240       exit (1);
241     }
242 
243   mpfr_set_inf (var, -1);
244   var_d = mpfr_get_d_2exp (&exp, var, MPFR_RNDN);
245   if (var_d != MPFR_DBL_INFM)
246     {
247       printf ("mpfr_get_d_2exp on -Inf returned a wrong value:\n"
248               " expected %g, got %g\n", MPFR_DBL_INFM, var_d);
249       exit (1);
250     }
251 
252   mpfr_clear (var);
253 
254 #endif
255 }
256 
257 int
main(void)258 main (void)
259 {
260   tests_start_mpfr ();
261   mpfr_test_init ();
262 
263 #ifndef MPFR_DOUBLE_SPEC
264   printf ("Warning! The MPFR_DOUBLE_SPEC macro is not defined. This means\n"
265           "that you do not have a conforming C implementation and problems\n"
266           "may occur with conversions between MPFR numbers and standard\n"
267           "floating-point types. Please contact the MPFR team.\n");
268 #elif MPFR_DOUBLE_SPEC == 0
269   /*
270   printf ("The type 'double' of your C implementation does not seem to\n"
271           "correspond to the IEEE-754 double precision. Though code has\n"
272           "been written to support such implementations, tests have been\n"
273           "done only on IEEE-754 double-precision implementations and\n"
274           "conversions between MPFR numbers and standard floating-point\n"
275           "types may be inaccurate. You may wish to contact the MPFR team\n"
276           "for further testing.\n");
277   */
278   printf ("The type 'double' of your C implementation does not seem to\n"
279           "correspond to the IEEE-754 double precision. Such particular\n"
280           "implementations are not supported yet, and conversions between\n"
281           "MPFR numbers and standard floating-point types may be very\n"
282           "inaccurate.\n");
283   printf ("FLT_RADIX    = %ld\n", (long) FLT_RADIX);
284   printf ("DBL_MANT_DIG = %ld\n", (long) DBL_MANT_DIG);
285   printf ("DBL_MIN_EXP  = %ld\n", (long) DBL_MIN_EXP);
286   printf ("DBL_MAX_EXP  = %ld\n", (long) DBL_MAX_EXP);
287 #endif
288 
289   if (check_subnorm ())
290     exit (1);
291 
292   check_inf_nan ();
293   check_min();
294   check_max();
295 
296   check_get_d_2exp_inf_nan ();
297 
298   tests_end_mpfr ();
299   return 0;
300 }
301 
302