1 module dkh.fastdiv;
2 
3 import dkh.foundation, dkh.int128;
4 
5 /**
6 Barrett reductionを使用し、高速除算を行う。
7 ulongをこれで置き換えれば大体うまく動く。
8  */
9 struct FastDivULong {
10     const ulong value, m;
11     const int lg;
12     this(ulong value) {
13         import core.bitop : bsr;
14         this.value = value;
15         assert(value);
16         if (value <= 1) return;
17         int _lg = value.bsr;
18         if (1UL<<_lg != value) _lg++;
19         lg = _lg;
20         m = div128([0UL, (2UL<<(lg-1))-value], value)+1;
21     }
22     ulong opBinaryRight(string op:"/")(ulong x) const {
23         if (value == 1) return x;
24         ulong r;
25         r = mul128(m, x)[1];
26         r = (r + ((x-r)>>1)) >> (lg-1);
27         return r;
28     }
29     ulong opBinaryRight(string op:"%")(ulong x) const {
30         return x - (x/this)*value;
31     }
32 }
33 
34 ///
35 unittest {
36     assert(11 / FastDivULong(3) == 3);
37     assert(11 % FastDivULong(3) == 2);
38 }
39 
40 unittest {
41     ulong[] up;
42     ulong[] down;
43     up ~= 0;
44     foreach (ulong i; 1..1000) {
45         up ~= i;
46         up ~= -i;
47     }
48     foreach (ulong i; 1..1000) {
49         down ~= i;
50         down ~= -i;
51     }
52     foreach (ulong i; down) {
53         auto b = FastDivULong(i);
54         foreach (ulong j; up) {
55             assert(j/b == j/i);
56             assert(j%b == j%i);
57         }
58     }
59 }