1

I want to do this with a 128 bit integer using g++ and GMP's mpz_class (or mpz_t):

typedef unsigned __int128 tw_limb_t;

mpz_class a = "1234567890123456789012345678901234567890";
tw_limb_t b = ...;
a += b;

I can do the following, but it seems slow to first convert the __int128 to mpz_t:

typedef unsigned __int128 tw_limb_t;

inline mpz_class& operator+=(mpz_class &lhs, const tw_limb_t &rhs) {
    if (sizeof(tw_limb_t) != 2 * sizeof(mp_limb_t)) {
        throw std::runtime_error("sizeof(tw_limb_t) is not twice sizeof(mp_limb_t)");
    }

    const int LIMB_BITLEN = sizeof(mp_limb_t) * 8;

    mpz_class rhs_mpz = (mp_limb_t) (rhs >> LIMB_BITLEN);
    rhs_mpz <<= LIMB_BITLEN;
    rhs_mpz += (mp_limb_t) rhs;

    lhs += rhs_mpz;

    return lhs;
}

How to get more performance out of this?

Daniel S.
  • 6,458
  • 4
  • 35
  • 78

1 Answers1

1

This is my current best solution using mpz_roinit_n as suggested by Marc Glisse.

typedef unsigned __int128 tw_limb_t;

inline mpz_class& operator+=(mpz_class &lhs, const tw_limb_t &rhs) {
    if (sizeof(tw_limb_t) != 2 * sizeof(mp_limb_t)) {
        throw std::runtime_error("sizeof(tw_limb_t) is not twice sizeof(mp_limb_t)");
    }

    mpz_t rhs_mpz;
    mpz_roinit_n(rhs_mpz, reinterpret_cast<const mp_limb_t*>(&rhs), 2);

    mpz_add(lhs.get_mpz_t(), lhs.get_mpz_t(), rhs_mpz);

    return lhs;
}

inline mpz_class operator+(mpz_class lhs, const tw_limb_t &rhs) {
    lhs += rhs;
    return lhs;
}
Daniel S.
  • 6,458
  • 4
  • 35
  • 78