blob: 9a1aa8f1120a2a3e733ff05817693719f79fb089 [file] [log] [blame]
Austin Schuhbb1338c2024-06-15 19:31:16 -07001/*
2
3Copyright 2012, 2013, 2018 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 <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
31mp_bitcnt_t
32mpz_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
39int
40mpz_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
49void
50test_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
121static const struct
122{
123 double d;
124 const char *s;
125} values[] = {
126 { 0.0, "0" },
127 { 0.3, "0" },
128 { -0.3, "0" },
129 { M_PI, "3" },
130 { M_PI*1e15, "b29430a256d21" },
131 { -M_PI*1e15, "-b29430a256d21" },
132 /* 17 * 2^{200} =
133 27317946752402834684213355569799764242877450894307478200123392 */
134 {0.2731794675240283468421335556979976424288e62,
135 "1100000000000000000000000000000000000000000000000000" },
136 { 0.0, NULL }
137};
138
139void
140testmain (int argc, char **argv)
141{
142 unsigned i;
143 mpz_t x;
144
145 for (i = 0; values[i].s; i++)
146 {
147 char *s;
148 mpz_init_set_d (x, values[i].d);
149 s = mpz_get_str (NULL, 16, x);
150 if (strcmp (s, values[i].s) != 0)
151 {
152 fprintf (stderr, "mpz_set_d failed:\n"
153 "d = %.20g\n"
154 "s = %s\n"
155 "r = %s\n",
156 values[i].d, s, values[i].s);
157 abort ();
158 }
159 testfree (s);
160 mpz_clear (x);
161 }
162
163 mpz_init (x);
164
165 for (i = 0; i < COUNT; i++)
166 {
167 /* Use volatile, to avoid extended precision in floating point
168 registers, e.g., on m68k and 80387. */
169 volatile double d, f;
170 unsigned long m;
171 int e;
172
173 mini_rrandomb (x, GMP_LIMB_BITS);
174 m = mpz_get_ui (x);
175 mini_urandomb (x, 8);
176 e = mpz_get_ui (x) - 100;
177
178 d = ldexp ((double) m, e);
179 mpz_set_d (x, d);
180 f = mpz_get_d (x);
181 if (f != floor (d))
182 {
183 fprintf (stderr, "mpz_set_d/mpz_get_d failed:\n");
184 goto dumperror;
185 }
186 if ((f == d) ? (mpz_cmp_d (x, d) != 0) : (mpz_cmp_d (x, d) >= 0))
187 {
188 fprintf (stderr, "mpz_cmp_d (x, d) failed:\n");
189 goto dumperror;
190 }
191 f = d + 1.0;
192 if (f > d && ! (mpz_cmp_d (x, f) < 0))
193 {
194 fprintf (stderr, "mpz_cmp_d (x, f) failed:\n");
195 goto dumperror;
196 }
197
198 d = - d;
199
200 mpz_set_d (x, d);
201 f = mpz_get_d (x);
202 if (f != ceil (d))
203 {
204 fprintf (stderr, "mpz_set_d/mpz_get_d failed:\n");
205 dumperror:
206 dump ("x", x);
207 fprintf (stderr, "m = %lx, e = %i\n", m, e);
208 fprintf (stderr, "d = %.15g\n", d);
209 fprintf (stderr, "f = %.15g\n", f);
210 fprintf (stderr, "f - d = %.5g\n", f - d);
211 abort ();
212 }
213 if ((f == d) ? (mpz_cmp_d (x, d) != 0) : (mpz_cmp_d (x, d) <= 0))
214 {
215 fprintf (stderr, "mpz_cmp_d (x, d) failed:\n");
216 goto dumperror;
217 }
218 f = d - 1.0;
219 if (f < d && ! (mpz_cmp_d (x, f) > 0))
220 {
221 fprintf (stderr, "mpz_cmp_d (x, f) failed:\n");
222 goto dumperror;
223 }
224 }
225
226 mpz_clear (x);
227 test_matissa();
228}