Question

This code works (C# 3)

double d;
if(d == (double)(int)d) ...;
  1. Is there a better way to do this?
  2. For extraneous reasons I want to avoid the double cast so; what nice ways exist other than this? (even if they aren't as good)

Note: Several people pointed out the (important) point that == is often problematic regrading floating point. In this cases I expect values in the range of 0 to a few hundred and they are supposed to be integers (non ints are errors) so if those points "shouldn't" be an issue for me.

Was it helpful?

Solution

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.

OTHER TIPS

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) {
  //...
}

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.

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"));
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top