简体   繁体   English

检查 double 变量是否包含 integer,而不是浮点数

[英]Check double variable if it contains an integer, and not floating point

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.我想知道 d1 是 integer 而 d2 不是。 Is there an easy way to do it in c/c++?有没有一种简单的方法可以在 c/c++ 中做到这一点?

Use std::modf :使用std::modf

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

Don't convert to int !不要转换为int The number 1.0e+300 is an integer too you know.你知道,数字1.0e+300也是一个整数。

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.编辑:正如 Pete Kirkham 指出的那样,标准不保证将 0 作为第二个参数传递,需要使用虚拟变量,不幸的是,这使代码变得不那么优雅。

Assuming a c99 and IEEE-754 compliant environment,假设一个符合 c99 和 IEEE-754 的环境,

(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.是另一种解决方案,并且(在大多数平台上)的性能比modf略好,因为它只需要生成整数部分。 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 .请注意, trunc产生双精度结果,因此您无需像使用(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.编辑:正如@pavon在评论中指出的那样,您可能需要添加另一个检查,这取决于您是否关心无穷大,以及如果x是无穷大,您想要得到什么结果。

Assuming you have the cmath <math.h> library, you can check the number against it's floor .假设您有 cmath <math.h>库,您可以根据它的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);
}

avakar was almost right - use modf, but the detail was off. avakar 几乎是正确的 - 使用 modf,但细节已关闭。

modf returns the fractional part, so the test should be that the result of modf is 0.0. modf 返回小数部分,所以测试应该是 modf 的结果是 0.0。

modf takes two arguments, the second of which should be a pointer of the same type as the first argument. modf 接受两个参数,其中第二个参数应该是与第一个参数类型相同的指针。 Passing NULL or 0 causes a segmentation fault in the g++ runtime.传递 NULL 或 0 会导致 g++ 运行时出现分段错误。 The standard does not specify that passing 0 is safe;该标准没有规定传递 0 是安全的; it might be that it happens to work on avakar's machine but don't do it.可能是它碰巧在 avakar 的机器上工作,但不要这样做。

You could also use fmod(a,b) which calculates the a modulo b passing 1.0.您还可以使用fmod(a,b)计算通过 1.0 的ab 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

}
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...现在,如果没有大约 40 年的语言修订,它就不会是 C...

In C, == returns int but in C++ it returns bool .在 C 中, ==返回int但在 C++ 中它返回bool At least on my Linux distro (Ubuntu) you need to either declare double trunc(double);至少在我的 Linux 发行版 (Ubuntu) 上,您需要声明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.或者您可以使用-std=c99编译,或声明级别宏,所有这些都是为了让<math.h>声明它。

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修复了使用舍入来反映 Anna 发现的错误的工作

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.还有另一种使用发言权,减去 0.5 并取 abs() 并与 0.499999999 进行比较,但我认为这不会是重大的性能改进。

How about this?这个怎么样?

if ((d1 - (int)d1) == 0)
    // integer
#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.这会查看整数值的两侧并设置 d 的值(如果它在整数值的范围内)。

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;
}
#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
  }
}

Below you have the code for testing d1 and d2 keeping it very simple.下面是测试 d1 和 d2 的代码,使其非常简单。 The only thing you have to test is whether the variable value is equal to the same value converted to an int type.您唯一需要测试的是变量值是否等于转换为 int 类型的相同值。 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;
     }
};

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()

Just compare ceil and floor value of d只需比较 d 的 ceil 和 floor 值

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

So, for d1=555 , the above statement will return 555==555 , ie, true , so it's an integer.因此,对于d1=555 ,上述语句将return 555==555 ,即true ,因此它是一个整数。

And for d2=555.6 , the above statement will return 555==556 , ie, false , so it's a double.对于d2=555.6 ,上面的语句将return 555==556 ,即false ,所以它是一个双精度值。

modf uses std::nearbyint(num) that why you should use nearbyint which return a double without decimal and may be faster. modf使用std::nearbyint(num)这就是为什么你应该使用nearbyint返回一个不带小数的双精度并且可能更快。

#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;
}

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.所以你可能真正想找到的问题是这个数字在整数值的 1e-5 之内。 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;
}

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.编辑:更改它以反映正确的代码。

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

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