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 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 37 mpz_abspow2_p (const mpz_t z) 38 { 39 return mpz_mantissasizeinbits (z) == 1; 40 } 41 42 mp_bitcnt_t 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 53 mpz_get_d_exact_p (const mpz_t z) 54 { 55 return mpz_mantissasizeinbits (z) <= DBL_MANT_DIG; 56 } 57 58 int 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 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 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 207 testmain (int argc, char *argv[]) 208 { 209 check_data (); 210 check_random (); 211 } 212