1/* Test mpz_get_d_2exp. 2 3Copyright 2002, 2003, 2012 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 <stdio.h> 21#include <stdlib.h> 22#include "gmp-impl.h" 23#include "tests.h" 24 25 26static void 27check_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 52static void 53check_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. */ 104static void 105check_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 159static void 160check_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 209int 210main (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