247

How do I tell if a decimal or double value is an integer?

For example:

decimal d = 5.0; // Would be true
decimal f = 5.5; // Would be false

or

double d = 5.0; // Would be true
double f = 5.5; // Would be false

The reason I would like to know this is so that I can determine programmatically if I want to output the value using .ToString("N0") or .ToString("N2"). If there is no decimal point value, then I don't want to show that.

hopper
  • 12,140
  • 7
  • 48
  • 50
Jim Geurts
  • 19,124
  • 23
  • 91
  • 105

14 Answers14

460

For floating point numbers, n % 1 == 0 is typically the way to check if there is anything past the decimal point.

public static void Main (string[] args)
{
    decimal d = 3.1M;
    Console.WriteLine((d % 1) == 0);
    d = 3.0M;
    Console.WriteLine((d % 1) == 0);
}

Output:

False
True

Update: As @Adrian Lopez mentioned below, comparison with a small value epsilon will discard floating-point computation mis-calculations. Since the question is about double values, below will be a more floating-point calculation proof answer:

Math.Abs(d % 1) <= (Double.Epsilon * 100)
Dan Atkinson
  • 10,801
  • 12
  • 78
  • 106
Mark Rushakoff
  • 224,642
  • 43
  • 388
  • 389
  • 104
    That works when the number starts out as a whole number, but not necessarily when the number is the result of some floating-point computation. How about something like "(d % 1) < epsilon" where epsion is some small value? – Adrian Lopez May 01 '10 at 22:23
  • 9
    It's a shame that the best answer in this thread is a comment, rather than the accepted answer. Nice one Adrian. – starskythehutch Nov 30 '11 at 12:35
  • The answer given by @MarkRushakoff fails for the input like `2.719601835756618E9` which is a double – Ram Patra Mar 09 '14 at 06:49
  • 13
    I also think Adrian's comment above is the best answer. To put his advice in formal C# code: if (Math.Abs(n % 1) < Double.Epsilon) {// Do something if n is integer}. – Ruben Ramirez Padron Mar 09 '15 at 20:12
  • 1
    @RubenRamirezPadron Is eps comparison only required for double? Can we use equality comparison for decimal? – user764754 Apr 10 '15 at 10:36
  • 10
    Actually, as the question is stated, this answer is correct and the comments are wrong. The OP doesn't want to know whether a double is an integer for mathematical purposes, but rather how to display it. Only *exact* integer values should be displayed without a decimal point. Also, the comment about about mod not being useful with floating point and not working outside of .NET is not well informed. And `(int)d` is a disaster that will throw an exception for most double values. – Jim Balter Mar 30 '16 at 00:14
  • I edited the answer to add @AdrianLopez's comment since it discards floating-point-calculation flaws – FallenAngel Dec 20 '16 at 11:39
  • 1
    I have edited the answer to use Double.Epsilon * 100 because d < Double.Epsilon is equivalent with d == 0. This is because Double.Epsilon is the smallest possible positive value. For example also mentioned here http://stackoverflow.com/a/31656800/1161635. Instead developer must choose a suitable epsilon. – Herman Jan 05 '17 at 16:05
  • 3
    double.Epsilon * 100 is also not suitable. A proper epsilon value needs to be scaled to the values being compared. The smallest possible change in a double is a fraction of the value, not a fixed amount. The value they chose for C# double.Epsilon is also particularly bad because they used a different concept than DBL_EPSILON in C that's been around for decades and is actually useful. – tukra May 02 '18 at 15:26
  • 1
    I'd test if the value is aktual between int.MinValue and int.MaxValue as well – Walter Vehoeven Aug 20 '18 at 12:59
  • To add to turka's comment: Even if we believed Double.Epsilon was relevant here (which it is not) why should we believe that floating point errors would accrue such to create decimals slightly larger than integers, and not slightly smaller? E.g. 1.00000000001 % 1 is 0.00000000001, but 0.99999999999 % 1 is 0.99999999999. Why is the former any more integer like than the latter? – Andrew Jun 30 '20 at 22:32
  • VB equivalent ```if variable mod 1 = 0 then ' its an integer ``` – user2728841 Nov 01 '20 at 08:49
  • The updated answer (`Math.Abs(d % 1) <= (Double.Epsilon * 100)`) will not work for `double result = 0.31d + 0.27d - 0.58d;` – YantingChen Dec 01 '20 at 06:07
51

There are any number of ways to do this. For example:

double d = 5.0;
bool isInt = d == (int)d;

You can also use modulo.

double d = 5.0;
bool isInt = d % 1 == 0;
Erik Funkenbusch
  • 90,480
  • 27
  • 178
  • 274
  • Would one of these be faster than the other? I'm wanting to do this in a performance sensitive context. – Basil Dec 04 '13 at 03:35
  • @Basil - Depends on the circumstances. You should do some timings for yourself and judge. – Erik Funkenbusch Dec 04 '13 at 22:09
  • 4
    `Math.Abs(d-(int)d) < double.Epsilon` is safer than `d == (int)d` – Reactgular Jan 31 '14 at 15:38
  • @MathewFoscarini - How exactly is it "safer"? Or did you mean more accurate? – Erik Funkenbusch Jan 31 '14 at 17:02
  • I mean it accounts for floating point errors. `double d = 16.1 - 6.1; bool isInt = d % 1 == 0;` will set `isInt` to false. Don't know if the word accurate or safer is the right one. The original question was using `decimal` but this answer is in `double`, and using double your answer doesn't always work. – Reactgular Jan 31 '14 at 17:15
  • sorry, both `d == (int)d` and `d % 1 == 0` didn't work in my example. – Reactgular Jan 31 '14 at 17:17
  • 3
    @MathewFoscarini - I think you're confused. It sets it to false, because the result of 16.1 - 6.1 is not an int. The point was to find if a given value is an int, not if something that is approximately an int is an int. – Erik Funkenbusch Jan 31 '14 at 18:56
  • @MystereMan how do you define int? Int for me is any number without a decimal value. 16.1-6.1 should equal 10.0 but it doesn't if you use double. In C# the following is true 10.0 != (16.1-6.1) – Reactgular Jan 31 '14 at 21:08
  • 1
    @MathewFoscarini - Yes, an int is a number without a decimal value (or a decimal value of 0). 16.1-6.1 does not create a 0 decimal value, it's a very small non-zero value that is caused by IEEE Floating Point format quirks. There is no way to know whether the number is SUPPOSED to have a decimal value or not, so assuming a rounding value is just as inaccurate. The purpose of the question was to know whether a floating point number was an integer, not whether it was approximately an integer. – Erik Funkenbusch Jan 31 '14 at 21:21
23

How about this?

public static bool IsInteger(double number) {
    return number == Math.Truncate(number);
}

Same code for decimal.

Mark Byers made a good point, actually: this may not be what you really want. If what you really care about is whether a number rounded to the nearest two decimal places is an integer, you could do this instead:

public static bool IsNearlyInteger(double number) {
    return Math.Round(number, 2) == Math.Round(number);
}
Dan Tao
  • 119,009
  • 50
  • 280
  • 431
12

Whilst the solutions proposed appear to work for simple examples, doing this in general is a bad idea. A number might not be exactly an integer but when you try to format it, it's close enough to an integer that you get 1.000000. This can happen if you do a calculation that in theory should give exactly 1, but in practice gives a number very close to but not exactly equal to one due to rounding errors.

Instead, format it first and if your string ends in a period followed by zeros then strip them. There are also some formats that you can use that strip trailing zeros automatically. This might be good enough for your purpose.

double d = 1.0002;
Console.WriteLine(d.ToString("0.##"));
d = 1.02;
Console.WriteLine(d.ToString("0.##"));

Output:

1
1.02
Mark Byers
  • 719,658
  • 164
  • 1,497
  • 1,412
  • @Mark Sounds interesting. Do you have an example of a format that strips trailing zeros? – Jim Geurts May 01 '10 at 21:47
  • I agree that it is safer and what the OP should probably do, but it is not an answer to the narrower (but more interesting) question of whether a value has a fractional part or not. – Clifford May 01 '10 at 22:10
  • 3
    @Clifford: I usually try to answer based on what is best to solve the OPs problem, not based on what the title says. Titles are rarely an accurate description of the problem. – Mark Byers May 01 '10 at 22:25
  • +1 Agree that trying to test floats or doubles to see if they could be ints is bad due to rounding and precision errors. – Romain Hippeau May 02 '10 at 01:42
  • 1
    For money usage, you would probably want 1.2 to be displayed as 1.20, which is not the case with the suggested solution. Any takers? – Kjell Rilbe Apr 29 '14 at 14:15
  • For money, d.ToString("0.00") – PRMan May 19 '16 at 12:32
10
bool IsInteger(double num) {
    if (ceil(num) == num && floor(num) == num)
        return true;
    else
        return false;
}

Problemo solvo.

Edit: Pwned by Mark Rushakoff.

Puppy
  • 138,897
  • 33
  • 232
  • 446
4

Mark Rushakoff's answer may be simpler, but the following also work and may be more efficient since there is no implicit division operation:

     bool isInteger = (double)((int)f) == f ;

and

     bool isInteger = (decimal)((int)d) == d ;

If you want a single expression for both types, perhaps

     bool isInteger = (double)((int)val) == (double)val ;
Clifford
  • 76,825
  • 12
  • 79
  • 145
4
static bool IsWholeNumber(double x) 
{
    return Math.Abs(x % 1) < double.Epsilon;
}
pomber
  • 19,363
  • 9
  • 71
  • 90
4

If upper and lower bound of Int32 matters:

public bool IsInt32(double value)
{
    return  value >= int.MinValue && value <= int.MaxValue && value == (int)value;
}
nawfal
  • 62,042
  • 48
  • 302
  • 339
2

You can use String formatting for the double type. Here is an example:

double val = 58.6547;
String.Format("{0:0.##}", val);      
//Output: "58.65"

double val = 58.6;
String.Format("{0:0.##}", val);      
//Output: "58.6"

double val = 58.0;
String.Format("{0:0.##}", val);      
//Output: "58"

Let me know if this doesn't help.

hopper
  • 12,140
  • 7
  • 48
  • 50
BALKANGraph
  • 1,987
  • 1
  • 14
  • 16
  • 1
    That does not really address the question of determining if a value has no fractional part, which is a mathematical question. It is however probably what the OP needs given his explanatory note. – Clifford May 01 '10 at 22:04
  • 2
    Yes, he want just to format double or decimal value without decimal point. Thank you... – BALKANGraph May 01 '10 at 22:27
1
    public static bool isInteger(decimal n)
    {
        return n - (Int64)n == 0;
    }
0

Using int.TryParse will yield these results:

        var shouldBeInt = 3;

        var shouldntBeInt = 3.1415;

        var iDontWantThisToBeInt = 3.000f;

        Console.WriteLine(int.TryParse(shouldBeInt.ToString(), out int parser)); // true

        Console.WriteLine(int.TryParse(shouldntBeInt.ToString(), out parser)); // false

        Console.WriteLine(int.TryParse(iDontWantThisToBeInt.ToString(), out parser)); // true, even if I don't want this to be int

        Console.WriteLine(int.TryParse("3.1415", out  parser)); // false

        Console.WriteLine(int.TryParse("3.0000", out parser)); // false

        Console.WriteLine(int.TryParse("3", out parser)); // true

        Console.ReadKey();
morethanyell
  • 186
  • 1
  • 8
0

I faced a similar situation, but where the value is a string. The user types in a value that's supposed to be a dollar amount, so I want to validate that it's numeric and has at most two decimal places.

Here's my code to return true if the string "s" represents a numeric with at most two decimal places, and false otherwise. It avoids any problems that would result from the imprecision of floating-point values.

try
{
    // must be numeric value
    double d = double.Parse(s);
    // max of two decimal places
    if (s.IndexOf(".") >= 0)
    {
        if (s.Length > s.IndexOf(".") + 3)
            return false;
    }
    return true;
catch
{
    return false;
}

I discuss this in more detail at http://progblog10.blogspot.com/2011/04/determining-whether-numeric-value-has.html.

Allan Pereira
  • 2,551
  • 4
  • 18
  • 26
Steve
  • 1
  • 4
    This assumes that you're working with one culture. For example, It would not work properly with cultures that represent decimals like 1.000,00 – Jim Geurts Apr 10 '11 at 16:15
-2

Try this:

number == Convert.ToInt16(number);
-3

Perhaps not the most elegant solution but it works if you are not too picky!

bool IsInteger(double num) {
    return !num.ToString("0.################").Contains(".");
}
Johan
  • 70
  • 2
  • 1