web-dev-qa-db-ja.com

浮動小数点ではなく整数が含まれている場合はdouble変数をチェックします

私が意味することは次のとおりです:

  double d1 =555;
  double d2=55.343

D1は整数で、d2は整数でないことを伝えたいのですが。 c/c ++でそれを行う簡単な方法はありますか?

40
vehomzzz

使用する - std::modf

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

intに変換しないでください!番号 1.0e+300も整数です。

編集:ピート・カーカムが指摘するように、2番目の引数として0を渡すことは、標準では機能しないことが保証されているため、ダミー変数を使用する必要があり、残念ながら、コードのエレガントさが大幅に低下しています。

73
avakar

あなたがcmathを持っていると仮定すると<math.h>ライブラリでは、番号を floor と照合して確認できます。数値が負の値になる可能性がある場合は、まず 絶対 を取得してください。

bool double_is_int(double trouble) {
   double absolute = abs( trouble );
   return absolute == floor(absolute);
}
9
TJ L

C99およびIEEE-754準拠の環境を想定し、

(trunc(x) == x)

もう1つの解決策であり、整数部分を生成するだけでよいため、(ほとんどのプラットフォームで)modfよりもわずかに優れたパフォーマンスが得られます。どちらも完全に許容されます。

truncは倍精度の結果を生成するため、(int)xのように範囲外の型変換を心配する必要はありません。


編集:@ pavonがコメントで指摘しているように、無限大に関心があるかどうか、およびx無限です。

6
Stephen Canon

avakarはほぼ正しく、modfを使用しましたが、詳細はオフになりました。

modfは小数部を返すため、modfの結果が0.0であることをテストする必要があります。

modfは2つの引数を取り、2番目の引数は最初の引数と同じ型のポインターでなければなりません。 NULLまたは0を渡すと、g ++ランタイムでセグメンテーション違反が発生します。この規格では、0を渡すことが安全であるとは規定されていません。それはたまたまavakarのマシンで動作するかもしれませんが、それをしないでください。

a modulo bを1.0として計算するfmod(a,b)を使用することもできます。これも小数部分を与える必要があります。

#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

}
5
Pete Kirkham

いかがですか

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

アンナが発見したバグを反映するために丸めを使用するように修正

代替ソリューション:

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 */
}

床を取り、0.5を引いてabs()を取り、0.499999999と比較する別の方法もありますが、パフォーマンスが大幅に向上することはないと思います。

3
DVK
_int iHaveNoFraction(double d){
    return d == trunc(d);
}
_

さて、約40年の言語修正がなければ、Cにはなりません...

Cでは、_==_はintを返しますが、C++ではboolを返します。少なくとも私のLinuxディストリビューション(Ubuntu)では、double trunc(double);を宣言するか、_-std=c99_を使用してコンパイルするか、レベルマクロを宣言して、_<math.h>_を宣言する必要があります。それ。

3
DigitalRoss

これはどう?

if ((d1 - (int)d1) == 0)
    // integer
2
Ashwin

試してください:

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

多くの計算で、浮動小数点の結果には、いくつかの乗算から生じる可能性のある小さな数値誤差があることがわかっています。

ですから、あなたが本当に見つけたいのは、整数値の1e-5の範囲内にあるこの数です。その場合、私はこれがうまくいくと思います:

bool isInteger( double value )
{
    double flr = floor( value + 1e-5 );
    double diff = value - flr;
    return diff < 1e-5;
}
0
Jeroen Dirks
#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
  }
}

私は同様の質問に直面しました。とにかくダブルを丸める必要があったので、それが私が機能しているものです:

double d = 2.000000001;
int i = std::round(d);
std::fabs(d-i) < 10 * std::numeric_limits<double>::epsilon()
0
Denis

以下に、d1とd2をテストして非常にシンプルに保つためのコードを示します。テストする必要があるのは、変数の値がint型に変換された同じ値と等しいかどうかだけです。そうでない場合は、整数ではありません。

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