C# 测试浮点数是否为整数

C# 测试浮点数是否为整数,c#,floating-point,numerical,C#,Floating Point,Numerical,此代码有效(C#3) 有更好的方法吗 出于无关的原因,我想避免双重演员;除此之外还有什么好办法?(即使没有那么好) 注意:有几个人指出,==这个(重要的)点在对浮点进行重新排序时经常出现问题。在这种情况下,我期望值在0到几百之间,并且它们应该是整数(非整数是错误的),因此如果这些点“不应该”对我来说是个问题。您不需要额外的(双精度)值。这项工作: if (d == (int)d) { //... } 换言之,也做同样的事情 NB:希望你知道在做这种事情时你必须非常小心;浮点数/双精度浮点数很

此代码有效(C#3)

  • 有更好的方法吗
  • 出于无关的原因,我想避免双重演员;除此之外还有什么好办法?(即使没有那么好)
  • 注意:有几个人指出,==这个(重要的)点在对浮点进行重新排序时经常出现问题。在这种情况下,我期望值在0到几百之间,并且它们应该是整数(非整数是错误的),因此如果这些点“不应该”对我来说是个问题。

    您不需要额外的(双精度)值。这项工作:

    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"));