Commit 94e64f0c by Markus Wick Committed by Copybara-Service

PR #1777: Avoid std::ldexp in `operator double(int128)`.

Imported from GitHub PR https://github.com/abseil/abseil-cpp/pull/1777

This patch replaces all instances of

  std::ldexp(msb, 64)

with

  msb * (2**64)

as it turns out that this optimization is not done by MSVC. Worse, it emited a function call with error checking, even if the int128 cannot hit the inf limitation.

Sadly even the constant `std::ldexp(1.0, 64)` is not inlined: https://gcc.godbolt.org/z/oGhGz77sx
Merge a21b1c952494944e51e12c62127a71480bc28695 into 87831365

Merging this change closes #1777

COPYBARA_INTEGRATE_REVIEW=https://github.com/abseil/abseil-cpp/pull/1777 from degasus:int128_t a21b1c952494944e51e12c62127a71480bc28695
PiperOrigin-RevId: 688968524
Change-Id: Id88cf38e241553f88bf4d97e7b001247dcd5599b
parent 87831365
...@@ -789,16 +789,20 @@ constexpr uint128::operator unsigned __int128() const { ...@@ -789,16 +789,20 @@ constexpr uint128::operator unsigned __int128() const {
// Conversion operators to floating point types. // Conversion operators to floating point types.
inline uint128::operator float() const { inline uint128::operator float() const {
return static_cast<float>(lo_) + std::ldexp(static_cast<float>(hi_), 64); // Note: This method might return Inf.
constexpr float pow_2_64 = 18446744073709551616.0f;
return static_cast<float>(lo_) + static_cast<float>(hi_) * pow_2_64;
} }
inline uint128::operator double() const { inline uint128::operator double() const {
return static_cast<double>(lo_) + std::ldexp(static_cast<double>(hi_), 64); constexpr double pow_2_64 = 18446744073709551616.0;
return static_cast<double>(lo_) + static_cast<double>(hi_) * pow_2_64;
} }
inline uint128::operator long double() const { inline uint128::operator long double() const {
constexpr long double pow_2_64 = 18446744073709551616.0L;
return static_cast<long double>(lo_) + return static_cast<long double>(lo_) +
std::ldexp(static_cast<long double>(hi_), 64); static_cast<long double>(hi_) * pow_2_64;
} }
// Comparison operators. // Comparison operators.
......
...@@ -170,27 +170,29 @@ inline int128::operator float() const { ...@@ -170,27 +170,29 @@ inline int128::operator float() const {
// complement overwhelms the precision of the mantissa. // complement overwhelms the precision of the mantissa.
// //
// Also check to make sure we don't negate Int128Min() // Also check to make sure we don't negate Int128Min()
constexpr float pow_2_64 = 18446744073709551616.0f;
return v_ < 0 && *this != Int128Min() return v_ < 0 && *this != Int128Min()
? -static_cast<float>(-*this) ? -static_cast<float>(-*this)
: static_cast<float>(Int128Low64(*this)) + : static_cast<float>(Int128Low64(*this)) +
std::ldexp(static_cast<float>(Int128High64(*this)), 64); static_cast<float>(Int128High64(*this)) * pow_2_64;
} }
inline int128::operator double() const { inline int128::operator double() const {
// See comment in int128::operator float() above. // See comment in int128::operator float() above.
constexpr double pow_2_64 = 18446744073709551616.0;
return v_ < 0 && *this != Int128Min() return v_ < 0 && *this != Int128Min()
? -static_cast<double>(-*this) ? -static_cast<double>(-*this)
: static_cast<double>(Int128Low64(*this)) + : static_cast<double>(Int128Low64(*this)) +
std::ldexp(static_cast<double>(Int128High64(*this)), 64); static_cast<double>(Int128High64(*this)) * pow_2_64;
} }
inline int128::operator long double() const { inline int128::operator long double() const {
// See comment in int128::operator float() above. // See comment in int128::operator float() above.
constexpr long double pow_2_64 = 18446744073709551616.0L;
return v_ < 0 && *this != Int128Min() return v_ < 0 && *this != Int128Min()
? -static_cast<long double>(-*this) ? -static_cast<long double>(-*this)
: static_cast<long double>(Int128Low64(*this)) + : static_cast<long double>(Int128Low64(*this)) +
std::ldexp(static_cast<long double>(Int128High64(*this)), static_cast<long double>(Int128High64(*this)) * pow_2_64;
64);
} }
#endif // Clang on PowerPC #endif // Clang on PowerPC
......
...@@ -139,26 +139,29 @@ inline int128::operator float() const { ...@@ -139,26 +139,29 @@ inline int128::operator float() const {
// complement overwhelms the precision of the mantissa. // complement overwhelms the precision of the mantissa.
// //
// Also check to make sure we don't negate Int128Min() // Also check to make sure we don't negate Int128Min()
constexpr float pow_2_64 = 18446744073709551616.0f;
return hi_ < 0 && *this != Int128Min() return hi_ < 0 && *this != Int128Min()
? -static_cast<float>(-*this) ? -static_cast<float>(-*this)
: static_cast<float>(lo_) + : static_cast<float>(lo_) +
std::ldexp(static_cast<float>(hi_), 64); static_cast<float>(hi_) * pow_2_64;
} }
inline int128::operator double() const { inline int128::operator double() const {
// See comment in int128::operator float() above. // See comment in int128::operator float() above.
constexpr double pow_2_64 = 18446744073709551616.0;
return hi_ < 0 && *this != Int128Min() return hi_ < 0 && *this != Int128Min()
? -static_cast<double>(-*this) ? -static_cast<double>(-*this)
: static_cast<double>(lo_) + : static_cast<double>(lo_) +
std::ldexp(static_cast<double>(hi_), 64); static_cast<double>(hi_) * pow_2_64;
} }
inline int128::operator long double() const { inline int128::operator long double() const {
// See comment in int128::operator float() above. // See comment in int128::operator float() above.
constexpr long double pow_2_64 = 18446744073709551616.0L;
return hi_ < 0 && *this != Int128Min() return hi_ < 0 && *this != Int128Min()
? -static_cast<long double>(-*this) ? -static_cast<long double>(-*this)
: static_cast<long double>(lo_) + : static_cast<long double>(lo_) +
std::ldexp(static_cast<long double>(hi_), 64); static_cast<long double>(hi_) * pow_2_64;
} }
// Comparison operators. // Comparison operators.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment