Chcę pomnożyć dwie liczby 128-bitowe. Robię to tak:
__int128 a = (11400714819323198485 << 64) | 17554116967691831348;
__int128 b = (11400714819323198485 << 64) | 17554116967691831348;
__int128 wynik;
__int128 multhi(__int128 a, __int128 b)
{
__int128 a_lo = (uint64_t)a;
__int128 a_hi = a >> 64;
__int128 b_lo = (uint64_t)b;
__int128 b_hi = b >> 64;
__int128 a_x_b_hi = a_hi * b_hi;
__int128 a_x_b_mid = a_hi * b_lo;
__int128 b_x_a_mid = b_hi * a_lo;
__int128 a_x_b_lo = a_lo * b_lo;
__int128 carry_bit = ((__int128)(uint64_t)a_x_b_mid + (__int128)(uint64_t)b_x_a_mid + (a_x_b_lo >> 64)) >> 64;
__int128 multhi = a_x_b_hi + (a_x_b_mid >> 64) + (b_x_a_mid >> 64) + carry_bit;
return multhi;
}
int main()
{
wynik = multhi(a,b);
uint64_t Hi = a >> 64;
uint64_t Lo = (uint64_t)a;
std::cout << Hi << " " << Lo << "\n";
}
Ale wynik jest błędny. Dolne bity mnożą się właściwie i można je uzyskać poprzez pomnożenie a*b. Ale chodzi o wyższe 128-bitów. Cały wynik to: 44228642460293897567044858665937249460741554819946588830554614791049552939664, zaś górne 128 bitów to 129976298391535590297638237547755878347.
Nie rozumiem dlaczego wynik jest niewłaściwy, bo, gdy zmienimy zmienne na 64-bitowe, razem z przesunięciami (tak, jakbyśmy zakładali, że nie mamy do dyspozycji intów 128-bitowych), to funkcja działa prawidłowo. Więc ta sama funkcja dla intów 64-bitowych daje poprawne wyniki. Na czym polega problem?