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;