1 /*
2
3 Copyright 2012, 2013, 2018, 2020 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 https://www.gnu.org/licenses/. */
19
20 #include <limits.h>
21 #include <math.h>
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <float.h>
26
27 #include "testutils.h"
28
29 #define GMP_LIMB_BITS (sizeof(mp_limb_t) * CHAR_BIT)
30
31 mp_bitcnt_t
mpz_mantissasizeinbits(const mpz_t z)32 mpz_mantissasizeinbits (const mpz_t z)
33 {
34 return ! mpz_cmp_ui (z, 0) ? 0 :
35 mpz_sizeinbase (z, 2) - mpz_scan1 (z, 0);
36 }
37
38 #if defined(DBL_MANT_DIG) && FLT_RADIX == 2
39 int
mpz_get_d_exact_p(const mpz_t z)40 mpz_get_d_exact_p (const mpz_t z)
41 {
42 return mpz_mantissasizeinbits (z) <= DBL_MANT_DIG;
43 }
44 #define HAVE_EXACT_P 1
45 #endif
46
47 #define COUNT 10000
48
49 void
test_matissa(void)50 test_matissa (void)
51 {
52 mpz_t x, y;
53 int i, c;
54
55 mpz_init (x);
56 mpz_init (y);
57
58 mini_urandomb (y, 4);
59 c = i = mpz_get_ui (y);
60
61 do {
62 double d;
63 int cmp;
64
65 mpz_setbit (x, c);
66 d = mpz_get_d (x);
67 mpz_set_d (y, d);
68 if (mpz_cmp_d (y, d) != 0)
69 {
70 fprintf (stderr, "mpz_cmp_d (y, d) failed:\n"
71 "d = %.20g\n"
72 "i = %i\n"
73 "c = %i\n",
74 d, i, c);
75 abort ();
76 }
77
78 cmp = mpz_cmp (x, y);
79
80 #if defined(HAVE_EXACT_P)
81 if ((mpz_get_d_exact_p (x) != 0) != (cmp == 0))
82 {
83 fprintf (stderr, "Not all bits converted:\n"
84 "d = %.20g\n"
85 "i = %i\n"
86 "c = %i\n",
87 d, i, c);
88 abort ();
89 }
90 #endif
91
92 if (cmp < 0)
93 {
94 fprintf (stderr, "mpz_get_d failed:\n"
95 "d = %.20g\n"
96 "i = %i\n"
97 "c = %i\n",
98 d, i, c);
99 abort ();
100 }
101 else if (cmp > 0)
102 {
103 if (mpz_cmp_d (x, d) <= 0)
104 {
105 fprintf (stderr, "mpz_cmp_d (x, d) failed:\n"
106 "d = %.20g\n"
107 "i = %i\n"
108 "c = %i\n",
109 d, i, c);
110 abort ();
111 }
112 break;
113 }
114 ++c;
115 } while (1);
116
117 mpz_clear (x);
118 mpz_clear (y);
119 }
120
121 #ifndef M_PI
122 #define M_PI 3.141592653589793238462643383279502884
123 #endif
124
125 static const struct
126 {
127 double d;
128 const char *s;
129 } values[] = {
130 { 0.0, "0" },
131 { 0.3, "0" },
132 { -0.3, "0" },
133 { M_PI, "3" },
134 { M_PI*1e15, "b29430a256d21" },
135 { -M_PI*1e15, "-b29430a256d21" },
136 /* 17 * 2^{200} =
137 27317946752402834684213355569799764242877450894307478200123392 */
138 {0.2731794675240283468421335556979976424288e62,
139 "1100000000000000000000000000000000000000000000000000" },
140 { 0.0, NULL }
141 };
142
143 void
testmain(int argc,char ** argv)144 testmain (int argc, char **argv)
145 {
146 unsigned i;
147 mpz_t x;
148
149 for (i = 0; values[i].s; i++)
150 {
151 char *s;
152 mpz_init_set_d (x, values[i].d);
153 s = mpz_get_str (NULL, 16, x);
154 if (strcmp (s, values[i].s) != 0)
155 {
156 fprintf (stderr, "mpz_set_d failed:\n"
157 "d = %.20g\n"
158 "s = %s\n"
159 "r = %s\n",
160 values[i].d, s, values[i].s);
161 abort ();
162 }
163 testfree (s);
164 mpz_clear (x);
165 }
166
167 mpz_init (x);
168
169 for (i = 0; i < COUNT; i++)
170 {
171 /* Use volatile, to avoid extended precision in floating point
172 registers, e.g., on m68k and 80387. */
173 volatile double d, f;
174 unsigned long m;
175 int e;
176
177 mini_rrandomb (x, GMP_LIMB_BITS);
178 m = mpz_get_ui (x);
179 mini_urandomb (x, 8);
180 e = mpz_get_ui (x) - 100;
181
182 d = ldexp ((double) m, e);
183 mpz_set_d (x, d);
184 f = mpz_get_d (x);
185 if (f != floor (d))
186 {
187 fprintf (stderr, "mpz_set_d/mpz_get_d failed:\n");
188 goto dumperror;
189 }
190 if ((f == d) ? (mpz_cmp_d (x, d) != 0) : (mpz_cmp_d (x, d) >= 0))
191 {
192 fprintf (stderr, "mpz_cmp_d (x, d) failed:\n");
193 goto dumperror;
194 }
195 f = d + 1.0;
196 if (f > d && ! (mpz_cmp_d (x, f) < 0))
197 {
198 fprintf (stderr, "mpz_cmp_d (x, f) failed:\n");
199 goto dumperror;
200 }
201
202 d = - d;
203
204 mpz_set_d (x, d);
205 f = mpz_get_d (x);
206 if (f != ceil (d))
207 {
208 fprintf (stderr, "mpz_set_d/mpz_get_d failed:\n");
209 dumperror:
210 dump ("x", x);
211 fprintf (stderr, "m = %lx, e = %i\n", m, e);
212 fprintf (stderr, "d = %.15g\n", d);
213 fprintf (stderr, "f = %.15g\n", f);
214 fprintf (stderr, "f - d = %.5g\n", f - d);
215 abort ();
216 }
217 if ((f == d) ? (mpz_cmp_d (x, d) != 0) : (mpz_cmp_d (x, d) <= 0))
218 {
219 fprintf (stderr, "mpz_cmp_d (x, d) failed:\n");
220 goto dumperror;
221 }
222 f = d - 1.0;
223 if (f < d && ! (mpz_cmp_d (x, f) > 0))
224 {
225 fprintf (stderr, "mpz_cmp_d (x, f) failed:\n");
226 goto dumperror;
227 }
228 }
229
230 mpz_clear (x);
231 test_matissa();
232 }
233