最大 "float" 小于或等于 `int.MaxValue`
Largest "float" less than or equal to `int.MaxValue`
我正在尝试编写一个采用 float
和 returns 和 int
的转换函数,它基本上进行饱和转换。如果它大于 int.MaxValue
,那么应该返回 int.MaxValue
,对于 int.MinValue
也是如此。
我宁愿不将异常捕获作为正常流程控制的一部分,而只是显式检查边界,除非我不确定上限是多少,因为可以存储在 int 中的最大浮点数较小比 int.MaxValue
因为 float 的精度低于 int 对于大小的值。
基本上我在寻找...
:
float largestFloatThatCanBeStoredInAnInt = ...
那不行吗?
float largestFloatThatCanBeStoredInAnInt = (float)int.MaxValue - 1;
这个表达式是正确的:
(float)int.MaxValue - 1 < int.MaxValue
我建议您 hard-code 它作为正确的数据类型:
var largestFloatThatCanBeStoredInAnInt = 2147483000f;
2,147,483,000 是您可以存储在小于 int.MaxValue
的浮点数中的最大值
这种方法解决了这个问题:
public static int ClampToInt(this float x)
{
const float maxFloat = int.MaxValue;
const float minFloat = int.MinValue;
return x >= maxFloat ? int.MaxValue : x <= minFloat ? int.MinValue : (int) x;
}
>=
的使用在这里很重要。只使用 >
,你会错过 (float) int.MaxValue
,然后当你进行普通转换时,你会发现 (int) (float) int.MaxValue == int.MinValue
,结果会使这个函数 return 出错值。
让我们进行一个实验:
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;
}
}
结果是
max float = 2147483520
min overflow = 2147483650
max int = 2147483583
所以我们可以得出结论,可以转换为int
的最大float
是2147483520
。可以转换为 float
并返回到 int
的最大 int
是 2147483583
;
如果我们尝试转换 2147483583 + 1 = 2147483584
我们会得到 2147483650f
如果我们尝试将它转换回 int
.
将会抛出异常
int overflow = 2147483583 + 1;
int back = checked((int)(float) overflow); // <- throws exception
甚至
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
最后,float
到 int
的转换(没有例外;int.MaxValue
或 int.MinValue
如果 float
是 超出范围):
// 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;
我正在尝试编写一个采用 float
和 returns 和 int
的转换函数,它基本上进行饱和转换。如果它大于 int.MaxValue
,那么应该返回 int.MaxValue
,对于 int.MinValue
也是如此。
我宁愿不将异常捕获作为正常流程控制的一部分,而只是显式检查边界,除非我不确定上限是多少,因为可以存储在 int 中的最大浮点数较小比 int.MaxValue
因为 float 的精度低于 int 对于大小的值。
基本上我在寻找...
:
float largestFloatThatCanBeStoredInAnInt = ...
那不行吗?
float largestFloatThatCanBeStoredInAnInt = (float)int.MaxValue - 1;
这个表达式是正确的:
(float)int.MaxValue - 1 < int.MaxValue
我建议您 hard-code 它作为正确的数据类型:
var largestFloatThatCanBeStoredInAnInt = 2147483000f;
2,147,483,000 是您可以存储在小于 int.MaxValue
这种方法解决了这个问题:
public static int ClampToInt(this float x)
{
const float maxFloat = int.MaxValue;
const float minFloat = int.MinValue;
return x >= maxFloat ? int.MaxValue : x <= minFloat ? int.MinValue : (int) x;
}
>=
的使用在这里很重要。只使用 >
,你会错过 (float) int.MaxValue
,然后当你进行普通转换时,你会发现 (int) (float) int.MaxValue == int.MinValue
,结果会使这个函数 return 出错值。
让我们进行一个实验:
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;
}
}
结果是
max float = 2147483520
min overflow = 2147483650
max int = 2147483583
所以我们可以得出结论,可以转换为int
的最大float
是2147483520
。可以转换为 float
并返回到 int
的最大 int
是 2147483583
;
如果我们尝试转换 2147483583 + 1 = 2147483584
我们会得到 2147483650f
如果我们尝试将它转换回 int
.
int overflow = 2147483583 + 1;
int back = checked((int)(float) overflow); // <- throws exception
甚至
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
最后,float
到 int
的转换(没有例外;int.MaxValue
或 int.MinValue
如果 float
是 超出范围):
// 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;