// x = x/R mod m (HAC 14.32) public void reduce(BigInteger x) { if (x == null) { return; } while (x.t <= this.mt2) { // pad x so am has enough room later x.SetData(x.t++, 0); } for (int i = 0; i < this.m.t; ++i) { // faster way of calculating u0 = x[i]*mp mod DV int j = x.datas[i] & 0x7fff; int u0 = (j * this.mpl + (((j * this.mph + (x.datas[i] >> 15) * this.mpl) & this.um) << 15)) & x.DM; // use am to combine the multiply-shift-add into one call j = i + this.m.t; x.datas[j] += this.m.am(0, u0, x.datas, i, 0, this.m.t); // propagate carry while (x.datas[j] >= x.DV) { x.datas[j] -= x.DV; x.datas[++j]++; } } x.clamp(); x.drShiftTo(this.m.t, x); if (x.compareTo(this.m) >= 0) { x.subTo(this.m, x); } }
// (protected) divide this by m, quotient and remainder to q, r (HAC 14.20) // r != q, this != m. q or r may be null. public void divRemTo(BigInteger m, BigInteger q, BigInteger r) { if (m == null) { return; } if (q == null) { q = new BigInteger(); } if (r == null) { r = new BigInteger(); } BigInteger pm = m.abs(); if (pm.t <= 0) { return; } BigInteger pt = this.abs(); if (pt.t < pm.t) { if (q != null) { q.fromInt(0); } if (r != null) { this.copyTo(r); } return; } BigInteger y = new BigInteger(); int ts = this.s, ms = m.s; int nsh = this.DB - nbits(pm.datas[pm.t - 1]); // normalize modulus if (nsh > 0) { pm.lShiftTo(nsh, y); pt.lShiftTo(nsh, r); } else { pm.copyTo(y); pt.copyTo(r); } int ys = y.t; int y0 = y.datas[ys - 1]; if (y0 == 0) { return; } long yt = (long)y0 * (1 << this.F1) + ((ys > 1) ? y.datas[ys - 2] >> this.F2 : 0); double d1 = (double)this.FV / yt; double d2 = (double)((long)1 << this.F1) / yt; int e = 1 << this.F2; int i = r.t, j = i - ys; BigInteger t = (q == null) ? new BigInteger() : q; y.dlShiftTo(j, t); if (r.compareTo(t) >= 0) { r.SetData(r.t++, 1); r.subTo(t, r); } ONE.dlShiftTo(ys, t); t.subTo(y, y); // "negative" y so we can replace sub with am later while (y.t < ys) { y.SetData(y.t++, 0); } while (--j >= 0) { // Estimate quotient digit int qd = (r.datas[--i] == y0) ? this.DM : Convert.ToInt32(Math.Floor((double)r.datas[i] * d1 + (double)(r.datas[i - 1] + e) * d2)); int tmp = y.am(0, qd, r.datas, j, 0, ys); if ((r.datas[i] += tmp) < qd) { // Try it out y.dlShiftTo(j, t); r.subTo(t, r); while (r.datas[i] < --qd) { r.subTo(t, r); } } } if (q != null) { r.drShiftTo(ys, q); if (ts != ms) { ZERO.subTo(q, q); } } r.t = ys; r.clamp(); if (nsh > 0) { r.rShiftTo(nsh, r); // Denormalize remainder } if (ts < 0) { ZERO.subTo(r, r); } }