C# 测试浮点数是否为整数
此代码有效(C#3)C# 测试浮点数是否为整数,c#,floating-point,numerical,C#,Floating Point,Numerical,此代码有效(C#3) 有更好的方法吗 出于无关的原因,我想避免双重演员;除此之外还有什么好办法?(即使没有那么好) 注意:有几个人指出,==这个(重要的)点在对浮点进行重新排序时经常出现问题。在这种情况下,我期望值在0到几百之间,并且它们应该是整数(非整数是错误的),因此如果这些点“不应该”对我来说是个问题。您不需要额外的(双精度)值。这项工作: if (d == (int)d) { //... } 换言之,也做同样的事情 NB:希望你知道在做这种事情时你必须非常小心;浮点数/双精度浮点数很
if (d == (int)d) {
//...
}
换言之,也做同样的事情
NB:希望你知道在做这种事情时你必须非常小心;浮点数/双精度浮点数很容易累积微小的错误,使得精确比较(如本例)无明显原因而失败。类似的情况
double d = 4.0;
int i = 4;
bool equal = d.CompareTo(i) == 0; // true
使用Math.Truncate()如果您的双精度是另一次计算的结果,您可能需要类似以下内容:
d == Math.Floor(d + 0.00001);
这样,如果有轻微的舍入误差,它仍然会匹配。我认为这会起作用:
if (d % 1 == 0) {
//...
}
我无法回答这个问题的C#特定部分,但我必须指出,您可能遗漏了一个关于浮点数的通用问题
通常,整数在浮点上没有很好的定义。出于同样的原因,在浮点上没有很好地定义相等。浮点计算通常包括舍入和表示错误
例如,1.1+0.6!=1.7
是的,这就是浮点数的工作方式
这里,1.1+0.6-1.7==2.22044604925031E-16
严格地说,最接近于对浮点进行相等比较的方法是将它们比较到选定的精度
如果这还不够,您必须使用十进制数表示法、具有内置错误范围的浮点数表示法或符号计算。如果您只是想转换它,Mike F/Khoth的答案很好,但不能完全回答您的问题。如果您要进行实际测试,而且这非常重要,我建议您实现一些包含误差范围的东西 例如,如果您正在考虑金钱,并且您想要测试偶数美元的金额,您可能会说(遵循Khoth的模式):
if(数学绝对值(d-数学楼层(d+0.001))<0.001)
换句话说,取数值差的绝对值及其整数表示形式,并确保其较小。这将允许您选择所需的精度,加上或减去半个刻度,以考虑浮点漂移。比较也是积分的,这很好
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
你能用这个吗
bool IsInt(double x)
{
try
{
int y = Int16.Parse(x.ToString());
return true;
}
catch
{
return false;
}
}
要处理双精度
Math.Abs(d - Math.Floor(d)) <= double.Epsilon
Math.Abs(d-Math.Floor(d))一个简单的测试,例如'x==Floor(x)',在数学上可以保证对任何固定精度的FP数正确工作
所有合法的固定精度FP编码都表示不同的实数,因此对于每个整数x,最多有一个固定精度FP编码与之完全匹配
因此,对于可以用这种方式表示的每个整数x,我们必须有x==floor(x),因为floor(x)根据定义返回最大的FP数y,因此y不完全相同。我觉得好多了。对于大的inetegr数,它可以存储在double中,但不能存储在int中,转换为int不会像您提到的那样起作用,应该非常小心地进行任何类型的浮点等式比较-在大多数情况下,更好的策略是使用一个小的epsilon因子。我喜欢这个答案!然而,在我的情况下,碰巧我也应该检测溢出(或任何舍入错误),但我将以更一般的形式保留问题。@Cade Roux:如果您正在查看舍入操作,精确的FP比较非常有用。@Mike F:另一种策略将使用d==Math.Truncate(d)因为这使用了一种更简单的取整模式。这很有效!顺便说一句,你确定会完全一样吗?嗯。这个怎么样<代码>d=3e30;如果(d==(int)d){
是的,它不会完全满足我的要求,但我会满足我的需要。这是一个很好的观点,描述得很好,但是在我的例子中,所需的行为由原始代码定义得很好。任何模仿它的行为都是有效的。即使是0.1!=0.1的浮点值。mantisas必然会截断二进制值0.000110011001100…试试0.1F==0.1I我只是有点厌倦了带负数的int mod,我不确定我想为FP算出它们。@BCS,你能告诉我,“带负数的int mod”有什么问题吗?当一个或两个操作数都为负数时,整数模至少有两种不同的解释。由于人们不记得当前语言使用的是哪种语言,因此有很多错误代码。我不知道如果在FP中使用too会发生什么。我怀疑答案有太多不同的“视情况而定”为了安全使用。例如,如果没有详细阅读标准,我不确定FP在某些情况下(或该语言的某些版本)不会在mod之前转换为int。int.TryParse更易于使用,但也会产生(相对)较大的开销。x.ToString()输入一些字符串搜索逻辑可能更好。我想你可以做一些事情,比如if(x.tostring().indexof('.')!=-1{true}或者{false}@Crash893:你需要IndexOfAny('.','e','e'),因为有些值没有点(例如1e15)。@Khoth,你能展示一个例子吗(d==Math.Floor(d))!=(d==Math.Floor(d+0.00001))?您应该使用double.Epsilon…或者如果您正在考虑x多个操作x*double.Epsilon.Or几乎是整数(d,eps),可以简单地返回Math.Floor(d-eps)!=Math.Floor(d+eps)
2 is an int
1.99999999 is an int
2.00000001 is an int
bool IsInt(double x)
{
try
{
int y = Int16.Parse(x.ToString());
return true;
}
catch
{
return false;
}
}
Math.Abs(d - Math.Floor(d)) <= 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"));