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