メインコンテンツ

整数から浮動小数点への変換での桁落ち

浮動小数点型への変換中に失われる整数の最下位ビット

説明

この欠陥は、整数値がその整数値を表現できない浮動小数点型にキャストされた場合に発生します。

たとえば、long int 型の値 1234567890L は、float 型の変数には大きすぎます。

リスク

浮動小数点型が整数値を表現できない場合、その動作は未定義になります (C11 規格、6.3.1.4、段落 2 を参照)。たとえば、変数値の最下位ビットが破棄され、予期しない結果につながる可能性があります。

修正方法

整数値を表現できる浮動小数点型に変換します。

たとえば、float データ型で整数値を表現できない場合は、代わりに double データ型を使用します。

整数を浮動小数点型に変換する関数を記述する場合、変換の前に、浮動小数点型で整数値を表現できるかどうかをチェックします。たとえば、DBL_MANT_DIG * log2(FLT_RADIX) は 2 を基数とする場合の桁数を double 型で表現します。double 型に変換する前に、この数が変換予定の整数の精度以上かどうかをチェックします。整数 num の精度を求めるには、以下のコードを使用します。

 size_t precision = 0;
 while (num != 0) {
    if (num % 2 == 1) {
      precision++;
    }
    num >>= 1;
 }

一部の実装では、整数の精度を求める組み込み関数が提供されています。たとえば、GCC では関数 __builtin_popcount が用意されています。

すべて展開する

#include <stdio.h>

int main(void) {
  long int big = 1234567890L;
  float approx = big;
  printf("%ld\n", (big - (long int)approx));
  return 0;
}

この C コードでは、long int 型の変数 bigfloat に変換されています。

修正 — より大きな浮動小数点型を使用

1 つの修正方法として、float ではなく double データ型に変換します。

#include <stdio.h>

int main(void) {
  long int big = 1234567890L;
  double approx = big;
  printf("%ld\n", (big - (long int)approx));
  return 0;
}

結果情報

グループ: 数値
言語: C | C++
既定値: オフ
コマンド ライン構文: INT_TO_FLOAT_PRECISION_LOSS
影響度: Low

バージョン履歴

R2018b で導入