此代码有效(C# 3)
double d;
if(d == (double)(int)d) ...;
- 有一个更好的方法吗?
- 出于无关的原因,我想避免双重演员;除了这个还有什么好的方法吗?(即使它们不是那么好)
注意:有几个人指出了(重要的)一点,即 == 在重新调整浮点时经常会出现问题。在这种情况下,我希望值在 0 到几百之间,并且它们应该是整数(非整数是错误),所以如果这些点“不应该”对我来说是个问题。
此代码有效(C# 3)
double d;
if(d == (double)(int)d) ...;
注意:有几个人指出了(重要的)一点,即 == 在重新调整浮点时经常会出现问题。在这种情况下,我希望值在 0 到几百之间,并且它们应该是整数(非整数是错误),所以如果这些点“不应该”对我来说是个问题。
d == Math.Floor(d)
换句话说,做同样的事情。
注意:希望您知道在做这种事情时必须非常小心;浮点数/双精度数很容易累积微小的错误,导致精确比较(如这个)无缘无故地失败。
我认为这会起作用:
if (d % 1 == 0) {
//...
}
如果你的双精度是另一个计算的结果,你可能想要这样的东西:
d == Math.Floor(d + 0.00001);
这样,如果有轻微的舍入误差,它仍然会匹配。
我无法回答问题的特定于 C# 的部分,但我必须指出您可能遗漏了浮点数的一般问题。
一般来说,整数在浮点数上没有很好的定义。出于同样的原因,在浮点数上没有很好地定义相等性。浮点计算通常包括舍入误差和表示误差。
例如,1.1 + 0.6 != 1.7
。
是的,这就是浮点数的工作方式。
在这里,1.1 + 0.6 - 1.7 == 2.2204460492503131e-16
。
严格来说,你可以用浮点数做的最接近相等比较的事情是将它们与选择的精度进行比较。
如果这还不够,您必须使用十进制数表示、具有内置错误范围的浮点数表示或符号计算。
如果您只是要转换它,Mike F / Khoth 的回答很好,但不能完全回答您的问题。如果您要进行实际测试,并且它实际上很重要,我建议您实施一些包含误差范围的方法。
例如,如果您正在考虑金钱并且想要测试美元金额,您可能会说(遵循 Khoth 的模式):
if( Math.abs(d - Math.Floor(d + 0.001)) < 0.001)
换句话说,取值与它的整数表示之差的绝对值,并确保它很小。
对于任何固定精度的 FP 数,诸如“x == floor(x)”之类的简单测试在数学上可以保证正常工作。
所有合法的固定精度 FP 编码都表示不同的实数,因此对于每个整数 x,至多有一个与它完全匹配的固定精度 FP 编码。
因此,对于可以以这种方式表示的每个整数 x,我们必然有 x == floor(x),因为 floor(x) 根据定义返回最大的 FP 数 y,使得 y <= x 并且 y 表示整数;所以 floor(x) 必须返回 x。
你不需要额外的(双)在那里。这有效:
if (d == (int)d) {
//...
}
使用 Math.Truncate()
这将让您选择您正在寻找的精度,加上或减去半个刻度,以考虑浮点漂移。比较也是不可或缺的,这很好。
static void Main(string[] args)
{
const int precision = 10000;
foreach (var d in new[] { 2, 2.9, 2.001, 1.999, 1.99999999, 2.00000001 })
{
if ((int) (d*precision + .5)%precision == 0)
{
Console.WriteLine("{0} is an int", d);
}
}
}
输出是
2 is an int
1.99999999 is an int
2.00000001 is an int
像这样的东西
double d = 4.0;
int i = 4;
bool equal = d.CompareTo(i) == 0; // true
你能用这个吗
bool IsInt(double x)
{
try
{
int y = Int16.Parse(x.ToString());
return true;
}
catch
{
return false;
}
}
为了处理双精度...
Math.Abs(d - Math.Floor(d)) <= double.Epsilon
考虑以下情况,其中小于 double.Epsilon的值无法比较为零。
// number of possible rounds
const int rounds = 1;
// precision causes rounding up to double.Epsilon
double d = double.Epsilon*.75;
// due to the rounding this comparison fails
Console.WriteLine(d == Math.Floor(d));
// this comparison succeeds by accounting for the rounding
Console.WriteLine(Math.Abs(d - Math.Floor(d)) <= rounds*double.Epsilon);
// The difference is double.Epsilon, 4.940656458412465E-324
Console.WriteLine(Math.Abs(d - Math.Floor(d)).ToString("E15"));