52

What I mean is the following:

  double d1 =555;
  double d2=55.343

I want to be able to tell that d1 is an integer while d2 is not. Is there an easy way to do it in c/c++?

Jacob
  • 34,255
  • 14
  • 110
  • 165
vehomzzz
  • 42,832
  • 72
  • 186
  • 216
  • There are hacks to make it work, but the way that a double represents it's value means that it is quite possibly not storing an integer as you think it would. It may store 555 as 554.99999998 or something funny like that. There is no way to tell really, unless you have the original source values and figure it out from there. float and double are limited precision. – Ape-inago Oct 05 '09 at 18:30
  • 7
    @Ape-inago: Actually, a double which is *assigned* an integer value will actually equal that value. And adding, subtracting, and multiplying by integral-valued doubles also yields an integral-valued double. However, once you multiply by an arbitrary double or divide by a double, all bets are off. – rlbond Oct 05 '09 at 18:51
  • 4
    rlbond, assuming the integer in question is sufficiently small. – avakar Oct 05 '09 at 18:56
  • @avakar: And by 'sufficiently small' he means a rather limiting 54 bits. – Jamie Oct 05 '09 at 19:26
  • 2
    What do you want d3 = 3.0 * (1.0 / 3.0) to return? Integer or not? As rlbond pointed out, multiplying by a non-integral double or dividing by anything is likely to result in something that may be extremely close to an integer, but may not be represented as a floating-point integer. – David Thornley Oct 05 '09 at 19:39
  • Caution, a lot of the answers here will not work for numbers close to an integer like 121.000002332 that may have some deviation resulting from earlier floating point calculations. – Jeroen Dirks Dec 07 '11 at 16:31

16 Answers16

96

Use std::modf:

double intpart;
modf(value, &intpart) == 0.0

Don't convert to int! The number 1.0e+300 is an integer too you know.

Edit: As Pete Kirkham points out, passing 0 as the second argument is not guaranteed by the standard to work, requiring the use of a dummy variable and, unfortunately, making the code a lot less elegant.

Alec Jacobson
  • 6,032
  • 5
  • 51
  • 88
avakar
  • 32,009
  • 9
  • 68
  • 103
  • 26
    I had no idea `modf` existed util now. – GManNickG Oct 05 '09 at 18:35
  • 2
    Agreed. +1 for nuggets in the C standard library. Though I would use `NULL` instead of `0` but I understand that's a rather contentious issue in C++ for no good reason. – Chris Lutz Oct 05 '09 at 18:44
  • 1
    should read `modf(value, 0) == 0` as `modf()` returns the fractional part! – Christoph Oct 05 '09 at 19:17
  • 1
    All double values above approximately 10^16 are integers (except positive infinity). – starblue Oct 05 '09 at 19:22
  • 3
    In fact, passing 0 as the second argument is not only not guaranteed to work, but will crash on many platforms. – Stephen Canon Oct 06 '09 at 03:59
  • 7
    I think you better compare modf return value to epsilon rather than zero – qrdl Oct 06 '09 at 07:51
  • 1
    qrdl, you mean for architectures, on which floating point numbers can't represent zero precisely? – avakar Oct 06 '09 at 09:11
  • 7
    Any vaguely competent implementation of modf on a host with IEEE-754 arithmetic will *always* produce an exact fractional part. If your platform doesn't have a vaguely competent implementation of the math library, you should either stick to integer or (better) find a new platform. – Stephen Canon Oct 06 '09 at 12:43
  • 3
    **Note that this method considers a ±∞ to be an integer.** However, you don't need to deal with `NaN` with this one. – Константин Ван Mar 08 '18 at 01:18
19

Assuming a c99 and IEEE-754 compliant environment,

(trunc(x) == x)

is another solution, and will (on most platforms) have slightly better performance than modf because it needs only to produce the integer part. Both are completely acceptable.

Note that trunc produces a double-precision result, so you don't need to worry about out of range type conversions as you would with (int)x.


Edit: as @pavon points out in a comment, you may need to add another check, depending on whether or not you care about infinity, and what result you want to get if x is infinite.

Stephen Canon
  • 103,815
  • 19
  • 183
  • 269
8

Assuming you have the cmath <math.h> library, you can check the number against it's floor. If the number might be negative, make sure you get the absolute first.

bool double_is_int(double trouble) {
   double absolute = abs( trouble );
   return absolute == floor(absolute);
}
TJ L
  • 23,914
  • 7
  • 59
  • 77
7

avakar was almost right - use modf, but the detail was off.

modf returns the fractional part, so the test should be that the result of modf is 0.0.

modf takes two arguments, the second of which should be a pointer of the same type as the first argument. Passing NULL or 0 causes a segmentation fault in the g++ runtime. The standard does not specify that passing 0 is safe; it might be that it happens to work on avakar's machine but don't do it.

You could also use fmod(a,b) which calculates the a modulo b passing 1.0. This also should give the fractional part.

#include<cmath>
#include<iostream>

int main ()
{
    double d1 = 555;
    double d2 = 55.343;

    double int_part1;
    double int_part2;

    using namespace std;

    cout << boolalpha;
    cout << d1 << " " << modf ( d1, &int_part1 ) << endl;
    cout << d1 << " " << ( modf ( d1, &int_part1 ) == 0.0 ) << endl;
    cout << d2 << " " << modf ( d2, &int_part2 ) << endl;
    cout << d1 << " " << ( modf ( d2, &int_part2 ) == 0.0 ) << endl;
    cout << d2 << " " << modf ( d2, &int_part2 ) << endl;
    cout << d1 << " " << ( modf ( d2, &int_part2 ) == 0.0 ) << endl;

    cout << d1 << " " << fmod ( d1, 1.0 ) << endl;
    cout << d1 << " " << ( fmod ( d1, 1.0 ) == 0 ) << endl;
    cout << d2 << " " << fmod ( d2, 1.0 ) << endl;
    cout << d2 << " " << ( fmod ( d2, 1.0 ) == 0 ) << endl;


    cout.flush();

    modf ( d1, 0 ); // segfault

}
Pete Kirkham
  • 48,893
  • 5
  • 92
  • 171
4
int iHaveNoFraction(double d){
    return d == trunc(d);
}

Now, it wouldn't be C if it didn't have about 40 years of language revisions...

In C, == returns int but in C++ it returns bool. At least on my Linux distro (Ubuntu) you need to either declare double trunc(double); or you could compile with -std=c99, or declare the level macro, all in order to get <math.h> to declare it.

moffeltje
  • 4,521
  • 4
  • 33
  • 57
DigitalRoss
  • 143,651
  • 25
  • 248
  • 329
  • 3
    Maybe make the return type bool, since this returns a boolean? – Daniel Bingham Oct 05 '09 at 18:31
  • trunc() is better than floor(). It works for negative numbers. – Martin York Oct 05 '09 at 18:36
  • Alcon, good point, it might be C++. Of course, in C, it *is* `int`. I've clarified things... – DigitalRoss Oct 05 '09 at 18:42
  • 1
    There is no `trunc` in C++ (except for `ios::trunc`). – avakar Oct 05 '09 at 18:44
  • That's not exactly true, try it, at least with g++ it works. While 14882 does not specifically declare trunc, it does state, and I cite C++ 26.5 (2), *The contents of these headers are the same as the Standard C library headers ``*, and conforming implementations of *that* are required to have `trunc()`. But yes, it might be safer to use floor(). – DigitalRoss Oct 05 '09 at 19:21
  • There is no `trunc` in C89 either. – avakar Oct 05 '09 at 19:50
4

Just compare ceil and floor value of d

return floor(d)==ceil(d);

So, for d1=555, the above statement will return 555==555, i.e, true, so it's an integer.

And for d2=555.6, the above statement will return 555==556, i.e, false, so it's a double.

Mayur Agarwal
  • 1,448
  • 1
  • 14
  • 30
2

How about

if (abs(d1 - (round(d1))) < 0.000000001) {
   printf "Integer\n"; /* Can not use "==" since we are concerned about precision */
}

Fixed up to work using rounding to reflect bug Anna found

Alternate solutions:

if ((d1 - floor(d1) < 0.000000001) || (d1 - floor(d1) > 0.9999999999)) {
   /* Better store floor value in a temp variable to speed up */
   printf "Integer\n"; /* Can not use "==" since we are concerned about precision */
}

Theres also another one with taking floor, subtracting 0.5 and taking abs() of that and comparing to 0.499999999 but I figure it won't be a major performance improvement.

DVK
  • 126,886
  • 32
  • 213
  • 327
  • If d = 15,999997, what is returning floor(d)? I do not think this is working. – Patrice Bernassola Oct 05 '09 at 18:24
  • 6
    Integers (at least up to a certain size) are represented exactly in any real implementation of floating point numbers I can think of, so I don't think there's a need to worry about precision for this particular problem. – Laurence Gonsalves Oct 05 '09 at 18:26
  • 3
    What about the case where d1 = 0.999999999999999 ? – Anna Oct 05 '09 at 18:26
  • I believe the precision won't matter, since integers can be represented exactly at all precisions. So you could get away with ==. If there's a counter example that proves me wrong, I'd love to hear about it. – Mark Ransom Oct 05 '09 at 18:26
  • @Patrice: if d =15.999997 then (d - floor(d)) = .999997 Thus it will fail the test above and not be printed. – Martin York Oct 05 '09 at 18:27
  • @Anna - Duh. My only excuse is a fever and no sleep last night. Fixed up – DVK Oct 05 '09 at 18:29
  • Fixed? Now it's really broken - floor is much better than round. – Mark Ransom Oct 05 '09 at 18:30
  • @Lawrence - the precision loss I'm worried about is coming from external sources, not C itself. – DVK Oct 05 '09 at 18:30
  • @ Laurence Gonsalves" That's fine if the value is assigned from a const literal. But if you have been doing some calulations with the number then you __do__ need to worry about precision and you should check to a certain delta. – Martin York Oct 05 '09 at 18:31
  • @Mark - If the # is an integer (or vey close to it), round will result in that integer. Subtracting and taking abs() we will get a very small delta. What is my poor brain missing? – DVK Oct 05 '09 at 18:32
  • Use STL limits to find the minimum value instead of 0.00..1 http://stackoverflow.com/questions/1521607/check-double-variable-if-it-contains-an-integer-and-not-floating-point/1521675#1521675 – Jacob Oct 05 '09 at 18:33
  • 1
    The only problem is that floor goes the wrong way for negative numbers. you should use trunc() – Martin York Oct 05 '09 at 18:35
  • DVK, you just made it a lot worse than before :-) – avakar Oct 05 '09 at 18:38
  • 1
    @Jacob: You don't want to use the minimum value. You need a value that represents the accuracy you need for the application. – Martin York Oct 05 '09 at 18:38
  • @York: Thanks, that is a better design paradigm. – Jacob Oct 05 '09 at 18:39
  • @Martin, floor is a problem for either negs of x.999999 numbers, so I solved by comparing to 0 or 1 in floor-using example – DVK Oct 05 '09 at 18:41
  • 1
    I must apologize. I was fixated on numbers that were exactly integers, not close to integer, and round is a better choice for the solution you provided. – Mark Ransom Oct 06 '09 at 02:36
1
#define _EPSILON_ 0.000001

bool close_to_int(double &d)
{
    double integer,
           fraction = modf(d, &integer);
    if(fraction < _EPSILON_)
    {
        d = integer;
        return true;
    }
    if((1.0 - fraction) < _EPSILON_)
    {
        d = integer + 1;
        return true;
    }
    return false;
}

This looks at both side of the integer value and sets the value of d if it is within the limits of an integer value.

  • `_EPSILON_` is reserved. (Underscore followed by a capital letter). Also there are better techniques that are more reliable to comparing on an arbitrary difference. – Bathsheba Jun 15 '23 at 13:41
0

try:

bool isInteger(double d, double delta)
{
   double absd = abs(d);

   if( absd - floor(absd) > 0.5 )
      return (ceil(absd) - absd) < delta;

   return (d - floor(absd)) < delta;
}
Patrice Bernassola
  • 14,136
  • 6
  • 46
  • 59
0

How about this?

if ((d1 - (int)d1) == 0)
    // integer
Ashwin
  • 3,609
  • 2
  • 18
  • 11
0

modf uses std::nearbyint(num) that why you should use nearbyint which return a double without decimal and may be faster.

#include <iostream>
#include <cmath>

int main() {
    double      number = 55.12;

    if (!(number - std::nearbyint(number))) {
      std::cout << "Is integer!";
    } else {
      std::cout << "Has decimal!";
    }
    
    return 0;
}
user2226755
  • 12,494
  • 5
  • 50
  • 73
-1
#include <math.h>
#include <limits>

int main()
{
  double x, y, n;
  x = SOME_VAL;
  y = modf( x, &n ); // splits a floating-point value into fractional and integer parts
  if ( abs(y) < std::numeric_limits<double>::epsilon() )
  {
    // no floating part
  }
}
Kirill V. Lyadvinsky
  • 97,037
  • 24
  • 136
  • 212
-1

I faced a similar questions. As I needed to round the double anyway, that's what I find working:

double d = 2.000000001;
int i = std::round(d);
std::fabs(d-i) < 10 * std::numeric_limits<double>::epsilon()
Denis
  • 1,526
  • 6
  • 24
  • 40
-1

In many calculations you know that your floating point results will have a small numerical error that can result from a number of multiplications.

So what you may really want to find is the question is this number within say 1e-5 of an integer value. In that case I think this works better:

bool isInteger( double value )
{
    double flr = floor( value + 1e-5 );
    double diff = value - flr;
    return diff < 1e-5;
}
Jeroen Dirks
  • 7,705
  • 12
  • 50
  • 70
-2

A sample code snipped that does it:

if (  ABS( ((int) d1) - (d1)) )< 0.000000001) 

 cout <<"Integer" << endl;

else

 cout <<"Flaot" << endl;

EDIT: Changed it to reflect correct code.

VNarasimhaM
  • 1,460
  • 3
  • 22
  • 36
  • if the # is 1.0000000001 (as can be returned, for exampleDB backend) it will not work. – DVK Oct 05 '09 at 18:24
-2

Below you have the code for testing d1 and d2 keeping it very simple. The only thing you have to test is whether the variable value is equal to the same value converted to an int type. If this is not the case then it is not an integer.

#include<iostream>
using namespace std;

int main()
{
    void checkType(double x);
    double d1 = 555;
    double d2 = 55.343;        
    checkType(d1);
    checkType(d2);
    system("Pause");
    return 0; 
}
void checkType(double x)
{
     if(x != (int)x)
     {
          cout<< x << " is not an integer "<< endl;
     }
     else 
     {
         cout << x << " is an integer " << endl;
     }
};
Igor
  • 26,650
  • 27
  • 89
  • 114
KJP
  • 531
  • 2
  • 9
  • 19