1 /* Test mpq_set_d.
2
3 Copyright 2001-2003, 2005, 2013, 2018 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 <math.h>
21 #include <float.h>
22 #include <limits.h>
23
24 #include "testutils.h"
25 #include "../mini-mpq.h"
26
27 #define COUNT 2000
28
29 mp_bitcnt_t
mpz_mantissasizeinbits(const mpz_t z)30 mpz_mantissasizeinbits (const mpz_t z)
31 {
32 return ! mpz_cmp_ui (z, 0) ? 0 :
33 mpz_sizeinbase (z, 2) - mpz_scan1 (z, 0);
34 }
35
36 int
mpz_abspow2_p(const mpz_t z)37 mpz_abspow2_p (const mpz_t z)
38 {
39 return mpz_mantissasizeinbits (z) == 1;
40 }
41
42 mp_bitcnt_t
mpq_mantissasizeinbits(const mpq_t q)43 mpq_mantissasizeinbits (const mpq_t q)
44 {
45 if (! mpz_abspow2_p (mpq_denref (q)))
46 return ~ (mp_bitcnt_t) 0;
47
48 return mpz_mantissasizeinbits (mpq_numref (q));
49 }
50
51 #if defined(DBL_MANT_DIG) && FLT_RADIX == 2
52 int
mpz_get_d_exact_p(const mpz_t z)53 mpz_get_d_exact_p (const mpz_t z)
54 {
55 return mpz_mantissasizeinbits (z) <= DBL_MANT_DIG;
56 }
57
58 int
mpq_get_d_exact_p(const mpq_t q)59 mpq_get_d_exact_p (const mpq_t q)
60 {
61 return mpq_mantissasizeinbits (q) <= DBL_MANT_DIG;
62 }
63 #define HAVE_EXACT_P 1
64 #endif
65
66 void
check_random(void)67 check_random (void)
68 {
69 unsigned i;
70 mpz_t x;
71 mpq_t y, z;
72
73 mpz_init (x);
74 mpq_init (y);
75 mpq_init (z);
76
77 for (i = 0; i < COUNT; i++)
78 {
79 /* Use volatile, to avoid extended precision in floating point
80 registers, e.g., on m68k and 80387. */
81 volatile double d, f;
82 unsigned long m;
83 int e, c;
84
85 mini_rrandomb (x, CHAR_BIT * sizeof (unsigned long));
86 m = mpz_get_ui (x);
87 mini_urandomb (x, 8);
88 e = mpz_get_ui (x) - 128;
89
90 d = ldexp ((double) m, e);
91 mpq_set_d (y, d);
92 f = mpq_get_d (y);
93 if (f != d)
94 {
95 fprintf (stderr, "mpq_set_d/mpq_get_d failed:\n");
96 goto dumperror;
97 }
98
99 d = - d;
100 mpq_neg (y, y);
101
102 mpq_set_d (z, d);
103 f = mpq_get_d (z);
104 if (f != d || !mpq_equal (y, z))
105 {
106 fprintf (stderr, "mpq_set_d/mpq_get_d failed:\n");
107 dumperror:
108 dump ("ny", mpq_numref (y));
109 dump ("dy", mpq_denref (y));
110 fprintf (stderr, "m = %lx, e = %i\n", m, e);
111 fprintf (stderr, "d = %.35g\n", d);
112 fprintf (stderr, "f = %.35g\n", f);
113 fprintf (stderr, "f - d = %.35g\n", f - d);
114 abort ();
115 }
116
117 mini_rrandomb (x, CHAR_BIT * sizeof (unsigned long));
118 m = mpz_get_ui (x);
119 mini_urandomb (x, 8);
120 e = mpz_get_ui (x) - 128;
121
122 d = ldexp ((double) m, e);
123 mpq_set_d (y, d);
124
125 if (i == 0)
126 mpq_neg (z, y);
127
128 mpq_add (y, y, z);
129 mpq_set_d (z, mpq_get_d (y));
130 f = mpq_get_d (z);
131 c = mpq_cmp (y, z);
132
133 #if defined(HAVE_EXACT_P)
134 if (mpq_get_d_exact_p (y) ? c != 0 : (f > 0 ? c <= 0 : c >= 0))
135 #else
136 if (f > 0 ? c < 0 : c > 0)
137 #endif
138 {
139 fprintf (stderr, "mpq_get_d/mpq_set_d failed: %i %i\n", i, c);
140 goto dumperror;
141 }
142 }
143
144 mpz_clear (x);
145 mpq_clear (y);
146 mpq_clear (z);
147 }
148
149
150 void
check_data(void)151 check_data (void)
152 {
153 static const struct {
154 double y;
155 long int n;
156 unsigned long d;
157 } data[] = {
158 { 0.0, 0, 1 },
159 { 1.0, 1, 1 },
160 { -1.0, -1, 1 },
161 { -1.5, -3, 2 },
162 {-1.25, -5, 4 },
163 {0.125, 1, 8 },
164
165 {24685,24685,1},
166 {-9876,-9876,1},
167 {463.5, 927,2},
168
169 {1234.5/8192, 2469, 16384 },
170 {-543.0/1024, -543, 1024 },
171 {9876.5/ 512, 19753, 1024 },
172 {9753.0/ 128, 9753, 128 },
173 {-789.0/ 32, -789, 32 },
174 {4.580078125, 2345, 512 },
175 };
176
177 mpq_t x, r;
178 unsigned i;
179 double d;
180
181 mpq_init (x);
182 mpq_init (r);
183
184 for (i = 0; i < numberof (data); i++)
185 {
186 mpq_set_d (x, data[i].y);
187 mpq_set_si (r, data[i].n, data[i].d);
188 mpq_canonicalize (r);
189 if (!mpq_equal (x, r))
190 {
191 fprintf (stderr, "mpq_set_d failed: %li / %lu != %g\n", data[i].n, data[i].d, data[i].y);
192 abort ();
193 }
194 d = mpq_get_d (r);
195 if (d != data[i].y)
196 {
197 fprintf (stderr, "mpq_get_d failed: %li / %lu != %g\n", data[i].n, data[i].d, data[i].y);
198 abort ();
199 }
200 }
201
202 mpq_clear (x);
203 mpq_clear (r);
204 }
205
206 void
testmain(int argc,char * argv[])207 testmain (int argc, char *argv[])
208 {
209 check_data ();
210 check_random ();
211 }
212