Test if a floating point number is an integer

喜夏-厌秋 提交于 2019-12-03 22:46:58
d == Math.Floor(d)

does the same thing in other words.

NB: Hopefully you're aware that you have to be very careful when doing this kind of thing; floats/doubles will very easily accumulate miniscule errors that make exact comparisons (like this one) fail for no obvious reason.

If your double is the result of another calculation, you probably want something like:

d == Math.Floor(d + 0.00001);

That way, if there's been a slight rounding error, it'll still match.

This would work I think:

if (d % 1 == 0) {
  //...
}
ddaa

I cannot answer the C#-specific part of the question, but I must point out you are probably missing a generic problem with floating point numbers.

Generally, integerness is not well defined on floats. For the same reason that equality is not well defined on floats. Floating point calculations normally include both rounding and representation errors.

For example, 1.1 + 0.6 != 1.7.

Yup, that's just the way floating point numbers work.

Here, 1.1 + 0.6 - 1.7 == 2.2204460492503131e-16.

Strictly speaking, the closest thing to equality comparison you can do with floats is comparing them up to a chosen precision.

If this is not sufficient, you must work with a decimal number representation, with a floating point number representation with built-in error range, or with symbolic computations.

Bill K

If you are just going to convert it, Mike F / Khoth's answer is good, but doesn't quite answer your question. If you are going to actually test, and it's actually important, I recommend you implement something that includes a margin of error.

For instance, if you are considering money and you want to test for even dollar amounts, you might say (following Khoth's pattern):

if( Math.abs(d - Math.Floor(d + 0.001)) < 0.001)

In other words, take the absolute value of the difference of the value and it's integer representation and ensure that it's small.

You don't need the extra (double) in there. This works:

if (d == (int)d) {
 //...
}

Use Math.Truncate()

A simple test such as 'x == floor(x)' is mathematically assured to work correctly, for any fixed-precision FP number.

All legal fixed-precision FP encodings represent distinct real numbers, and so for every integer x, there is at most one fixed-precision FP encoding that matches it exactly.

Therefore, for every integer x that CAN be represented in such way, we have x == floor(x) necessarily, since floor(x) by definition returns the largest FP number y such that y <= x and y represents an integer; so floor(x) must return x.

This will let you choose what precision you're looking for, plus or minus half a tick, to account for floating point drift. The comparison is integral also which is nice.

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

and the output is

2 is an int
1.99999999 is an int
2.00000001 is an int

Something like this

double d = 4.0;
int i = 4;

bool equal = d.CompareTo(i) == 0; // true

Could you use this

    bool IsInt(double x)
    {
        try
        {
            int y = Int16.Parse(x.ToString());
            return true;
        }
        catch 
        {
            return false;
        }
    }

To handle the precision of the double...

Math.Abs(d - Math.Floor(d)) <= double.Epsilon

Consider the following case where a value less then double.Epsilon fails to compare as zero.

// 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"));
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!