1 /* Test mpz_get_d_2exp. 2 3 Copyright 2002, 2003, 2012 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 <stdio.h> 21 #include <stdlib.h> 22 #include "gmp-impl.h" 23 #include "tests.h" 24 25 26 static void 27 check_zero (void) 28 { 29 mpz_t z; 30 double got, want; 31 long got_exp, want_exp; 32 33 mpz_init_set_ui (z, 0); 34 35 want = 0.0; 36 want_exp = 0; 37 got = mpz_get_d_2exp (&got_exp, z); 38 if (got != want || got_exp != want_exp) 39 { 40 printf ("mpz_get_d_2exp wrong on zero\n"); 41 mpz_trace (" z ", z); 42 d_trace (" want ", want); 43 d_trace (" got ", got); 44 printf (" want exp %ld\n", want_exp); 45 printf (" got exp %ld\n", got_exp); 46 abort(); 47 } 48 49 mpz_clear (z); 50 } 51 52 static void 53 check_onebit (void) 54 { 55 static const unsigned long data[] = { 56 1, 32, 52, 53, 54, 63, 64, 65, 128, 256, 511, 512, 513 57 }; 58 mpz_t z; 59 double got, want; 60 long got_exp, want_exp; 61 int i; 62 63 mpz_init (z); 64 65 for (i = 0; i < numberof (data); i++) 66 { 67 mpz_set_ui (z, 1L); 68 mpz_mul_2exp (z, z, data[i]); 69 want = 0.5; 70 want_exp = data[i] + 1; 71 got = mpz_get_d_2exp (&got_exp, z); 72 if (got != want || got_exp != want_exp) 73 { 74 printf ("mpz_get_d_2exp wrong on 2**%ld\n", data[i]); 75 mpz_trace (" z ", z); 76 d_trace (" want ", want); 77 d_trace (" got ", got); 78 printf (" want exp %ld\n", want_exp); 79 printf (" got exp %ld\n", got_exp); 80 abort(); 81 } 82 83 mpz_set_si (z, -1L); 84 mpz_mul_2exp (z, z, data[i]); 85 want = -0.5; 86 want_exp = data[i] + 1; 87 got = mpz_get_d_2exp (&got_exp, z); 88 if (got != want || got_exp != want_exp) 89 { 90 printf ("mpz_get_d_2exp wrong on -2**%ld\n", data[i]); 91 mpz_trace (" z ", z); 92 d_trace (" want ", want); 93 d_trace (" got ", got); 94 printf (" want exp %ld\n", want_exp); 95 printf (" got exp %ld\n", got_exp); 96 abort(); 97 } 98 } 99 mpz_clear (z); 100 } 101 102 /* Check that hardware rounding doesn't make mpz_get_d_2exp return a value 103 outside its defined range. */ 104 static void 105 check_round (void) 106 { 107 static const unsigned long data[] = { 1, 32, 53, 54, 64, 128, 256, 512 }; 108 mpz_t z; 109 double got; 110 long got_exp; 111 int i, rnd_mode, old_rnd_mode; 112 113 mpz_init (z); 114 old_rnd_mode = tests_hardware_getround (); 115 116 for (rnd_mode = 0; rnd_mode < 4; rnd_mode++) 117 { 118 tests_hardware_setround (rnd_mode); 119 120 for (i = 0; i < numberof (data); i++) 121 { 122 mpz_set_ui (z, 1L); 123 mpz_mul_2exp (z, z, data[i]); 124 mpz_sub_ui (z, z, 1L); 125 126 got = mpz_get_d_2exp (&got_exp, z); 127 if (got < 0.5 || got >= 1.0) 128 { 129 printf ("mpz_get_d_2exp wrong on 2**%lu-1\n", data[i]); 130 printf ("result out of range, expect 0.5 <= got < 1.0\n"); 131 printf (" rnd_mode = %d\n", rnd_mode); 132 printf (" data[i] = %lu\n", data[i]); 133 mpz_trace (" z ", z); 134 d_trace (" got ", got); 135 printf (" got exp %ld\n", got_exp); 136 abort(); 137 } 138 139 mpz_neg (z, z); 140 got = mpz_get_d_2exp (&got_exp, z); 141 if (got <= -1.0 || got > -0.5) 142 { 143 printf ("mpz_get_d_2exp wrong on -2**%lu-1\n", data[i]); 144 printf ("result out of range, expect -1.0 < got <= -0.5\n"); 145 printf (" rnd_mode = %d\n", rnd_mode); 146 printf (" data[i] = %lu\n", data[i]); 147 mpz_trace (" z ", z); 148 d_trace (" got ", got); 149 printf (" got exp %ld\n", got_exp); 150 abort(); 151 } 152 } 153 } 154 155 mpz_clear (z); 156 tests_hardware_setround (old_rnd_mode); 157 } 158 159 static void 160 check_rand (void) 161 { 162 gmp_randstate_ptr rands = RANDS; 163 int i; 164 mpz_t z; 165 double got; 166 long got_exp; 167 unsigned long bits; 168 169 mpz_init (z); 170 171 for (i = 0; i < 200; i++) 172 { 173 bits = gmp_urandomm_ui (rands, 512L); 174 mpz_urandomb (z, rands, bits); 175 176 got = mpz_get_d_2exp (&got_exp, z); 177 if (mpz_sgn (z) == 0) 178 continue; 179 bits = mpz_sizeinbase (z, 2); 180 181 if (got < 0.5 || got >= 1.0) 182 { 183 printf ("mpz_get_d_2exp out of range, expect 0.5 <= got < 1.0\n"); 184 mpz_trace (" z ", z); 185 d_trace (" got ", got); 186 printf (" got exp %ld\n", got_exp); 187 abort(); 188 } 189 190 /* FIXME: If mpz_get_d_2exp rounds upwards we might have got_exp == 191 bits+1, so leave this test disabled until we decide if that's what 192 should happen, or not. */ 193 #if 0 194 if (got_exp != bits) 195 { 196 printf ("mpz_get_d_2exp wrong exponent\n", i); 197 mpz_trace (" z ", z); 198 d_trace (" bits ", bits); 199 d_trace (" got ", got); 200 printf (" got exp %ld\n", got_exp); 201 abort(); 202 } 203 #endif 204 } 205 mpz_clear (z); 206 } 207 208 209 int 210 main (void) 211 { 212 tests_start (); 213 mp_trace_base = -16; 214 215 check_zero (); 216 check_onebit (); 217 check_round (); 218 check_rand (); 219 220 tests_end (); 221 exit (0); 222 } 223