Reputation: 1976
In JavaScript there is this isSafeInteger method. How check the same thing in C++? The most straightforward way would be:
bool isSafeInteger(double d) noexcept {
auto const i = static_cast<std::int64_t>(d);
return i == d && i <= 9007199254740991 && i >= -9007199254740991;
}
But it doesn't feel right. Is there a better way to do it?
Upvotes: 1
Views: 106
Reputation: 275200
bool isSafeInteger(double d) noexcept {
if (d>=std::numeric_limits<std::int64_t>::max()) return false;
if (d<=std::numeric_limits<std::int64_t>::min()) return false;
if (isnan(d)) return false;
auto as_int=[](double d){return static_cast<std::int64_t>(d);};
return (as_int(d)==d) && (as_int(d+1)!=as_int(d)) && (as_int(d-1)!=as_int(d));
}
this checks it round trips to double, and that adjacent doubles don't round to the same integer, and that the double isn't a NaN (while svoiding triggering any NaN traps).
Finally, guard against out of bounds conversion, which is UB. We use >=
and <=
to be safe due to +1
/-1
usage later.
This also works for float, but not for 128 (or 70ish) sized floats.
Upvotes: 4