This is a special case, especially if you have not indicated which platforms you are looking for, but with GCC you can use the so-called mode (TI) to receive (synthesized) 128-bit operations, for example:
typedef unsigned int uint128_t __attribute__((mode(TI))); uint64_t x = 0xABCDEF01234568; uint64_t y = ~x; uint128_t result = ((uint128_t) x * y); printf("%016llX * %016llX -> ", x, y); uint64_t r1 = (result >> 64); uint64_t r2 = result; printf("%016llX %016llX\n", r1, r2);
This only works on 64-bit processors.
One way or another, you are looking at multiple arithmetic of accuracy to solve this problem. mode (TI) will force the compiler to generate operations for you, otherwise they must be written explicitly.
You can use the generic bigint package; in C ++ I know that include LiDIA and NTL number theory packages and bigint packages used for cryptographic code in Crypto ++ and Botan ). Plus, of course, there is GnuMP , which is the canonical C MPI library (and it also has a C ++ wrapper, although it seemed poorly documented the last time I looked at it). All of them are designed for quick operation, but they are also probably configured for larger (1000+ bits) numbers, so for 128 bits you can deal with a lot of overhead. (On the other hand, you donβt say if it matters or not). And all of them (unlike the bigint-cpp package, which is the GPL, are either BSD or LGPL) - not sure if this matters, but it can make a big difference.
You can also write your own type uint128_t; usually, such a class will implement the same algorithms as a regular MPI class, just hard-coded to have only 2 or 4 elements. If you're curious about how to implement such algorithms, a good reference is Chapter 14 of the Applied Cryptography Reference
Of course, doing it manually is easier if you really don't need all the arithmetic operations (division and modulation, in particular, a rather difficult task). For example, if you just need to keep track of a counter that can hypothetically overflow 64 bits, you could simply imagine it as a pair of long 64-bit lengths and perform the manual transfer:
unsigned long long ctrs[2] = { 0 }; void increment() { ++ctrs[0]; if(!ctrs[0])
Which, of course, will be much easier to deal with the common MPI package or with the regular uint128_t class.