Test if a floating point number is an integer

18,054

Solution 1

This would work I think:

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

Solution 2

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.

Solution 3

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.

Solution 4

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.

Solution 5

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.

Share:
18,054
Tjkoopa
Author by

Tjkoopa

For me, fun is taking a program, language, whatever and making it do things it's designer never envisioned it doing. It comes in handy when I'm asked to do something a little outside the norm as part of my job.

Updated on June 03, 2022

Comments

  • Tjkoopa
    Tjkoopa almost 2 years

    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.

  • Tjkoopa
    Tjkoopa over 15 years
    That works! BTW, are you sure that it will be exactly the same?
  • Tjkoopa
    Tjkoopa over 15 years
    A good point and well described, However in my case the desired behavior is well defined by the original code. Anything that mimics it is valid.
  • Tjkoopa
    Tjkoopa over 15 years
    I'm just a bit weary of int mod with negative numbers, I'm not sure I want to figure them out for FP.
  • Ishbir
    Ishbir over 15 years
    Um. What about this? d= 3e30; if (d == (int)d) {
  • Tjkoopa
    Tjkoopa over 15 years
    Yup, it wont do exactly what I asked for there but I will do what I need.
  • Hosam Aly
    Hosam Aly about 15 years
    int.TryParse would be easier to use, but it will also incur a (relatively) large overhead.
  • Tjkoopa
    Tjkoopa about 15 years
    x.ToString() feed into some string searching logic might be even better.
  • Crash893
    Crash893 about 15 years
    I guess you could do something like if(x.tostring().indexof('.')!= -1) {true} else {false}
  • Hosam Aly
    Hosam Aly about 15 years
    @Crash893: You'd need IndexOfAny('.', 'e', 'E'), as some values don't have dots (e.g. 1e15).
  • aka.nice
    aka.nice over 11 years
    @Khoth Please, could you exhibit a case where (d==Math.Floor(d)) != (d==Math.Floor(d+0.00001)) ?
  • aka.nice
    aka.nice over 11 years
    Or is_almost_integer(d,eps) could simply be return Math.Floor(d-eps)!=Math.Floor(d+eps)
  • ccook
    ccook over 11 years
    You should use double.Epsilon... Or if you are considering x many operations x*double.Epsilon.
  • ccook
    ccook over 11 years
    Even 0.1 != 0.1 as far as floats go. The mantisas are necessarily truncating the binary value 0.0001100110011001100110011001100... Try 0.1F==0.1
  • user1234567
    user1234567 almost 4 years
    @BCS, could you please say, what's wrong with "int mod with negative numbers"?
  • Tjkoopa
    Tjkoopa almost 4 years
    There are at least two different interpretations for integer modules when one or both operands are negative. And there is a lot of buggy code as a result of people not remembering which the current language uses. I don't know what happens if you toos in FP. And I suspect the answer has too many different "it depends" to be safe to use. For example, without a detailed read of the standards, I'd not be sure that the FP won't get cast to int before the mod in some cases (or some version of the language).