Let's carry out an experiment:
float best = 0f;
for (int i = 2147483000; ; ++i)
{
float f = (float)i;
try
{
checked
{
int v = (int)f;
}
best = f;
}
catch (OverflowException)
{
string report = string.Join(Environment.NewLine,
$" max float = {best:g10}",
$"min overflow = {f:g10}",
$" max int = {i - 1}");
Console.Write(report);
break;
}
}
The outcome is
max float = 2147483520
min overflow = 2147483650
max int = 2147483583
So we can conclude that the max float
which can be cast to int
is 2147483520
. The max int
which can be cast into float
and back to int
is 2147483583
;
if we try to cast 2147483583 + 1 = 2147483584
we'll get 2147483650f
which will throw excpetion if we try to cast it back to int
.
int overflow = 2147483583 + 1;
int back = checked((int)(float) overflow); // <- throws exception
or even
float f_1 = 2147483583f; // f_1 == 2147483520f (rounding)
int i_1 = checked((int) f_1); // OK
float f_2 = 2147483584f; // f_2 == 2147483650f (rounding) > int.MaxValue
int i_2 = checked((int) f_2); // throws exception
Finally, float
to int
conversion (no exceptions; int.MaxValue
or int.MinValue
if float
is out of range):
// float: round errors (mantissa has 23 bits only: 23 < 32)
public static int ClampToInt(this float x) =>
x > 2147483520f ? int.MaxValue
: x < -2147483650f ? int.MinValue
: (int) x;
// double: no round errors (mantissa has 52 bits: 52 > 32)
public static int ClampToInt(this double x) =>
x > int.MaxValue ? int.MaxValue
: x < int.MinValue ? int.MinValue
: (int) x;