1 /* Test mpz_[cft]div_[qr]_2exp. 2 3 Copyright 2001 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 23 #include "gmp-impl.h" 24 #include "tests.h" 25 26 27 /* If the remainder is in the correct range and q*d+r is correct, then q 28 must have rounded correctly. */ 29 30 void 31 check_one (mpz_srcptr a, unsigned long d) 32 { 33 mpz_t q, r, p, d2exp; 34 int inplace; 35 36 mpz_init (d2exp); 37 mpz_init (q); 38 mpz_init (r); 39 mpz_init (p); 40 41 mpz_set_ui (d2exp, 1L); 42 mpz_mul_2exp (d2exp, d2exp, d); 43 44 #define INPLACE(fun,dst,src,d) \ 45 if (inplace) \ 46 { \ 47 mpz_set (dst, src); \ 48 fun (dst, dst, d); \ 49 } \ 50 else \ 51 fun (dst, src, d); 52 53 for (inplace = 0; inplace <= 1; inplace++) 54 { 55 INPLACE (mpz_fdiv_q_2exp, q, a, d); 56 INPLACE (mpz_fdiv_r_2exp, r, a, d); 57 58 mpz_mul_2exp (p, q, d); 59 mpz_add (p, p, r); 60 if (mpz_sgn (r) < 0 || mpz_cmp (r, d2exp) >= 0) 61 { 62 printf ("mpz_fdiv_r_2exp result out of range\n"); 63 goto error; 64 } 65 if (mpz_cmp (p, a) != 0) 66 { 67 printf ("mpz_fdiv_[qr]_2exp doesn't multiply back\n"); 68 goto error; 69 } 70 71 72 INPLACE (mpz_cdiv_q_2exp, q, a, d); 73 INPLACE (mpz_cdiv_r_2exp, r, a, d); 74 75 mpz_mul_2exp (p, q, d); 76 mpz_add (p, p, r); 77 if (mpz_sgn (r) > 0 || mpz_cmpabs (r, d2exp) >= 0) 78 { 79 printf ("mpz_cdiv_r_2exp result out of range\n"); 80 goto error; 81 } 82 if (mpz_cmp (p, a) != 0) 83 { 84 printf ("mpz_cdiv_[qr]_2exp doesn't multiply back\n"); 85 goto error; 86 } 87 88 89 INPLACE (mpz_tdiv_q_2exp, q, a, d); 90 INPLACE (mpz_tdiv_r_2exp, r, a, d); 91 92 mpz_mul_2exp (p, q, d); 93 mpz_add (p, p, r); 94 if (mpz_sgn (r) != 0 && mpz_sgn (r) != mpz_sgn (a)) 95 { 96 printf ("mpz_tdiv_r_2exp result wrong sign\n"); 97 goto error; 98 } 99 if (mpz_cmpabs (r, d2exp) >= 0) 100 { 101 printf ("mpz_tdiv_r_2exp result out of range\n"); 102 goto error; 103 } 104 if (mpz_cmp (p, a) != 0) 105 { 106 printf ("mpz_tdiv_[qr]_2exp doesn't multiply back\n"); 107 goto error; 108 } 109 } 110 111 mpz_clear (d2exp); 112 mpz_clear (q); 113 mpz_clear (r); 114 mpz_clear (p); 115 return; 116 117 118 error: 119 mpz_trace ("a", a); 120 printf ("d=%lu\n", d); 121 mpz_trace ("q", q); 122 mpz_trace ("r", r); 123 mpz_trace ("p", p); 124 125 mp_trace_base = -16; 126 mpz_trace ("a", a); 127 printf ("d=0x%lX\n", d); 128 mpz_trace ("q", q); 129 mpz_trace ("r", r); 130 mpz_trace ("p", p); 131 132 abort (); 133 } 134 135 136 void 137 check_all (mpz_ptr a, unsigned long d) 138 { 139 check_one (a, d); 140 mpz_neg (a, a); 141 check_one (a, d); 142 } 143 144 145 void 146 check_various (void) 147 { 148 static const unsigned long table[] = { 149 0, 1, 2, 3, 4, 5, 150 GMP_NUMB_BITS-1, GMP_NUMB_BITS, GMP_NUMB_BITS+1, 151 2*GMP_NUMB_BITS-1, 2*GMP_NUMB_BITS, 2*GMP_NUMB_BITS+1, 152 3*GMP_NUMB_BITS-1, 3*GMP_NUMB_BITS, 3*GMP_NUMB_BITS+1, 153 4*GMP_NUMB_BITS-1, 4*GMP_NUMB_BITS, 4*GMP_NUMB_BITS+1 154 }; 155 156 int i, j; 157 unsigned long n, d; 158 mpz_t a; 159 160 mpz_init (a); 161 162 /* a==0, and various d */ 163 mpz_set_ui (a, 0L); 164 for (i = 0; i < numberof (table); i++) 165 check_one (a, table[i]); 166 167 /* a==2^n, and various d */ 168 for (i = 0; i < numberof (table); i++) 169 { 170 n = table[i]; 171 mpz_set_ui (a, 1L); 172 mpz_mul_2exp (a, a, n); 173 174 for (j = 0; j < numberof (table); j++) 175 { 176 d = table[j]; 177 check_all (a, d); 178 } 179 } 180 181 mpz_clear (a); 182 } 183 184 185 void 186 check_random (int argc, char *argv[]) 187 { 188 gmp_randstate_ptr rands = RANDS; 189 int reps = 100; 190 mpz_t a; 191 unsigned long d; 192 int i; 193 194 if (argc == 2) 195 reps = atoi (argv[1]); 196 197 mpz_init (a); 198 199 for (i = 0; i < reps; i++) 200 { 201 /* exponentially within 2 to 257 bits */ 202 mpz_erandomb (a, rands, urandom () % 8 + 2); 203 204 d = urandom () % 256; 205 206 check_all (a, d); 207 } 208 209 mpz_clear (a); 210 } 211 212 213 int 214 main (int argc, char *argv[]) 215 { 216 tests_start (); 217 218 check_various (); 219 check_random (argc, argv); 220 221 tests_end (); 222 exit (0); 223 } 224