1 /* Test mpz_get_d_2exp.
2 
3 Copyright 2002, 2003, 2012 Free Software Foundation, Inc.
4 
5 This file is part of the GNU MP Library test suite.
6 
7 The GNU MP Library test suite is free software; you can redistribute it
8 and/or modify it under the terms of the GNU General Public License as
9 published by the Free Software Foundation; either version 3 of the License,
10 or (at your option) any later version.
11 
12 The GNU MP Library test suite is distributed in the hope that it will be
13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
15 Public License for more details.
16 
17 You should have received a copy of the GNU General Public License along with
18 the GNU MP Library test suite.  If not, see http://www.gnu.org/licenses/.  */
19 
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include "gmp.h"
23 #include "gmp-impl.h"
24 #include "tests.h"
25 
26 
27 static void
28 check_zero (void)
29 {
30   mpz_t   z;
31   double  got, want;
32   long    got_exp, want_exp;
33 
34   mpz_init_set_ui (z, 0);
35 
36   want = 0.0;
37   want_exp = 0;
38   got = mpz_get_d_2exp (&got_exp, z);
39   if (got != want || got_exp != want_exp)
40     {
41       printf    ("mpz_get_d_2exp wrong on zero\n");
42       mpz_trace ("   z    ", z);
43       d_trace   ("   want ", want);
44       d_trace   ("   got  ", got);
45       printf    ("   want exp %ld\n", want_exp);
46       printf    ("   got exp  %ld\n", got_exp);
47       abort();
48     }
49 
50   mpz_clear (z);
51 }
52 
53 static void
54 check_onebit (void)
55 {
56   static const unsigned long data[] = {
57     1, 32, 52, 53, 54, 63, 64, 65, 128, 256, 511, 512, 513
58   };
59   mpz_t   z;
60   double  got, want;
61   long    got_exp, want_exp;
62   int     i;
63 
64   mpz_init (z);
65 
66   for (i = 0; i < numberof (data); i++)
67     {
68       mpz_set_ui (z, 1L);
69       mpz_mul_2exp (z, z, data[i]);
70       want = 0.5;
71       want_exp = data[i] + 1;
72       got = mpz_get_d_2exp (&got_exp, z);
73       if (got != want || got_exp != want_exp)
74         {
75           printf    ("mpz_get_d_2exp wrong on 2**%ld\n", data[i]);
76           mpz_trace ("   z    ", z);
77           d_trace   ("   want ", want);
78           d_trace   ("   got  ", got);
79           printf    ("   want exp %ld\n", want_exp);
80           printf    ("   got exp  %ld\n", got_exp);
81           abort();
82         }
83 
84       mpz_set_si (z, -1L);
85       mpz_mul_2exp (z, z, data[i]);
86       want = -0.5;
87       want_exp = data[i] + 1;
88       got = mpz_get_d_2exp (&got_exp, z);
89       if (got != want || got_exp != want_exp)
90         {
91           printf    ("mpz_get_d_2exp wrong on -2**%ld\n", data[i]);
92           mpz_trace ("   z    ", z);
93           d_trace   ("   want ", want);
94           d_trace   ("   got  ", got);
95           printf    ("   want exp %ld\n", want_exp);
96           printf    ("   got exp  %ld\n", got_exp);
97           abort();
98         }
99     }
100   mpz_clear (z);
101 }
102 
103 /* Check that hardware rounding doesn't make mpz_get_d_2exp return a value
104    outside its defined range. */
105 static void
106 check_round (void)
107 {
108   static const unsigned long data[] = { 1, 32, 53, 54, 64, 128, 256, 512 };
109   mpz_t   z;
110   double  got;
111   long    got_exp;
112   int     i, rnd_mode, old_rnd_mode;
113 
114   mpz_init (z);
115   old_rnd_mode = tests_hardware_getround ();
116 
117   for (rnd_mode = 0; rnd_mode < 4; rnd_mode++)
118     {
119       tests_hardware_setround (rnd_mode);
120 
121       for (i = 0; i < numberof (data); i++)
122         {
123           mpz_set_ui (z, 1L);
124           mpz_mul_2exp (z, z, data[i]);
125           mpz_sub_ui (z, z, 1L);
126 
127           got = mpz_get_d_2exp (&got_exp, z);
128           if (got < 0.5 || got >= 1.0)
129             {
130               printf    ("mpz_get_d_2exp wrong on 2**%lu-1\n", data[i]);
131               printf    ("result out of range, expect 0.5 <= got < 1.0\n");
132               printf    ("   rnd_mode = %d\n", rnd_mode);
133               printf    ("   data[i]  = %lu\n", data[i]);
134               mpz_trace ("   z    ", z);
135               d_trace   ("   got  ", got);
136               printf    ("   got exp  %ld\n", got_exp);
137               abort();
138             }
139 
140           mpz_neg (z, z);
141           got = mpz_get_d_2exp (&got_exp, z);
142           if (got <= -1.0 || got > -0.5)
143             {
144               printf    ("mpz_get_d_2exp wrong on -2**%lu-1\n", data[i]);
145               printf    ("result out of range, expect -1.0 < got <= -0.5\n");
146               printf    ("   rnd_mode = %d\n", rnd_mode);
147               printf    ("   data[i]  = %lu\n", data[i]);
148               mpz_trace ("   z    ", z);
149               d_trace   ("   got  ", got);
150               printf    ("   got exp  %ld\n", got_exp);
151               abort();
152             }
153         }
154     }
155 
156   mpz_clear (z);
157   tests_hardware_setround (old_rnd_mode);
158 }
159 
160 static void
161 check_rand (void)
162 {
163   gmp_randstate_ptr rands = RANDS;
164   int     i;
165   mpz_t   z;
166   double  got;
167   long    got_exp;
168   unsigned long  bits;
169 
170   mpz_init (z);
171 
172   for (i = 0; i < 200; i++)
173     {
174       bits = gmp_urandomm_ui (rands, 512L);
175       mpz_urandomb (z, rands, bits);
176 
177       got = mpz_get_d_2exp (&got_exp, z);
178       if (mpz_sgn (z) == 0)
179         continue;
180       bits = mpz_sizeinbase (z, 2);
181 
182       if (got < 0.5 || got >= 1.0)
183         {
184           printf    ("mpz_get_d_2exp out of range, expect 0.5 <= got < 1.0\n");
185           mpz_trace ("   z    ", z);
186           d_trace   ("   got  ", got);
187           printf    ("   got exp  %ld\n", got_exp);
188           abort();
189         }
190 
191       /* FIXME: If mpz_get_d_2exp rounds upwards we might have got_exp ==
192          bits+1, so leave this test disabled until we decide if that's what
193          should happen, or not.  */
194 #if 0
195       if (got_exp != bits)
196         {
197           printf    ("mpz_get_d_2exp wrong exponent\n", i);
198           mpz_trace ("   z    ", z);
199           d_trace   ("   bits ", bits);
200           d_trace   ("   got  ", got);
201           printf    ("   got exp  %ld\n", got_exp);
202           abort();
203         }
204 #endif
205     }
206   mpz_clear (z);
207 }
208 
209 
210 int
211 main (void)
212 {
213   tests_start ();
214   mp_trace_base = -16;
215 
216   check_zero ();
217   check_onebit ();
218   check_round ();
219   check_rand ();
220 
221   tests_end ();
222   exit (0);
223 }
224