diff --git a/mrbgems/mruby-bigint/core/bigint.c b/mrbgems/mruby-bigint/core/bigint.c index d0d460f84..95146a2a0 100644 --- a/mrbgems/mruby-bigint/core/bigint.c +++ b/mrbgems/mruby-bigint/core/bigint.c @@ -687,55 +687,86 @@ udiv(mrb_state *mrb, mpz_t *qq, mpz_t *rr, mpz_t *xx, mpz_t *yy) mp_dbl_limb z = y.p[yd-1]; if (xd>=yd) { for (size_t j=xd-yd;; j--) { - mp_dbl_limb_signed b=0; mp_dbl_limb qhat; - - - mp_dbl_limb rhat; if (j+yd == xd) { - // Treat missing high limb as 0 and use the same two-limb formula - qhat = (((mp_dbl_limb)0 << DIG_SIZE) + x.p[j+yd-1]) / z; - rhat = (((mp_dbl_limb)0 << DIG_SIZE) + x.p[j+yd-1]) % z; - } - else { - mp_dbl_limb dividend = ((mp_dbl_limb)x.p[j+yd] << DIG_SIZE) + x.p[j+yd-1]; + // Only one high limb available + mp_dbl_limb dividend = (((mp_dbl_limb)0 << DIG_SIZE) + x.p[j+yd-1]); qhat = dividend / z; rhat = dividend % z; } + else { + // Two limbs available - use enhanced estimation for better accuracy + mp_dbl_limb dividend = ((mp_dbl_limb)x.p[j+yd] << DIG_SIZE) + x.p[j+yd-1]; + qhat = dividend / z; + rhat = dividend % z; - // Knuth's qhat refinement step - essential to prevent overestimation + // Three-limb pre-adjustment when available (reduces correction iterations) + if (yd >= 2 && j+yd-2 < x.sz && y.p[yd-2] != 0) { + mp_dbl_limb y_second = y.p[yd-2]; + mp_dbl_limb x_third = x.p[j+yd-2]; + + // Pre-check: if qhat * y_second > rhat * base + x_third, reduce qhat + if (qhat > 0) { + mp_dbl_limb left = qhat * y_second; + mp_dbl_limb right = (rhat << DIG_SIZE) + x_third; + + if (qhat >= ((mp_dbl_limb)1 << DIG_SIZE) || left > right) { + qhat--; + rhat += z; + // Note: This pre-adjustment reduces work in the refinement loop + } + } + } + } + + // Enhanced qhat refinement step - reduced redundant calculations if (yd > 1) { // Apply refinement for all iterations, including j=0 - mp_dbl_limb left_side = qhat * y.p[yd-2]; - mp_dbl_limb right_side = (rhat << DIG_SIZE) + (j+yd-2 < x.sz ? x.p[j+yd-2] : 0); + mp_dbl_limb y_second = y.p[yd-2]; + mp_dbl_limb x_third = (j+yd-2 < x.sz) ? x.p[j+yd-2] : 0; + mp_dbl_limb left_side = qhat * y_second; + mp_dbl_limb right_side = (rhat << DIG_SIZE) + x_third; while (qhat >= ((mp_dbl_limb)1 << DIG_SIZE) || (left_side > right_side)) { qhat--; rhat += z; if (rhat >= ((mp_dbl_limb)1 << DIG_SIZE)) break; - left_side = qhat * y.p[yd-2]; - right_side = (rhat << DIG_SIZE) + (j+yd-2 < x.sz ? x.p[j+yd-2] : 0); + left_side -= y_second; // Optimized: subtract instead of multiply + right_side = (rhat << DIG_SIZE) + x_third; } } - if (qhat) { + if (qhat > 0) { + // Optimized subtraction: x -= qhat * y + mp_dbl_limb_signed borrow = 0; size_t i; - for (i=0; i 0) { + x.p[i+j] += (mp_limb)carry; + } } - b += c; } q.p[j] = (mp_limb)qhat; if (j == 0) break;