web-dev-qa-db-ja.com

すべての整数値は完全にdoubleとして表されていますか?

私の質問は、すべての整数値が完全な二重表現を持つことが保証されているかどうかです。

「同じ」を出力する次のコードサンプルを検討してください。

// Example program
#include <iostream>
#include <string>

int main()
{
  int a = 3;
  int b = 4;
  double d_a(a);
  double d_b(b);

  double int_sum = a + b;
  double d_sum = d_a + d_b;

  if (double(int_sum) == d_sum)
  {
      std::cout << "Same" << std::endl;
  }
}

これは、アーキテクチャ、コンパイラ、aおよびbのすべての値に当てはまることが保証されていますか? iに変換された整数doubleは、たとえばi.0000000000000ではなく、常にi.000000000001として表されますか?

私は他のいくつかの数字で試してみましたが、それは常に真実でしたが、これが偶然なのか、設計によるのかについては何も見つけることができませんでした。

注:これは、2つの整数を追加するため、 この質問 (言語は別として)とは異なります。

55
Thomas

免責事項(Toby Speightが提案):IEEE 754表現は非常に一般的ですが、実装では言語の要件を満たす他の表現を使用することが許可されています。


Doubleはmantissa * 2^exponentの形式で表されます。つまり、一部のビットはdoubleの整数以外の部分に使用されます。

             bits        range                       precision
  float        32        1.5E-45   .. 3.4E38          7- 8 digits
  double       64        5.0E-324  .. 1.7E308        15-16 digits
  long double  80        1.9E-4951 .. 1.1E4932       19-20 digits

Schematic of IEEE 754 double type

分数の部分は、ドットの後のすべての数字を削除する指数を使用して整数を表すためにも使用できます。

例えば。 2,9979・10 ^ 4 = 29979。

一般的なintは通常32ビットなので、すべてのintsをdoubleとして表すことができますが、64ビット整数の場合、これはもはや当てはまりません。より正確に(コメントでLThodeが述べているように):IEEE 754倍精度は、これを最大53ビット(仮数の52ビット+暗黙の先行1ビット)に対して保証できます。

Answer:32ビット整数の場合はyes、64ビット整数の場合はno.

(これは、サーバー/デスクトップの汎用CPU環境に適していますが、他のアーキテクチャの動作は異なる場合があります。)

Palical AnswerMalcom McLeanは次のように述べています。


経験的に傾斜している場合は、 this を試してください。

#include <iostream>
#include <limits>
using namespace std;

int main() {
    double test;
    volatile int test_int;
    for(int i=0; i< std::numeric_limits<int>::max(); i++) {
        test = i;
        test_int = test;

        // compare int with int:
        if (test_int != i)
            std::cout<<"found integer i="<<i<<", test="<<test<<std::endl;
    }
    return 0;
}

成功時間:0.85メモリ:15240信号:0


Subquestion:わずかな違いの質問について。分数だけ正しい値から外れているが、丸めのために同じ整数に戻るdoubleに変換する整数を持つことは可能ですか?

答えはノーです。なぜなら、同じ値に行き来する整数は、実際には同じ整数値をdoubleで表しているからです。私にとってこれに関する最も簡単な説明(ilkkachuが提案)は、指数2^exponentを使用すると、ステップ幅は常に2のべき乗でなければならないということです。したがって、最大の52(+1符号)ビット整数を超えると、距離が2未満のdouble値が2つなくなり、丸めの問題が解決されます。

71
Beginner

いいえ。64ビット整数型と64ビット浮動小数点型(doubleに一般的)があるとします。その整数型には2 ^ 64の値があり、その浮動小数点型には2 ^ 64の値があります。ただし、これらの浮動小数点値の一部(実際にはほとんど)は整数値を表さないため、浮動小数点型は整数型よりも少ない整数値を表すことができます。

15
Pete Becker

答えはノーです。これは、intsが32ビットの場合にのみ機能します。これは、ほとんどのプラットフォームではtrueですが、標準では保証されていません。

2つの整数は同じdouble表現を共有できます。

たとえば、 this

#include <iostream>
int main() {
    int64_t n = 2397083434877565865;
    if (static_cast<double>(n) == static_cast<double>(n - 1)) {
        std::cout << "n and (n-1) share the same double representation\n";
    }
}    

印刷します

nと(n-1)は同じ二重表現を共有します

つまり2397083434877565865と2397083434877565864の両方が同じdoubleに変換されます。

ここではint64_tを使用して64ビット整数を保証していることに注意してください。これは、プラットフォームによってはintでもある場合があります。

11
Corristo

次の2つの質問があります。

すべての整数値は完全にdoubleとして表されていますか?

それはすでに他の人々によって回答されました(TL; DR:intdoubleの精度に依存します)。

「同じ」を出力する次のコード例を考えてみてください。[...]これは、アーキテクチャ、コンパイラ、aおよびbの値に当てはまることが保証されていますか?

コードは2つのintsを追加し、thenは結果をdoubleに変換します。 intsの合計willは特定の値に対してオーバーフローしますが、2つの個別に変換されたdoublesの合計は(通常)オーバーフローしません。これらの値では、結果が異なります。

4
Pablo H

短い答えは「おそらく」です。ポータブルな答えは「どこでもない」です。

それは本当にあなたのプラットフォームに依存し、特に、

  • doubleのサイズと表現
  • intの範囲

IEEE-754倍精度を使用するプラットフォームでは、intが53ビット以下の場合、mayが真になります。 intdoubleより大きいプラットフォームの場合、明らかにfalseです。

std::numeric_limitsおよびstd::nextafterを使用して、ランタイムホストのプロパティを調査できる場合があります。

2
Toby Speight