- Which, if any, float values could not be represented as int after truncation?
After the float
value is truncated, the whole number value must be in the INT
range [INT_MIN ... INT_MAX]
. If outside this range, or not-a-number, conversion is UB.
- If there are any, does this mean that auto x = static_cast(float) is unsafe?
Yes, for many float
values.
- what is the proper/safe way of converting float to int then (assuming you want truncation)?
To test if float
to int
succeeds, test the limits with carefully constructed float
values that are exact and incurred no FP rounding in their derivation. No need for wider types like double
.
Take advantage INT_MIN
is a negated power-of-2 and INT_MAX
is one less than a power-of-2. Form 2 limits exactly: INT_MIN_FLT, INT_MAXP1_FLT
(INT_MAX
plus 1).
With common 32-bit int
, conversion well specified for float in the -2,147,483,648.999... to +2,147,483,647.999... range, not -2,147,483,648.0 to +2,147,483,647.0.
C-like answer, yet should be realizable in C++.
// One more than INT_MAX
#define INT_MAXP1_FLT (static_cast<float>(INT_MAX/2 + 1) * 2.0f)
#define INT_MIN_FLT (static_cast<float>INT_MIN)
float f;
int i;
// Avoid this as INT_MAXP1_FLT - 1.0f may be inexact
// if (f < INT_MAXP1_FLT && f > INT_MAXP1_FLT - 1.0f) {
if (f < INT_MAXP1_FLT && f - INT_MAXP1_FLT > -1.0f) {
i = static_cast<int>(f);
else if (f < 0)
i = INT_MIN;
else if (f > 0)
i = INT_MAX;
else
i = 0; // NAN case - best to do a isnan(f) test up front.
This approach works as long as the xxx_INT < FLT_MAX
. E.g. we are not dealing with some 128 bit integer type like uint128_t
.
This approach extends well to double
, long double
and the various integer types, both signed and unsigned.
NaN
.NaN
is always the weird one. – Latanyaauto x = static_cast<int>(f);
is just an obscure way of writingint x = f;
. Neither is more or less safe than the other, regardless of how you define "safe". – Theocritusstatic_cast
obscure. It's actually quite explicit that the cast is intended whereas in the case ofint x = f;
it's anyone's guess rather it's an intended implicit cast or a mistake. – Stomacherstatic_cast
is obscure. I said that the statement is obscure; there's more in it than thestatic_cast
. – Theocritusstatic_cast
is the correct way to do it; most compilers support and many (most?) companies use warnings that will flagint x = f
. – Thaliaint
whose value cannot be represented byint
. – Surgeon