1 /*
2
3 Copyright 2012, 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 <assert.h>
21 #include <stdlib.h>
22 #include <stdio.h>
23
24 #include "testutils.h"
25 #include "../mini-mpq.h"
26
27 #define MAXBITS 300
28 #define COUNT 10000
29
30 static void
31 _mpq_set_zz (mpq_t q, mpz_t n, mpz_t d)
32 {
33 if (mpz_fits_ulong_p (d) && mpz_fits_slong_p (n))
34 {
35 mpq_set_si (q, mpz_get_si (n), mpz_get_ui (d));
36 }
37 else if (mpz_fits_ulong_p (d) && mpz_fits_ulong_p (n))
38 {
39 mpq_set_ui (q, mpz_get_ui (n), mpz_get_ui (d));
40 }
41 else
42 {
43 mpq_set_num (q, n);
44 mpq_set_den (q, d);
45 }
46 mpq_canonicalize (q);
47 }
48
49 void
50 testmain (int argc, char **argv)
51 {
52 unsigned i;
53 mpz_t a, b, t;
54 mpq_t aq, rq, tq;
55 mp_bitcnt_t e;
56 long int e2, t1, t2;
57
58 mpz_init (a);
59 mpz_init (b);
60 mpz_init (t);
61 mpq_init (aq);
62 mpq_init (rq);
63 mpq_init (tq);
64
65 for (i = 0; i < COUNT; i++)
66 {
67 do {
68 mini_random_bit_op (OP_COMBIT, MAXBITS, a, &e, b);
69 } while (mpz_sgn (a) == 0 || mpz_sgn (b) == 0);
70
71 _mpq_set_zz (aq, a, b);
72 e2 = mpz_scan1 (a, 0);
73 e2-= mpz_scan1 (b, 0);
74
75 mpq_mul_2exp (rq, aq, e);
76 t1 = mpz_scan1 (mpq_numref (rq), 0);
77 t2 = mpz_scan1 (mpq_denref (rq), 0);
78 mpq_neg (tq, rq);
79 mpq_div (tq, aq, tq);
80 mpq_get_den (t, tq);
81
82 if (e2 + e != t1 - t2 || (t2 != 0 && t1 != 0) || mpz_scan1 (t, 0) != e
83 || mpz_sizeinbase (t, 2) - 1 != e || mpz_cmp_si (mpq_numref (tq), -1) != 0)
84 {
85 fprintf (stderr, "mpq_mul_2exp failed: %lu\n", e);
86 dump ("na", a);
87 dump ("da", b);
88 dump ("nr", mpq_numref (rq));
89 dump ("dr", mpq_denref (rq));
90 abort ();
91 }
92
93 mpq_div_2exp (rq, aq, e);
94 t1 = mpz_scan1 (mpq_numref (rq), 0);
95 t2 = mpz_scan1 (mpq_denref (rq), 0);
96 mpq_div (aq, aq, rq);
97 mpq_get_num (t, aq);
98
99 if (e2 != t1 - t2 + e || (t2 != 0 && t1 != 0) || mpz_scan1 (t, 0) != e
100 || mpz_sizeinbase (t, 2) - 1 != e || mpz_cmp_ui (mpq_denref (aq), 1) != 0)
101 {
102 fprintf (stderr, "mpq_div_2exp failed: %lu\n", e);
103 fprintf (stderr, "%li %li %lu %zu\n", e2, t2, mpz_scan1 (t, 0), mpz_sizeinbase (t, 2));
104 dump ("na", a);
105 dump ("da", b);
106 dump ("nr", mpq_numref (rq));
107 dump ("dr", mpq_denref (rq));
108 abort ();
109 }
110
111 mpq_set_ui (aq, 0, 1);
112 mpq_set_ui (rq, 6, 7);
113 mpq_set (tq, aq);
114 mpq_div_2exp (rq, aq, e);
115
116 if (!mpq_equal (tq, rq))
117 {
118 fprintf (stderr, "mpq_div_2exp failed on zero: %lu\n", e);
119 abort ();
120 }
121
122 mpq_set_ui (rq, 7, 6);
123 mpq_mul_2exp (rq, aq, e);
124
125 if (!mpq_equal (rq, tq))
126 {
127 fprintf (stderr, "mpq_mul_2exp failed on zero: %lu\n", e);
128 abort ();
129 }
130 }
131
132 mpz_clear (a);
133 mpz_clear (b);
134 mpz_clear (t);
135 mpq_clear (aq);
136 mpq_clear (rq);
137 mpq_clear (tq);
138 }