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