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