简体   繁体   中英

C++ determining if a number is an integer

I have a program in C++ where I divide two numbers, and I need to know if the answer is an integer or not. What I am using is:

if(fmod(answer,1) == 0)

I also tried this:

if(floor(answer)==answer)

The problem is that answer usually is a 5 digit number, but with many decimals. For example, answer can be: 58696.000000000000000025658 and the program considers that an integer.

Is there any way I can make this work?

I am dividing double a/double b= double answer

(sometimes there are more than 30 decimals)

Thanks!

EDIT: a and b are numbers in the thousands (about 100,000) which are then raised to powers of 2 and 3, added together and divided (according to a complicated formula). So I am plugging in various a and b values and looking at the answer. I will only keep the a and b values that make the answer an integer. An example of what I got for one of the answers was: 218624 which my program above considered to be an integer, but it really was: 218624.00000000000000000056982 So I need a code that can distinguish integers with more than 20-30 decimals.

You can use std::modf in cmath.h :

double integral;
if(std::modf(answer, &integral) == 0.0)

The integral part of answer is stored in fraction and the return value of std::modf is the fractional part of answer with the same sign as answer .

The usual solution is to check if the number is within a very short distance of an integer, like this:

bool isInteger(double a){
    double b=round(a),epsilon=1e-9; //some small range of error
    return (a<=b+epsilon && a>=b-epsilon); 
}

This is needed because floating point numbers have limited precision, and numbers that indeed are integers may not be represented perfectly. For example, the following would fail if we do a direct comparison:

double d=sqrt(2); //square root of 2
double answer=2.0/(d*d); //2 divided by 2

Here, answer actually holds the value 0.99999... , so we cannot compare that to an integer, and we cannot check if the fractional part is close to 0. In general, since the floating point representation of a number can be either a bit smaller or a bit bigger than the actual number, it is not good to check if the fractional part is close to 0. It may be a number like 0.99999999 or 0.000001 (or even their negatives), these are all possible results of a precision loss. That's also why I'm checking both sides ( +epsilon and -epsilon ). You should adjust that epsilon variable to fit your needs.

Also, keep in mind that the precision of a double is close to 15 digits . You may also use a long double , which may give you some extra digits of precision (or not, it is up to the compiler), but even that only gets you around 18 digits . If you need more precision than that, you will need to use an external library, like GMP .

Floating point numbers are stored in memory using a very different bit format than integers. Because of this, comparing them for equality is not likely to work effectively. Instead, you need to test if the difference is smaller than some epsilon :

const double EPSILON = 0.00000000000000000001; // adjust for whatever precision is useful for you
double remainder = std::fmod(numer, denom);
if(std::fabs(0.0 - remainder) < EPSILON)
{
    //...
}

Alternatively, if you want to include values that are close to integers (based on your desired precision), you can modify the if condition slightly (since the remainder returned by std::fmod will be in the range [0, 1) ):

if (std::fabs(std::round(d) - d) < EPSILON)
{
    // ...
}

You can see the test for this here .

Floating point numbers are generally somewhat precise to about 12-15 digits (as a double ), but as they are stored as a mantissa (fraction) and a exponent, rational numbers (integers or common fractions) are not likely to be stored as such. For example,

double d = 2.0; // d might actually be 1.99999999999999995

Because of this, you need to compare the difference of what you expect to some very small number that encompasses the precision you desire (we will call this value, epsilon ):

double d = 2.0;
bool test = std::fabs(2 - d) < epsilon; // will return true

So when you are trying to compare the remainder from std::fmod , you need to check it against the difference from 0.0 (not for actual equality to 0.0 ), which is what is done above.

Also, the std::fabs call prevents you from having to do 2 checks by asserting that the value will always be positive.

If you desire a precision that is greater than 15-18 decimal places, you cannot use double or long double ; you will need to use a high precision floating point library.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM