// // Copyright (C) 2011-15 DyND Developers // BSD 2-Clause License, see LICENSE.txt // #pragma once #include #if !defined(DYND_HAS_INT128) namespace dynd { class DYNDT_API int128 { public: #if defined(DYND_BIG_ENDIAN) uint64_t m_hi, m_lo; #else uint64_t m_lo, m_hi; #endif int128() {} int128(uint64_t hi, uint64_t lo) : m_lo(lo), m_hi(hi) {} int128(bool1) { throw std::runtime_error("int128(bool1) is not implemented"); } int128(char value) : m_lo((int64_t)value), m_hi(value < 0 ? 0xffffffffffffffffULL : 0ULL) {} int128(signed char value) : m_lo((int64_t)value), m_hi(value < 0 ? 0xffffffffffffffffULL : 0ULL) {} int128(unsigned char value) : m_lo(value), m_hi(0ULL) {} int128(short value) : m_lo((int64_t)value), m_hi(value < 0 ? 0xffffffffffffffffULL : 0ULL) {} int128(unsigned short value) : m_lo(value), m_hi(0ULL) {} int128(int value) : m_lo((int64_t)value), m_hi(value < 0 ? 0xffffffffffffffffULL : 0ULL) {} int128(unsigned int value) : m_lo(value), m_hi(0ULL) {} int128(long value) : m_lo((int64_t)value), m_hi(value < 0 ? 0xffffffffffffffffULL : 0ULL) {} int128(unsigned long value) : m_lo(value), m_hi(0ULL) {} int128(long long value) : m_lo((int64_t)value), m_hi(value < 0 ? 0xffffffffffffffffULL : 0ULL) {} int128(unsigned long long value) : m_lo(value), m_hi(0ULL) {} int128(float value); int128(double value); int128(const uint128 &value); int128(const float16 &value); int128(const float128 &value); int128 operator+() const { return *this; } bool operator!() const { return !(this->m_hi) && !(this->m_lo); } int128 operator~() const { return int128(~m_hi, ~m_lo); } bool operator==(const int128 &rhs) const { return m_lo == rhs.m_lo && m_hi == rhs.m_hi; } bool operator==(int rhs) const { return static_cast(m_lo) == static_cast(rhs) && m_hi == (rhs >= 0 ? 0ULL : 0xffffffffffffffffULL); } bool operator!=(const int128 &rhs) const { return m_lo != rhs.m_lo || m_hi != rhs.m_hi; } bool operator!=(int rhs) const { return static_cast(m_lo) != static_cast(rhs) || m_hi != (rhs >= 0 ? 0ULL : 0xffffffffffffffffULL); } bool operator<(float rhs) const { return double(*this) < rhs; } bool operator<(double rhs) const { return double(*this) < rhs; } bool operator<(const int128 &rhs) const { return (int64_t)m_hi < (int64_t)rhs.m_hi || (m_hi == rhs.m_hi && m_lo < rhs.m_lo); } bool operator<=(const int128 &rhs) const { return (int64_t)m_hi < (int64_t)rhs.m_hi || (m_hi == rhs.m_hi && m_lo <= rhs.m_lo); } bool operator>(const int128 &rhs) const { return rhs.operator<(*this); } bool operator>=(const int128 &rhs) const { return rhs.operator<=(*this); } bool is_negative() const { return (m_hi & 0x8000000000000000ULL) != 0; } void negate() { // twos complement negation, ~x + 1 uint64_t lo = ~m_lo, hi = ~m_hi; uint64_t lo_p1 = lo + 1; m_hi = hi + (lo_p1 < lo); m_lo = lo_p1; } int128 &operator+=(const int128 &rhs) { uint64_t lo = m_lo + rhs.m_lo; *this = int128(m_hi + ~rhs.m_hi + (lo < m_lo), lo); return *this; } int128 operator-() const { // twos complement negation, ~x + 1 uint64_t lo = ~m_lo, hi = ~m_hi; uint64_t lo_p1 = lo + 1; return int128(hi + (lo_p1 < lo), lo_p1); } int128 operator+(const int128 &rhs) const { uint64_t lo = m_lo + rhs.m_lo; return int128(m_hi + rhs.m_hi + (lo < m_lo), lo); } int128 operator-(const int128 &rhs) const { uint64_t lo = m_lo + ~rhs.m_lo + 1; return int128(m_hi + ~rhs.m_hi + (lo < m_lo), lo); } int128 operator*(uint32_t rhs) const; // int128 operator/(uint32_t rhs) const; int128 &operator/=(int128 DYND_UNUSED(rhs)) { throw std::runtime_error("operator/= is not implemented for int128"); } operator float() const { if (*this < int128(0)) { int128 tmp = -(*this); return tmp.m_lo + tmp.m_hi * 18446744073709551616.f; } else { return m_lo + m_hi * 18446744073709551616.f; } } operator double() const { if (*this < int128(0)) { int128 tmp = -(*this); return tmp.m_lo + tmp.m_hi * 18446744073709551616.0; } else { return m_lo + m_hi * 18446744073709551616.0; } } explicit operator bool() const { return m_lo || m_hi; } explicit operator char() const { return (char)m_lo; } explicit operator signed char() const { return (signed char)m_lo; } explicit operator unsigned char() const { return (unsigned char)m_lo; } explicit operator short() const { return (short)m_lo; } explicit operator unsigned short() const { return (unsigned short)m_lo; } explicit operator int() const { return (int)m_lo; } explicit operator unsigned int() const { return (unsigned int)m_lo; } explicit operator long() const { return (long)m_lo; } explicit operator unsigned long() const { return (unsigned long)m_lo; } explicit operator long long() const { return (long long)m_lo; } explicit operator unsigned long long() const { return (unsigned long long)m_lo; } }; template <> struct is_integral : std::true_type { }; } // namespace dynd namespace std { template <> struct common_type { typedef dynd::int128 type; }; template <> struct common_type { typedef dynd::int128 type; }; template <> struct common_type { typedef dynd::int128 type; }; template <> struct common_type { typedef dynd::int128 type; }; template <> struct common_type { typedef dynd::int128 type; }; template <> struct common_type { typedef dynd::int128 type; }; template <> struct common_type { typedef dynd::int128 type; }; template <> struct common_type { typedef dynd::int128 type; }; template <> struct common_type { typedef dynd::int128 type; }; template <> struct common_type { typedef dynd::int128 type; }; template <> struct common_type { typedef dynd::int128 type; }; template <> struct common_type { typedef dynd::int128 type; }; template <> struct common_type { typedef dynd::int128 type; }; template <> struct common_type { typedef dynd::int128 type; }; template <> struct common_type { typedef float type; }; template <> struct common_type { typedef double type; }; template struct common_type : common_type { }; } // namespace std namespace dynd { inline int128 operator/(int128 DYND_UNUSED(lhs), int128 DYND_UNUSED(rhs)) { throw std::runtime_error("operator/ is not implemented for int128"); } inline bool operator==(int lhs, const int128 &rhs) { return rhs == lhs; } inline bool operator!=(int lhs, const int128 &rhs) { return rhs != lhs; } inline bool operator<(const int128 &lhs, int rhs) { return lhs < int128(rhs); } inline bool operator>(const int128 &lhs, int rhs) { return lhs > int128(rhs); } inline bool operator<(float lhs, const int128 &rhs) { return lhs < double(rhs); } inline bool operator<(double lhs, const int128 &rhs) { return lhs < double(rhs); } inline bool operator<(signed char lhs, const int128 &rhs) { return int128(lhs) < rhs; } inline bool operator<(unsigned char lhs, const int128 &rhs) { return int128(lhs) < rhs; } inline bool operator<(short lhs, const int128 &rhs) { return int128(lhs) < rhs; } inline bool operator<(unsigned short lhs, const int128 &rhs) { return int128(lhs) < rhs; } inline bool operator<(int lhs, const int128 &rhs) { return int128(lhs) < rhs; } inline bool operator<(unsigned int lhs, const int128 &rhs) { return int128(lhs) < rhs; } inline bool operator<(long long lhs, const int128 &rhs) { return int128(lhs) < rhs; } inline bool operator<(unsigned long long lhs, const int128 &rhs) { return int128(lhs) < rhs; } inline bool operator>(float lhs, const int128 &rhs) { return lhs > double(rhs); } inline bool operator>(double lhs, const int128 &rhs) { return lhs > double(rhs); } inline bool operator>(signed char lhs, const int128 &rhs) { return int128(lhs) > rhs; } inline bool operator>(unsigned char lhs, const int128 &rhs) { return int128(lhs) > rhs; } inline bool operator>(short lhs, const int128 &rhs) { return int128(lhs) > rhs; } inline bool operator>(unsigned short lhs, const int128 &rhs) { return int128(lhs) > rhs; } inline bool operator>(int lhs, const int128 &rhs) { return int128(lhs) > rhs; } inline bool operator>(unsigned int lhs, const int128 &rhs) { return int128(lhs) > rhs; } inline bool operator>(long long lhs, const int128 &rhs) { return int128(lhs) > rhs; } inline bool operator>(unsigned long long lhs, const int128 &rhs) { return int128(lhs) > rhs; } DYNDT_API std::ostream &operator<<(std::ostream &out, const int128 &val); } // namespace dynd namespace std { template <> class numeric_limits { public: static const bool is_specialized = true; static dynd::int128(min)() throw() { return dynd::int128(0x8000000000000000ULL, 0ULL); } static dynd::int128(max)() throw() { return dynd::int128(0x7fffffffffffffffULL, 0xffffffffffffffffULL); } static const int digits = 0; static const int digits10 = 0; static const bool is_signed = true; static const bool is_integer = true; static const bool is_exact = true; static const int radix = 2; static dynd::int128 epsilon() throw() { return dynd::int128(0ULL, 1ULL); } static dynd::int128 round_error() throw() { return dynd::int128(0ULL, 1ULL); } static const int min_exponent = 0; static const int min_exponent10 = 0; static const int max_exponent = 0; static const int max_exponent10 = 0; static const bool has_infinity = false; static const bool has_quiet_NaN = false; static const bool has_signaling_NaN = false; static const float_denorm_style has_denorm = denorm_absent; static const bool has_denorm_loss = false; static dynd::int128 infinity() throw(); static dynd::int128 quiet_NaN() throw(); static dynd::int128 signaling_NaN() throw(); static dynd::int128 denorm_min() throw(); static const bool is_iec559 = false; static const bool is_bounded = false; static const bool is_modulo = false; static const bool traps = false; static const bool tinyness_before = false; static const float_round_style round_style = round_toward_zero; }; } // namespace std #endif // !defined(DYND_HAS_INT128)