1/* Test mpz_cmp_d and mpz_cmpabs_d. 2 3Copyright 2001-2003, 2005, 2013 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 <math.h> 21 22#include "testutils.h" 23 24/* FIXME: Not sure if the tests here are exhaustive. Ought to try to get 25 each possible exit from mpz_cmp_d (and mpz_cmpabs_d) exercised. */ 26 27 28#define SGN(n) ((n) > 0 ? 1 : (n) < 0 ? -1 : 0) 29 30 31void 32check_one (const char *name, mpz_srcptr x, double y, int cmp, int cmpabs) 33{ 34 int got; 35 36 got = mpz_cmp_d (x, y); 37 if (SGN(got) != cmp) 38 { 39 unsigned i; 40 printf ("mpz_cmp_d wrong (from %s)\n", name); 41 printf (" got %d\n", got); 42 printf (" want %d\n", cmp); 43 fail: 44 printf (" x="); 45 mpz_out_str (stdout, 10, x); 46 printf ("\n y %g\n", y); 47 printf (" x=0x"); 48 mpz_out_str (stdout, -16, x); 49 printf ("\n y %g\n", y); 50 printf (" y"); 51 for (i = 0; i < sizeof(y); i++) 52 printf (" %02X", (unsigned) ((unsigned char *) &y)[i]); 53 printf ("\n"); 54 abort (); 55 } 56 57 got = mpz_cmpabs_d (x, y); 58 if (SGN(got) != cmpabs) 59 { 60 printf ("mpz_cmpabs_d wrong\n"); 61 printf (" got %d\n", got); 62 printf (" want %d\n", cmpabs); 63 goto fail; 64 } 65} 66 67void 68check_data (void) 69{ 70 static const struct { 71 const char *x; 72 double y; 73 int cmp, cmpabs; 74 75 } data[] = { 76 77 { "0", 0.0, 0, 0 }, 78 79 { "1", 0.0, 1, 1 }, 80 { "-1", 0.0, -1, 1 }, 81 82 { "1", 0.5, 1, 1 }, 83 { "-1", -0.5, -1, 1 }, 84 85 { "0", 1.0, -1, -1 }, 86 { "0", -1.0, 1, -1 }, 87 88 { "0x1000000000000000000000000000000000000000000000000", 1.0, 1, 1 }, 89 { "-0x1000000000000000000000000000000000000000000000000", 1.0, -1, 1 }, 90 91 { "0", 1e100, -1, -1 }, 92 { "0", -1e100, 1, -1 }, 93 94 { "2", 1.5, 1, 1 }, 95 { "2", -1.5, 1, 1 }, 96 { "-2", 1.5, -1, 1 }, 97 { "-2", -1.5, -1, 1 }, 98 }; 99 100 mpz_t x; 101 unsigned i; 102 103 mpz_init (x); 104 105 for (i = 0; i < numberof (data); i++) 106 { 107 mpz_set_str_or_abort (x, data[i].x, 0); 108 check_one ("check_data", x, data[i].y, data[i].cmp, data[i].cmpabs); 109 } 110 111 mpz_clear (x); 112} 113 114 115/* Equality of integers with up to 53 bits */ 116void 117check_onebits (void) 118{ 119 mpz_t x, x2; 120 double y; 121 int i; 122 123 mpz_init_set_ui (x, 0L); 124 mpz_init (x2); 125 126 for (i = 0; i < 512; i++) 127 { 128 mpz_mul_2exp (x, x, 1); 129 mpz_add_ui (x, x, 1L); 130 131 y = mpz_get_d (x); 132 mpz_set_d (x2, y); 133 134 /* stop if any truncation is occurring */ 135 if (mpz_cmp (x, x2) != 0) 136 break; 137 138 check_one ("check_onebits", x, y, 0, 0); 139 check_one ("check_onebits", x, -y, 1, 0); 140 mpz_neg (x, x); 141 check_one ("check_onebits", x, y, -1, 0); 142 check_one ("check_onebits", x, -y, 0, 0); 143 mpz_neg (x, x); 144 } 145 146 mpz_clear (x); 147 mpz_clear (x2); 148} 149 150 151/* With the mpz differing by 1, in a limb position possibly below the double */ 152void 153check_low_z_one (void) 154{ 155 mpz_t x; 156 double y; 157 unsigned long i; 158 159 mpz_init (x); 160 161 /* FIXME: It'd be better to base this on the float format. */ 162#if defined (__vax) || defined (__vax__) 163#define LIM 127 /* vax fp numbers have limited range */ 164#else 165#define LIM 512 166#endif 167 168 for (i = 1; i < LIM; i++) 169 { 170 mpz_set_ui (x, 1L); 171 mpz_mul_2exp (x, x, i); 172 y = mpz_get_d (x); 173 174 check_one ("check_low_z_one", x, y, 0, 0); 175 check_one ("check_low_z_one", x, -y, 1, 0); 176 mpz_neg (x, x); 177 check_one ("check_low_z_one", x, y, -1, 0); 178 check_one ("check_low_z_one", x, -y, 0, 0); 179 mpz_neg (x, x); 180 181 mpz_sub_ui (x, x, 1); 182 183 check_one ("check_low_z_one", x, y, -1, -1); 184 check_one ("check_low_z_one", x, -y, 1, -1); 185 mpz_neg (x, x); 186 check_one ("check_low_z_one", x, y, -1, -1); 187 check_one ("check_low_z_one", x, -y, 1, -1); 188 mpz_neg (x, x); 189 190 mpz_add_ui (x, x, 2); 191 192 check_one ("check_low_z_one", x, y, 1, 1); 193 check_one ("check_low_z_one", x, -y, 1, 1); 194 mpz_neg (x, x); 195 check_one ("check_low_z_one", x, y, -1, 1); 196 check_one ("check_low_z_one", x, -y, -1, 1); 197 mpz_neg (x, x); 198 } 199 200 mpz_clear (x); 201} 202 203/* Comparing 1 and 1+2^-n. "y" is volatile to make gcc store and fetch it, 204 which forces it to a 64-bit double, whereas on x86 it would otherwise 205 remain on the float stack as an 80-bit long double. */ 206void 207check_one_2exp (void) 208{ 209 double e; 210 mpz_t x; 211 volatile double y; 212 int i; 213 214 mpz_init (x); 215 216 e = 1.0; 217 for (i = 0; i < 128; i++) 218 { 219 e /= 2.0; 220 y = 1.0 + e; 221 if (y == 1.0) 222 break; 223 224 mpz_set_ui (x, 1L); 225 check_one ("check_one_2exp", x, y, -1, -1); 226 check_one ("check_one_2exp", x, -y, 1, -1); 227 228 mpz_set_si (x, -1L); 229 check_one ("check_one_2exp", x, y, -1, -1); 230 check_one ("check_one_2exp", x, -y, 1, -1); 231 } 232 233 mpz_clear (x); 234} 235 236void 237check_infinity (void) 238{ 239 mpz_t x; 240 double y = HUGE_VAL; 241 if (y != 2*y) 242 return; 243 244 mpz_init (x); 245 246 /* 0 cmp inf */ 247 mpz_set_ui (x, 0L); 248 check_one ("check_infinity", x, y, -1, -1); 249 check_one ("check_infinity", x, -y, 1, -1); 250 251 /* 123 cmp inf */ 252 mpz_set_ui (x, 123L); 253 check_one ("check_infinity", x, y, -1, -1); 254 check_one ("check_infinity", x, -y, 1, -1); 255 256 /* -123 cmp inf */ 257 mpz_set_si (x, -123L); 258 check_one ("check_infinity", x, y, -1, -1); 259 check_one ("check_infinity", x, -y, 1, -1); 260 261 /* 2^5000 cmp inf */ 262 mpz_set_ui (x, 1L); 263 mpz_mul_2exp (x, x, 5000L); 264 check_one ("check_infinity", x, y, -1, -1); 265 check_one ("check_infinity", x, -y, 1, -1); 266 267 /* -2^5000 cmp inf */ 268 mpz_neg (x, x); 269 check_one ("check_infinity", x, y, -1, -1); 270 check_one ("check_infinity", x, -y, 1, -1); 271 272 mpz_clear (x); 273} 274 275void 276testmain (int argc, char *argv[]) 277{ 278 check_data (); 279 check_onebits (); 280 check_low_z_one (); 281 check_one_2exp (); 282 check_infinity (); 283} 284