You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
600 lines
13 KiB
600 lines
13 KiB
/*
|
|
uint128_t.h
|
|
An unsigned 128 bit integer library for C++
|
|
By Jason Lee @ calccrypto@yahoo.com
|
|
with much help from Auston Sterling
|
|
|
|
And thanks to Stefan Deigmüller for finding
|
|
a bug in operator*.
|
|
|
|
From http://calccrypto.wikidot.com/programming:uint128-t
|
|
Licenced http://creativecommons.org/licenses/by-sa/3.0/
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <cstdlib>
|
|
#include <iostream>
|
|
#include <stdint.h>
|
|
|
|
class uint128_t{
|
|
private:
|
|
uint64_t UPPER, LOWER;
|
|
|
|
public:
|
|
// Constructors
|
|
uint128_t(){
|
|
UPPER = 0;
|
|
LOWER = 0;
|
|
}
|
|
|
|
template <typename T>
|
|
uint128_t(T rhs){
|
|
UPPER = 0;
|
|
LOWER = (uint64_t) rhs;
|
|
}
|
|
|
|
template <typename S, typename T>
|
|
uint128_t(const S upper_rhs, const T lower_rhs){
|
|
UPPER = (uint64_t) upper_rhs;
|
|
LOWER = (uint64_t) lower_rhs;
|
|
}
|
|
|
|
uint128_t(const uint128_t & rhs){
|
|
UPPER = rhs.UPPER;
|
|
LOWER = rhs.LOWER;
|
|
}
|
|
|
|
// RHS input args only
|
|
|
|
// Assignment Operator
|
|
template <typename T> uint128_t operator=(T rhs){
|
|
UPPER = 0;
|
|
LOWER = (uint64_t) rhs;
|
|
return *this;
|
|
}
|
|
|
|
uint128_t operator=(uint128_t rhs){
|
|
UPPER = rhs.UPPER;
|
|
LOWER = rhs.LOWER;
|
|
return *this;
|
|
}
|
|
|
|
// Typecast Operators
|
|
operator bool(){
|
|
return (bool) (UPPER | LOWER);
|
|
}
|
|
|
|
operator char(){
|
|
return (char) LOWER;
|
|
}
|
|
|
|
operator int(){
|
|
return (int) LOWER;
|
|
}
|
|
|
|
operator uint8_t(){
|
|
return (uint8_t) LOWER;
|
|
}
|
|
|
|
operator uint16_t(){
|
|
return (uint16_t) LOWER;
|
|
}
|
|
|
|
operator uint32_t(){
|
|
return (uint32_t) LOWER;
|
|
}
|
|
|
|
operator uint64_t(){
|
|
return LOWER;
|
|
}
|
|
|
|
// Bitwise Operators
|
|
template <typename T> uint128_t operator&(T rhs){
|
|
return uint128_t(0, LOWER & (uint64_t) rhs);
|
|
}
|
|
|
|
uint128_t operator&(uint128_t rhs){
|
|
return uint128_t(UPPER & rhs.UPPER, LOWER & rhs.LOWER);
|
|
}
|
|
|
|
template <typename T> uint128_t operator|(T rhs){
|
|
return uint128_t(UPPER, LOWER | (uint64_t) rhs);
|
|
}
|
|
|
|
uint128_t operator|(uint128_t rhs){
|
|
return uint128_t(UPPER | rhs.UPPER, LOWER | rhs.LOWER);
|
|
}
|
|
|
|
template <typename T> uint128_t operator^(T rhs){
|
|
return uint128_t(UPPER, LOWER ^ (uint64_t) rhs);
|
|
}
|
|
|
|
uint128_t operator^(uint128_t rhs){
|
|
return uint128_t(UPPER ^ rhs.UPPER, LOWER ^ rhs.LOWER);
|
|
}
|
|
|
|
template <typename T> uint128_t operator&=(T rhs){
|
|
UPPER = 0;
|
|
LOWER &= rhs;
|
|
return *this;
|
|
}
|
|
|
|
uint128_t operator&=(uint128_t rhs){
|
|
UPPER &= rhs.UPPER;
|
|
LOWER &= rhs.LOWER;
|
|
return *this;
|
|
}
|
|
|
|
template <typename T> uint128_t operator|=(T rhs){
|
|
LOWER |= (uint64_t) rhs;
|
|
return *this;
|
|
}
|
|
|
|
uint128_t operator|=(uint128_t rhs){
|
|
UPPER |= rhs.UPPER;
|
|
LOWER |= rhs.LOWER;
|
|
return *this;
|
|
}
|
|
|
|
template <typename T> uint128_t operator^=(T rhs){
|
|
LOWER ^= (uint64_t) rhs;
|
|
return *this;
|
|
}
|
|
|
|
uint128_t operator^=(const uint128_t rhs){
|
|
UPPER ^= rhs.UPPER;
|
|
LOWER ^= rhs.LOWER;
|
|
return *this;
|
|
}
|
|
|
|
uint128_t operator~(){
|
|
return uint128_t(~UPPER, ~LOWER);
|
|
}
|
|
|
|
// Bit Shift Operators
|
|
template <typename T>
|
|
uint128_t operator<<(const T shift){
|
|
if (shift >= 128)
|
|
return uint128_t(0, 0);
|
|
else if (shift == 64)
|
|
return uint128_t(LOWER, 0);
|
|
else if (shift == 0)
|
|
return *this;
|
|
else if (shift < 64)
|
|
return uint128_t((UPPER << shift) + (LOWER >> (64 - shift)), LOWER << shift);
|
|
else if ((128 > shift) && (shift > 64))
|
|
return uint128_t(LOWER << (shift - 64), 0);
|
|
else
|
|
return uint128_t(0);
|
|
}
|
|
|
|
template <typename T>
|
|
uint128_t operator>>(const T shift){
|
|
if (shift >= 128)
|
|
return uint128_t(0, 0);
|
|
else if (shift == 64)
|
|
return uint128_t(0, UPPER);
|
|
else if (shift == 0)
|
|
return *this;
|
|
else if (shift < 64)
|
|
return uint128_t(UPPER >> shift, (UPPER << (64 - shift)) + (LOWER >> shift));
|
|
else if ((128 > shift) && (shift > 64))
|
|
return uint128_t(0, (UPPER >> (shift - 64)));
|
|
else
|
|
return uint128_t(0);
|
|
}
|
|
|
|
uint128_t operator<<=(int shift){
|
|
*this = *this << shift;
|
|
return *this;
|
|
}
|
|
|
|
uint128_t operator>>=(int shift){
|
|
*this = *this >> shift;
|
|
return *this;
|
|
}
|
|
|
|
// Logical Operators
|
|
bool operator!(){
|
|
return !(bool) (UPPER | LOWER);
|
|
}
|
|
|
|
template <typename T> bool operator&&(T rhs){
|
|
return (bool) *this && rhs;
|
|
}
|
|
|
|
template <typename T> bool operator&&(uint128_t rhs){
|
|
return (bool) *this && (bool) rhs;
|
|
}
|
|
|
|
template <typename T> bool operator||(T rhs){
|
|
return ((bool) *this) || rhs;
|
|
|
|
}
|
|
|
|
template <typename T> bool operator||(uint128_t rhs){
|
|
return ((bool) *this) || (bool) rhs;
|
|
}
|
|
|
|
// Comparison Operators
|
|
template <typename T> bool operator==(T rhs){
|
|
return (!UPPER && (LOWER == (uint64_t) rhs));
|
|
}
|
|
|
|
bool operator==(uint128_t rhs){
|
|
return ((UPPER == rhs.UPPER) && (LOWER == rhs.LOWER));
|
|
}
|
|
|
|
template <typename T> bool operator!=(T rhs){
|
|
return (UPPER | (LOWER != (uint64_t) rhs));
|
|
}
|
|
|
|
bool operator!=(uint128_t rhs){
|
|
return ((UPPER != rhs.UPPER) | (LOWER != rhs.LOWER));
|
|
}
|
|
|
|
template <typename T> bool operator>(T rhs){
|
|
if (UPPER)
|
|
return true;
|
|
return (LOWER > (uint64_t) rhs);
|
|
}
|
|
|
|
bool operator>(uint128_t rhs){
|
|
if (UPPER == rhs.UPPER)
|
|
return (LOWER > rhs.LOWER);
|
|
if (UPPER > rhs.UPPER)
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
template <typename T> bool operator<(T rhs){
|
|
if (!UPPER)
|
|
return (LOWER < (uint64_t) rhs);
|
|
return false;
|
|
}
|
|
|
|
bool operator<(uint128_t rhs){
|
|
if (UPPER == rhs.UPPER)
|
|
return (LOWER < rhs.LOWER);
|
|
if (UPPER < rhs.UPPER)
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
template <typename T> bool operator>=(T rhs){
|
|
return ((*this > rhs) | (*this == rhs));
|
|
}
|
|
|
|
bool operator>=(uint128_t rhs){
|
|
return ((*this > rhs) | (*this == rhs));
|
|
}
|
|
|
|
template <typename T> bool operator<=(T rhs){
|
|
return ((*this < rhs) | (*this == rhs));
|
|
}
|
|
|
|
bool operator<=(uint128_t rhs){
|
|
return ((*this < rhs) | (*this == rhs));
|
|
}
|
|
|
|
// Arithmetic Operators
|
|
template <typename T> uint128_t operator+(T rhs){
|
|
return uint128_t(UPPER + ((LOWER + (uint64_t) rhs) < LOWER), LOWER + (uint64_t) rhs);
|
|
}
|
|
|
|
uint128_t operator+(uint128_t rhs){
|
|
return uint128_t(rhs.UPPER + UPPER + ((LOWER + rhs.LOWER) < LOWER), LOWER + rhs.LOWER);
|
|
}
|
|
|
|
template <typename T> uint128_t operator+=(T rhs){
|
|
UPPER = UPPER + ((LOWER + rhs) < LOWER);
|
|
LOWER = LOWER + rhs;
|
|
return *this;
|
|
}
|
|
|
|
uint128_t operator+=(uint128_t rhs){
|
|
UPPER = rhs.UPPER + UPPER + ((LOWER + rhs.LOWER) < LOWER);
|
|
LOWER = LOWER + rhs.LOWER;
|
|
return *this;
|
|
}
|
|
|
|
template <typename T> uint128_t operator-(T rhs){
|
|
return uint128_t((uint64_t) (UPPER - ((LOWER - rhs) > LOWER)), (uint64_t) (LOWER - rhs));
|
|
}
|
|
|
|
uint128_t operator-(uint128_t rhs){
|
|
return uint128_t(UPPER - rhs.UPPER - ((LOWER - rhs.LOWER) > LOWER), LOWER - rhs.LOWER);
|
|
}
|
|
|
|
template <typename T> uint128_t operator-=(T rhs){
|
|
*this = *this - rhs;
|
|
return *this;
|
|
}
|
|
|
|
uint128_t operator-=(uint128_t rhs){
|
|
*this = *this - rhs;
|
|
return *this;
|
|
}
|
|
|
|
template <typename T> uint128_t operator*(T rhs){
|
|
return *this * uint128_t(rhs);
|
|
}
|
|
|
|
uint128_t operator*(uint128_t rhs){
|
|
// split values into 4 32-bit parts
|
|
uint64_t top[4] = {UPPER >> 32, UPPER % 0x100000000ULL, LOWER >> 32, LOWER % 0x100000000ULL};
|
|
uint64_t bottom[4] = {rhs.upper() >> 32, rhs.upper() % 0x100000000ULL, rhs.lower() >> 32, rhs.lower() % 0x100000000ULL};
|
|
uint64_t products[4][4];
|
|
|
|
for(int y = 3; y > -1; y--)
|
|
for(int x = 3; x > -1; x--){
|
|
products[3 - x][y] = top[x] * bottom[y];
|
|
}
|
|
|
|
// initial row
|
|
uint64_t fourth32 = products[0][3] % 0x100000000ULL;
|
|
uint64_t third32 = products[0][2] % 0x100000000ULL + (products[0][3] >> 32);
|
|
uint64_t second32 = products[0][1] % 0x100000000ULL + (products[0][2] >> 32);
|
|
uint64_t first32 = products[0][0] % 0x100000000ULL + (products[0][1] >> 32);
|
|
|
|
// second row
|
|
third32 += products[1][3] % 0x100000000ULL;
|
|
second32 += (products[1][2] % 0x100000000ULL) + (products[1][3] >> 32);
|
|
first32 += (products[1][1] % 0x100000000ULL) + (products[1][2] >> 32);
|
|
|
|
// third row
|
|
second32 += products[2][3] % 0x100000000ULL;
|
|
first32 += (products[2][2] % 0x100000000ULL) + (products[2][3] >> 32);
|
|
|
|
// fourth row
|
|
first32 += products[3][3] % 0x100000000ULL;
|
|
|
|
// combines the values, taking care of carry over
|
|
return uint128_t(first32 << 32, 0) + uint128_t(third32 >> 32, third32 << 32) + uint128_t(second32, 0) + uint128_t(fourth32);
|
|
}
|
|
|
|
template <typename T> uint128_t operator*=(T rhs){
|
|
*this = *this * uint128_t(rhs);
|
|
return *this;
|
|
}
|
|
|
|
uint128_t operator*=(uint128_t rhs){
|
|
*this = *this * rhs;
|
|
return *this;
|
|
}
|
|
|
|
template <typename T> uint128_t operator/(T rhs){
|
|
return *this / uint128_t(rhs);
|
|
}
|
|
|
|
uint128_t operator/(uint128_t rhs){
|
|
// Save some calculations /////////////////////
|
|
if (rhs == 0){
|
|
std::cout << "Error: division or modulus by zero" << std::endl;
|
|
exit(1);
|
|
}
|
|
if (rhs == 1)
|
|
return *this;
|
|
if (*this == rhs)
|
|
return uint128_t(1);
|
|
if ((*this == 0) | (*this < rhs))
|
|
return uint128_t(0);
|
|
// Checks for divisors that are powers of two
|
|
uint16_t s = 0;
|
|
uint128_t copyd(rhs);
|
|
while ((copyd.LOWER & 1) == 0){
|
|
copyd >>= 1;
|
|
s++;
|
|
}
|
|
if (copyd == 1)
|
|
return *this >> s;
|
|
////////////////////////////////////////////////
|
|
uint128_t copyn(*this), quotient = 0;
|
|
while (copyn >= rhs){
|
|
uint128_t copyd(rhs), temp(1);
|
|
// shift the divsor to match the highest bit
|
|
while ((copyn >> 1) > copyd){
|
|
copyd <<= 1;
|
|
temp <<= 1;
|
|
}
|
|
copyn -= copyd;
|
|
quotient += temp;
|
|
}
|
|
return quotient;
|
|
}
|
|
|
|
template <typename T> uint128_t operator/=(T rhs){
|
|
*this = *this / uint128_t(rhs);
|
|
return *this;
|
|
}
|
|
|
|
uint128_t operator/=(uint128_t rhs){
|
|
*this = *this / rhs;
|
|
return *this;
|
|
}
|
|
|
|
template <typename T> uint128_t operator%(T rhs){
|
|
return *this - (rhs * (*this / rhs));
|
|
}
|
|
|
|
uint128_t operator%(uint128_t rhs){
|
|
return *this - (rhs * (*this / rhs));
|
|
}
|
|
|
|
template <typename T> uint128_t operator%=(T rhs){
|
|
*this = *this % uint128_t(rhs);
|
|
return *this;
|
|
}
|
|
|
|
uint128_t operator%=(uint128_t rhs){
|
|
*this = *this % rhs;
|
|
return *this;
|
|
}
|
|
|
|
// Increment Operator
|
|
uint128_t operator++(){
|
|
*this += 1;
|
|
return *this;
|
|
}
|
|
|
|
uint128_t operator++(int){
|
|
uint128_t temp(*this);
|
|
++*this;
|
|
return temp;
|
|
}
|
|
|
|
// Decrement Operator
|
|
uint128_t operator--(){
|
|
*this -= 1;
|
|
return *this;
|
|
}
|
|
|
|
uint128_t operator--(int){
|
|
uint128_t temp(*this);
|
|
--*this;
|
|
return temp;
|
|
}
|
|
|
|
// get private values
|
|
uint64_t upper(){
|
|
return UPPER;
|
|
}
|
|
|
|
uint64_t lower(){
|
|
return LOWER;
|
|
}
|
|
};
|
|
// lhs type T as first arguemnt
|
|
|
|
// Bitwise Operators
|
|
template <typename T> T operator&(T lhs, uint128_t rhs){
|
|
T out = lhs & (T) rhs.lower();
|
|
return out;
|
|
}
|
|
|
|
template <typename T> T operator|(T lhs, uint128_t rhs){
|
|
T out = lhs | (T) rhs.lower();
|
|
return out;
|
|
}
|
|
|
|
template <typename T> T operator^(T lhs, uint128_t rhs){
|
|
T out = lhs ^ (T) rhs.lower();
|
|
return out;
|
|
}
|
|
|
|
template <typename T> T operator&=(T & lhs, uint128_t rhs){
|
|
lhs &= (T) rhs.lower();
|
|
return lhs;
|
|
}
|
|
|
|
template <typename T> T operator|=(T & lhs, uint128_t rhs){
|
|
lhs |= (T) rhs.lower();
|
|
return lhs;
|
|
}
|
|
|
|
template <typename T> T operator^=(T & lhs, uint128_t rhs){
|
|
lhs ^= (T) rhs.lower();
|
|
return lhs;
|
|
}
|
|
|
|
// Comparison Operators
|
|
template <typename T> bool operator==(T lhs, uint128_t rhs){
|
|
return (!rhs.upper() && ((uint64_t) lhs == rhs.lower()));
|
|
}
|
|
|
|
template <typename T> bool operator!=(T lhs, uint128_t rhs){
|
|
return (rhs.upper() | ((uint64_t) lhs != rhs.lower()));
|
|
}
|
|
|
|
template <typename T> bool operator>(T lhs, uint128_t rhs){
|
|
if (rhs.upper())
|
|
return false;
|
|
return ((uint64_t) lhs > rhs.lower());
|
|
}
|
|
|
|
template <typename T> bool operator<(T lhs, uint128_t rhs){
|
|
if (rhs.upper())
|
|
return true;
|
|
return ((uint64_t) lhs < rhs.lower());
|
|
}
|
|
|
|
template <typename T> bool operator>=(T lhs, uint128_t rhs){
|
|
if (rhs.upper())
|
|
return false;
|
|
return ((uint64_t) lhs >= rhs.lower());
|
|
}
|
|
|
|
template <typename T> bool operator<=(T lhs, uint128_t rhs){
|
|
if (rhs.upper())
|
|
return true;
|
|
return ((uint64_t) lhs <= rhs.lower());
|
|
}
|
|
|
|
// Arithmetic Operators
|
|
template <typename T> T operator+(T lhs, uint128_t rhs){
|
|
return (T) (rhs + lhs);
|
|
}
|
|
|
|
template <typename T> T & operator+=(T & lhs, uint128_t rhs){
|
|
lhs = (T) (rhs + lhs);
|
|
return lhs;
|
|
}
|
|
|
|
template <typename T> T operator-(T lhs, uint128_t rhs){
|
|
return (T) (rhs - lhs);
|
|
}
|
|
|
|
template <typename T> T & operator-=(T & lhs, uint128_t rhs){
|
|
lhs = (T) (rhs - lhs);
|
|
return lhs;
|
|
}
|
|
|
|
template <typename T> T operator*(T lhs, uint128_t rhs){
|
|
return lhs * rhs.lower();
|
|
}
|
|
|
|
template <typename T> T & operator*=(T & lhs, uint128_t rhs){
|
|
lhs = (T) (rhs.lower() * lhs);
|
|
return lhs;
|
|
}
|
|
|
|
template <typename T> T operator/(T lhs, uint128_t rhs){
|
|
return (T) (uint128_t(lhs) / rhs);
|
|
}
|
|
|
|
template <typename T> T & operator/=(T & lhs, uint128_t rhs){
|
|
lhs = (T) (uint128_t(lhs) / rhs);
|
|
return lhs;
|
|
}
|
|
|
|
template <typename T> T operator%(T lhs, uint128_t rhs){
|
|
return (T) (uint128_t(lhs) % rhs);
|
|
}
|
|
|
|
template <typename T> T & operator%=(T & lhs, uint128_t rhs){
|
|
lhs = (T) (uint128_t(lhs) % rhs);
|
|
return lhs;
|
|
}
|
|
|
|
// IO Operator
|
|
inline std::ostream & operator<<(std::ostream & stream, uint128_t rhs){
|
|
std::string out = "";
|
|
if (rhs == 0)
|
|
out = "0";
|
|
else {
|
|
int div = 10;
|
|
if (stream.flags() & stream.oct)
|
|
div = 8;
|
|
if (stream.flags() & stream.dec)
|
|
div = 10;
|
|
if (stream.flags() & stream.hex)
|
|
div = 16;
|
|
while (rhs > 0){
|
|
out = "0123456789abcdef"[size_t(rhs % div)] + out;
|
|
rhs /= div;
|
|
}
|
|
}
|
|
stream << out;
|
|
return stream;
|
|
}
|
|
|