Welcome to collectivesolver - Programming & Software Q&A with code examples. A website with trusted programming answers. All programs are tested and work.

Contact: aviboots(AT)netvision.net.il

Semrush - keyword research tool

Turn ChatGPT, Claude, Gemini, And CoPilot Into Your Personal Assistant, Business Coach, Content Creator, And More

AFFILIATE MARKETING Your all-in-one performance engine Manage affiliates, creators, and customer referrals in one unified platform—turning every partnership into measurable growth
Secure & Reliable Web Hosting, Free Domain, Free SSL, 1-Click WordPress Install, Expert 24/7 Support

Boost your online presence with premium web hosting and servers

Disclosure: My content contains affiliate links.

42,752 questions

55,516 answers

573 users

How to do modulo multiplication for 64‑bit values without using BigInteger in C++

1 Answer

0 votes
#include <iostream>
#include <cstdint>

/*
    ================================================================
    Modulo Multiplication (Slow and Fast Versions)
    ================================================================

    Goal:
        Compute (a * b) % mod safely for large 64‑bit values
        without using BigInteger.

    Why two versions?
        1. Slow version:
            - Conceptually simple.
            - Adds 'b' to the result 'a' times.
            - Always correct, but extremely slow for large numbers.
            - Useful as a "ground truth" reference.

        2. Fast version:
            - Uses the classic "double‑and‑add" technique.
            - Runs in O(log b) time.
            - Must use __uint128_t internally to avoid overflow.
            - Produces the same correct result as the slow version.

    ================================================================
*/


// ---------------------------------------------------------------
// SLOW VERSION (always correct, but very slow)
// ---------------------------------------------------------------
std::uint64_t mul_mod_slow(std::uint64_t a, std::uint64_t b, std::uint64_t mod) {
    /*
        This version literally performs:

            result = (b + b + b + ... a times) % mod

        It never overflows because:
            - result stays below mod
            - b fits in uint64_t
            - addition is safe

        But it is O(a), which is far too slow for large inputs.
    */

    if (b < a)
        std::swap(a, b);  // reduce number of loop iterations

    std::uint64_t result = 0;

    for (std::uint64_t i = 0; i < a; i++) {
        result += b;
        result %= mod;
    }

    return result;
}


// ---------------------------------------------------------------
// FAST VERSION (efficient and safe using __uint128_t)
// ---------------------------------------------------------------
std::uint64_t mul_mod_fast(std::uint64_t a, std::uint64_t b, std::uint64_t mod) {
    /*
        This version uses the "double‑and‑add" method:

            - If the lowest bit of b is set, add 'a' to result.
            - Double 'a' each step.
            - Shift b right each step.

        The key improvement:
            Use __uint128_t for intermediate values so that
            doubling 'a' never overflows.

        This makes the algorithm:
            - Fast: O(log b)
            - Safe: no overflow
            - Exact: matches slow version
    */

    __uint128_t A = a;
    __uint128_t B = b;
    __uint128_t M = mod;

    __uint128_t result = 0;

    while (B > 0) {
        if (B & 1)
            result = (result + A) % M;

        A = (A << 1) % M;
        B >>= 1;
    }

    return static_cast<std::uint64_t>(result);
}


// ---------------------------------------------------------------
// MAIN PROGRAM
// ---------------------------------------------------------------
int main() {
    std::uint64_t x   = 798345ULL;
    std::uint64_t y   = 20289473612815ULL;
    std::uint64_t mod = 100000000000003ULL;

    std::uint64_t slow_result = mul_mod_slow(x, y, mod);
    std::uint64_t fast_result = mul_mod_fast(x, y, mod);

    std::cout << "Slow result: " << slow_result << "\n";
    std::cout << "Fast result: " << fast_result << "\n";
}


/*
run:

Slow result: 99811422305238
Fast result: 99811422305238

*/

 



answered 21 hours ago by avibootz
edited 21 hours ago by avibootz

Related questions

...