简体   繁体   English

C ++确定数字是否为整数

[英]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. 我有一个用C ++编写的程序,其中我将两个数相除,我需要知道答案是否为整数。 What I am using is: 我正在使用的是:

if(fmod(answer,1) == 0) 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. 问题是答案通常是5位数字,但有许多小数。 For example, answer can be: 58696.000000000000000025658 and the program considers that an integer. 例如,答案可以是: 58696.000000000000000025658 ,并且程序认为该整数。

Is there any way I can make this work? 有什么办法可以使这项工作吗?

I am dividing double a/double b= double answer 我将double a/double b= double answer

(sometimes there are more than 30 decimals) (有时超过30个小数)

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). 编辑:a和b是数以千计(约100,000),然后将其提高为2和3的幂,相加并相除(根据一个复杂的公式)。 So I am plugging in various a and b values and looking at the answer. 因此,我插入各种a和b值并查看答案。 I will only keep the a and b values that make the answer an integer. 我只会保留使答案成为整数的a和b值。 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. 我得到一个答案的例子是:218624,上面的程序认为它是整数,但实际上是:218624.00000000000000000056982因此,我需要一个可以区分具有20-30个以上十进制小数的整数的代码。

You can use std::modf in cmath.h : 您可以在cmath.h使用std::modf

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 . answer的整数部分存储在fractionstd::modf的返回值是answer的分数部分,其符号与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. 在这里, answer实际上保持值为0.99999... ,因此我们无法将其与整数进行比较,也无法检查小数部分是否接近0。通常,由于数字的浮点表示可以是一位小于或大于实际数字,则不宜检查小数部分是否接近0。它可能是0.999999990.000001 (甚至它们的负数)之类的数字,这些都是精度损失的可能结果。 That's also why I'm checking both sides ( +epsilon and -epsilon ). 这就是为什么我要同时检查两面( +epsilon-epsilon )。 You should adjust that epsilon variable to fit your needs. 您应该调整该epsilon变量以适合您的需求。

Also, keep in mind that the precision of a double is close to 15 digits . 另外,请记住, double精度的精度接近15位数 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 . 您还可以使用long double精度数,这可能会给您带来一些额外的精度数字(或者不是,这取决于编译器),但是即使这样也只能使您达到18位数左右。 If you need more precision than that, you will need to use an external library, like GMP . 如果您需要的精度更高,则需要使用外部库,例如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 : 相反,您需要测试差异是否小于某个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::fmod返回的余数将在[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. 浮点数通常会精确到大约12至15位数(以double ),但由于它们以尾数(分数)存储,并且指数形式的有理数(整数或普通分数)不太可能这样存储。 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 ): 因此,您需要将期望值的差异与包含所需精度的一个很小的数字进行比较(我们将这个值称为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. 因此,当您尝试比较std::fmod的其余部分时,需要将其与0.0之差(不是实际等于0.0 )进行检查,这就是上面所做的。

Also, the std::fabs call prevents you from having to do 2 checks by asserting that the value will always be positive. 同样, std::fabs调用通过断言该值始终为正值来防止您必须进行两次检查。

If you desire a precision that is greater than 15-18 decimal places, you cannot use double or long double ; 如果您希望精度达到小数点后15-18位,则不能使用doublelong double you will need to use a high precision floating point library. 您将需要使用高精度浮点库。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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