Test if a floating point number is an integer
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.
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, 2022Comments
-
Tjkoopa almost 2 years
This code works (C# 3)
double d; if(d == (double)(int)d) ...;
- Is there a better way to do this?
- 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 over 15 yearsThat works! BTW, are you sure that it will be exactly the same?
-
Tjkoopa over 15 yearsA 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 over 15 yearsI'm just a bit weary of int mod with negative numbers, I'm not sure I want to figure them out for FP.
-
Ishbir over 15 yearsUm. What about this?
d= 3e30; if (d == (int)d) {
-
Tjkoopa over 15 yearsYup, it wont do exactly what I asked for there but I will do what I need.
-
Hosam Aly about 15 yearsint.TryParse would be easier to use, but it will also incur a (relatively) large overhead.
-
Tjkoopa about 15 yearsx.ToString() feed into some string searching logic might be even better.
-
Crash893 about 15 yearsI guess you could do something like if(x.tostring().indexof('.')!= -1) {true} else {false}
-
Hosam Aly about 15 years@Crash893: You'd need IndexOfAny('.', 'e', 'E'), as some values don't have dots (e.g. 1e15).
-
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 over 11 yearsOr is_almost_integer(d,eps) could simply be return Math.Floor(d-eps)!=Math.Floor(d+eps)
-
ccook over 11 yearsYou should use double.Epsilon... Or if you are considering x many operations x*double.Epsilon.
-
ccook over 11 yearsEven 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 almost 4 years@BCS, could you please say, what's wrong with "int mod with negative numbers"?
-
Tjkoopa almost 4 yearsThere 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).