web-dev-qa-db-ja.com

floatが整数かどうかを確認する

float変数に整数値が含まれているかどうかを確認するにはどうすればよいですか?これまでのところ、私は使用しています:

float f = 4.5886;
if (f-(int)f == 0)
     printf("yes\n");
else printf("no\n");

しかし、より良い解決策があるのか​​、それとも何らかの(または多くの)欠点があるのか​​疑問に思います。

65
sidyll

既に与えられたすばらしい答えとは別に、ceilf(f) == fまたはfloorf(f) == fを使用することもできます。 trueが整数の場合、両方の式はfを返します。また、ReturnfalseはNaN( NaNは常に等しくない )およびtrueは±∞であり、切り捨てられた結果を保持するために使用される整数型のオーバーフローに関する問題はありませんfloorf()/ceilf()floatsを返すため。

66

ここでのテクニックのほとんどは、事前の計算による丸め誤差は要因ではないと仮定して有効であることに留意してください。例えば。 youcould次のようにroundfを使用します:

_float z = 1.0f;

if (roundf(z) == z) {
    printf("integer\n");
} else {
    printf("fraction\n");
}
_

これや他の同様の手法(ceilflongへのキャストなど)の問題は、整数定数に対してはうまく機能するが、数値が浮動小数点の丸め誤差の影響を受けた計算の結果。例えば:

_float z = powf(powf(3.0f, 0.05f), 20.0f);

if (roundf(z) == z) {
    printf("integer\n");
} else {
    printf("fraction\n");
}
_

(31/2020 実際の計算結果は2.9999992847442626953125であるため、3に等しくなければなりません。

fmodfまたはその他の同様の方法は、この対象となります。複雑な計算または丸めがちな計算を実行するアプリケーションでは、通常、「全体数」を構成するものの「許容値」を定義します(これは一般に浮動小数点の等値比較に使用されます)。この許容値epsilonとよく呼ばれます。たとえば、コンピューターに最大+/- 0.00001の丸め誤差を許すとしましょう。次に、zをテストしている場合、0.00001のイプシロンを選択して実行できます。

_if (fabsf(roundf(z) - z) <= 0.00001f) {
    printf("integer\n");
} else {
    printf("fraction\n");
}
_

ここでceilfを使用したくないのは、たとえばceilf(1.0000001)は1ではなく2であり、ceilf(-1.99999999)は-2ではなく-1です。

rintfの代わりにroundfを使用することもできます。

アプリケーションに適した許容値を選択します(そして、はい、場合によっては許容値ゼロが適切です)。詳細については、この記事の 浮動小数点数の比較 をご覧ください。

18
Jason C

stdlib float modf(float x、float * ipart)は2つの部分に分割され、戻り値(小数部分)== 0かどうかを確認します。

9
DavidN
if (fmod(f, 1) == 0.0) {
  ...
}

math.hおよびlibm

if (f <= LONG_MIN || f >= LONG_MAX || f == (long)f) /* it's an integer */
4
R..

100%確信はありませんが、fをintにキャストし、fからそれを引くと、floatにキャストし直されていると思います。この場合、これはおそらく問題になりませんが、何らかの理由でintであると予想している場合は、将来的に問題が発生する可能性があります。

それ自体がより良い解決策であるかどうかはわかりませんが、代わりにモジュラスの数学を使用することができます、例えば:float f = 4.5886; bool isInt; isInt = (f % 1.0 != 0) ? false : true;暗黙のキャストが作用します。このコードでは、bool isIntは、小数点の右側がすべてゼロの場合はtrue、そうでない場合はfalseである必要があります。

0
Controllerface
#define twop22 (0x1.0p+22)
#define ABS(x) (fabs(x))
#define isFloatInteger(x) ((ABS(x) >= twop22) || (((ABS(x) + twop22) - twop22) == ABS(x)))
0
kanna