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