Search code examples
c++modulusinteger-overflowlargenumber

Errors involving precedence of modulus operator and brackets with large numbers in C++


The first part of the just computes some mathematical formula, stroed in ans1, ans2 and ans3. Many sites give % and * as having the same priority in the precedence order. Should we then consider them left to right in an expression? Only difference between line 56 and 57 is the order in which the terms in the product have used and also an addition pair of brackets are being used. I don't understand how this makes a difference to the final result.

#include <iostream>

using namespace std;

#define mod 998244353

int main()
{
int ans1 = 672510887; // These are the outputs for the previous part of the program
int ans2 = 814503527;
int ans3 = 71242790;

cout << ans1%mod << endl; // Returns the same number for all three as they are lesser than mod
cout << ans2%mod << endl;
cout << ans3%mod << endl;
cout << 1LL*ans1*ans2*ans3 << endl; // 4021307808285681478
cout << 1LL * ( 1LL * ans1%mod * ans2%mod)%mod << endl; // 313818575
cout << (1LL * 672510887 * 313818575)%mod << endl; // 873911579
cout << (1LL * ((1LL * ans2 * ans3)%mod) * ans1) % mod << endl; // 414849507
cout << (1LL * ans1 * (1LL * ans2 * ans3)%mod) % mod << endl; // 935539465
cout << (1LL * ans1 * ((1LL * ans2 * ans3)%mod)) % mod << endl; // 414849507
cout <<  (5 * (3 * 4)%8)%8 << ' ' << (5 * ((3 * 4)%8))%8 << endl; // 4 4
}

Solution

  • The * and % have equal precedence and left-right associative. So an expression like a * b%c * d means ((a * b) % c) * d).

    // Undefined behaviour: integer overflow
    cout << 1LL*ans1*ans2*ans3 << endl;
    
    // Works out ans1 x ans2 (modulo mod) correctly
    cout << 1LL * ( 1LL * ans1%mod * ans2%mod)%mod << endl;
    
    // Works out ans1 x ans1 x ans2 (modulo mod) correctly
    cout << (1LL * 672510887 * 313818575)%mod << endl;
    
    // Works out ans1 x ans2 x ans3 (modulo mod) correctly
    cout << (1LL * ((1LL * ans2 * ans3)%mod) * ans1) % mod << endl;
    
    // Undefined behaviour due to integer overflow: ans1*ans2*ans3 occurs before the mod
    cout << (1LL * ans1 * (1LL * ans2 * ans3)%mod) % mod << endl;
    
    // Works out ans1 x ans2 x ans3 (modulo mod) correctly
    cout << (1LL * ans1 * ((1LL * ans2 * ans3)%mod)) % mod << endl;
    

    Not sure what the purpose of the last line was; (5 * (3 * 4)%8)%8 means (5*3*4)%8 as explained above. Which coincidentally to give the same result as (5 * ((3*4)%8))%8 for these specific values.