Skip to content

Commit

Permalink
PR #1777: Avoid std::ldexp in operator double(int128).
Browse files Browse the repository at this point in the history
Imported from GitHub PR #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 a21b1c9 into 8783136

Merging this change closes #1777

COPYBARA_INTEGRATE_REVIEW=#1777 from degasus:int128_t a21b1c9
PiperOrigin-RevId: 688968524
Change-Id: Id88cf38e241553f88bf4d97e7b001247dcd5599b
  • Loading branch information
degasus authored and copybara-github committed Oct 23, 2024
1 parent 8783136 commit 94e64f0
Show file tree
Hide file tree
Showing 3 changed files with 19 additions and 10 deletions.
10 changes: 7 additions & 3 deletions absl/numeric/int128.h
Original file line number Diff line number Diff line change
Expand Up @@ -789,16 +789,20 @@ constexpr uint128::operator unsigned __int128() const {
// Conversion operators to floating point types.

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 {
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 {
constexpr long double pow_2_64 = 18446744073709551616.0L;
return static_cast<long double>(lo_) +
std::ldexp(static_cast<long double>(hi_), 64);
static_cast<long double>(hi_) * pow_2_64;
}

// Comparison operators.
Expand Down
10 changes: 6 additions & 4 deletions absl/numeric/int128_have_intrinsic.inc
Original file line number Diff line number Diff line change
Expand Up @@ -170,27 +170,29 @@ inline int128::operator float() const {
// complement overwhelms the precision of the mantissa.
//
// Also check to make sure we don't negate Int128Min()
constexpr float pow_2_64 = 18446744073709551616.0f;
return v_ < 0 && *this != Int128Min()
? -static_cast<float>(-*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 {
// See comment in int128::operator float() above.
constexpr double pow_2_64 = 18446744073709551616.0;
return v_ < 0 && *this != Int128Min()
? -static_cast<double>(-*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 {
// See comment in int128::operator float() above.
constexpr long double pow_2_64 = 18446744073709551616.0L;
return v_ < 0 && *this != Int128Min()
? -static_cast<long double>(-*this)
: static_cast<long double>(Int128Low64(*this)) +
std::ldexp(static_cast<long double>(Int128High64(*this)),
64);
static_cast<long double>(Int128High64(*this)) * pow_2_64;
}
#endif // Clang on PowerPC

Expand Down
9 changes: 6 additions & 3 deletions absl/numeric/int128_no_intrinsic.inc
Original file line number Diff line number Diff line change
Expand Up @@ -139,26 +139,29 @@ inline int128::operator float() const {
// complement overwhelms the precision of the mantissa.
//
// Also check to make sure we don't negate Int128Min()
constexpr float pow_2_64 = 18446744073709551616.0f;
return hi_ < 0 && *this != Int128Min()
? -static_cast<float>(-*this)
: static_cast<float>(lo_) +
std::ldexp(static_cast<float>(hi_), 64);
static_cast<float>(hi_) * pow_2_64;
}

inline int128::operator double() const {
// See comment in int128::operator float() above.
constexpr double pow_2_64 = 18446744073709551616.0;
return hi_ < 0 && *this != Int128Min()
? -static_cast<double>(-*this)
: static_cast<double>(lo_) +
std::ldexp(static_cast<double>(hi_), 64);
static_cast<double>(hi_) * pow_2_64;
}

inline int128::operator long double() const {
// See comment in int128::operator float() above.
constexpr long double pow_2_64 = 18446744073709551616.0L;
return hi_ < 0 && *this != Int128Min()
? -static_cast<long double>(-*this)
: static_cast<long double>(lo_) +
std::ldexp(static_cast<long double>(hi_), 64);
static_cast<long double>(hi_) * pow_2_64;
}

// Comparison operators.
Expand Down

0 comments on commit 94e64f0

Please sign in to comment.