diff --git a/lib/mini-gmp.c b/lib/mini-gmp.c index 9168d98667..8d79019df6 100644 --- a/lib/mini-gmp.c +++ b/lib/mini-gmp.c @@ -4285,8 +4285,39 @@ mpz_sizeinbase (const mpz_t u, int base) return (bits + 3) / 4; case 32: return (bits + 4) / 5; - /* FIXME: Do something more clever for the common case of base - 10. */ + } + + if (GMP_LIMB_BITS >= 32 && bits <= (1UL << 30)) + { + /* ceil (2^32 / log2 (base)) (rounded up), + for bases 3 through 62. */ + static const unsigned long log2_inverse[] = { + 2709822658, /*done*/0, 1849741733, 1661520156, + 1529898220, /*done*/0, 1354911329, 1292913987, + 1241523976, 1198050830, 1160664036, 1128071164, + 1099331346, /*done*/0, 1050766078, 1029986702, + 1011073585, 993761859, 977836273, 963119892, + 949465784, 936750802, 924870867, 913737343, + 903274220, 893415895, 884105414, 875293063, + 866935226, /*done*/0, 851433730, 844225783, + 837342624, 830760078, 824456425, 818412085, + 812609357, 807032192, 801666002, 796497491, + 791514512, 786705943, 782061578, 777572033, + 773228661, 769023480, 764949110, 760998713, + 757165946, 753444911, 749830123, 746316465, + 742899164, 739573757, 736336068, 733182184, + 730108433, 727111368, 724187745, 721334514, + }; + mp_limb_t hi, lo; + int shift = (int) GMP_LIMB_BITS - 32; + + /* With bits <= 2^30, coefficient rounding adds less than 1/4 + digit. The bit-length estimate adds at most 1/log2(3), + and 1/4 + 1/log2(3) < 1, ensuring at most one extra digit. */ + gmp_umul_ppmm (hi, lo, (mp_limb_t) bits, + (mp_limb_t) log2_inverse[base - 3] << shift); + (void) lo; + return 1 + hi; } tp = gmp_alloc_limbs (un);