1 /**
2 * Division
3 * 
4 * Copyright:
5 * (C) 1999-2007 Jack Lloyd
6 * (C) 2014-2015 Etienne Cimon
7 *
8 * License:
9 * Botan is released under the Simplified BSD License (see LICENSE.md)
10 */
11 module botan.math.bigint.divide;
12 
13 import botan.constants;
14 import botan.math.bigint.bigint;
15 import botan.math.mp.mp_core;
16 import botan.constants;
17 import std.algorithm : max;
18 /**
19 * BigInt Division
20 * Params:
21 *  x = an integer
22 *  y_arg = a non-zero integer
23 *  q = will be set to x / y
24 *  r = will be set to x % y
25 */
26 void divide(const(BigInt)* x, const(BigInt)* y_arg, BigInt* q_out, BigInt* r_out, bool trace = false)
27 {
28     /*
29     * Solve x = q * y + r
30     */
31     if (y_arg.isZero())
32         throw new BigInt.DivideByZero();
33     BigInt y = y_arg.clone;
34     const size_t y_words = y.sigWords();
35     
36     BigInt r = x.clone;
37     BigInt q = 0;
38     
39     r.setSign(BigInt.Positive);
40     y.setSign(BigInt.Positive);
41     
42     int compare = r.cmp(y);
43     
44     if (compare == 0)
45     {
46         q = 1;
47         r = 0;
48     }
49     else if (compare > 0)
50     {
51         size_t shifts = 0;
52         word y_top = y.wordAt(y.sigWords()-1);
53         while (y_top < MP_WORD_TOP_BIT) { y_top <<= 1; ++shifts; }
54         y <<= shifts;
55         r <<= shifts;
56         
57         const size_t n = r.sigWords() - 1, t = y_words - 1;
58         if (n < t)
59             throw new InternalError("BigInt division word sizes");
60         
61         q.growTo(n - t + 1);
62         
63         word* q_words = q.mutablePtr();
64         
65         if (n <= t)
66         {
67             while (r > y) { r -= y; ++(q); }
68             r >>= shifts;
69             goto ret;
70         }
71         
72         BigInt shifted_y = y << (MP_WORD_BITS * (n-t));
73         
74         while (r >= shifted_y) { r -= shifted_y; q_words[n-t] += 1; }
75         
76         for (size_t j = n; j != t; --j)
77         {
78             const word x_j0  = r.wordAt(j);
79             const word x_j1 = r.wordAt(j-1);
80             const word x_j2 = r.wordAt(j-2);
81             const word y_t0  = y.wordAt(t);
82             const word y_t1  = y.wordAt(t-1);
83 
84             word qjt = (x_j0 == y_t0) ? MP_WORD_MAX : bigint_divop(x_j0, x_j1, y_t0);
85             
86             while (divisionCheck(qjt, y_t0, y_t1, x_j0, x_j1, x_j2))
87             {
88                 qjt -= 1;
89             }
90 
91             shifted_y >>= BOTAN_MP_WORD_BITS;
92             // Now shifted_y == y << (BOTAN_MP_WORD_BITS * (j-t-1))
93             r -= shifted_y * qjt;
94             if (r.isNegative()) {
95                 // overcorrected
96                 qjt -= 1;
97                 r += shifted_y;
98                 
99             }
100             q_words[j-t-1] = qjt;
101             
102         }
103         r >>= shifts;
104     }
105     
106 ret:
107     signFixup(x, y_arg, &q, &r);
108     *r_out = r.move();
109     *q_out = q.move();
110 }
111 
112 private:
113 /*
114 * Handle signed operands, if necessary
115 */
116 void signFixup(const(BigInt)* x, const(BigInt)* y, BigInt* q, BigInt* r)
117 {
118     if (x.sign() == BigInt.Negative)
119     {
120         q.flipSign();
121         if (r.isNonzero()) { --*q; *r = y.abs() - *r; }
122     }
123     if (y.sign() == BigInt.Negative)
124         q.flipSign();
125 }
126 
127 bool divisionCheck(word q, word y2, word y1, word x3, word x2, word x1)
128 {
129     // Compute (y3,y2,y1) = (y2,y1) * q
130     
131     word y3 = 0;
132     y1 = word_madd2(q, y1, &y3);
133     y2 = word_madd2(q, y2, &y3);
134 
135     // Return (y3,y2,y1) >? (x3,x2,x1)
136     
137     if (y3 > x3) return true;
138     if (y3 < x3) return false;
139     
140     if (y2 > x2) return true;
141     if (y2 < x2) return false;
142     
143     if (y1 > x1) return true;
144     if (y1 < x1) return false;
145     
146     return false;
147 }