web-dev-qa-db-ja.com

CのdoubleがC ++よりも少ない10進数を出力するのはなぜですか?

このコードはCにあり、0.1をdoubleとして宣言しています。

#include <stdio.h> 
int main() {
    double a = 0.1;

    printf("a is %0.56f\n", a);
    return 0;
}

これが表示されるものです、a is 0.10000000000000001000000000000000000000000000000000000000

C++の同じコード、

#include <iostream>
using namespace std;
int main() {
    double a = 0.1;

    printf("a is %0.56f\n", a);
    return 0;
}

これが表示されるものです、a is 0.1000000000000000055511151231257827021181583404541015625

違いはなんですか?両方を読むと8バイトが割り当てられますか? C++は、小数点以下の桁でより多くの数値をどのように出力しますか?

また、小数点以下55桁までどのように移動できますか? IEEE 754浮動小数点には、小数部用に52ビットしかなく、15桁の精度で取得できます。バイナリで保存されます。どうして10進数の解釈がより多くを格納するのでしょうか

63

MinGW g ++(およびgcc)7.3.0を使用すると、結果が正確に再現されます。

これは、Undefined Behaviorの非常に奇妙なケースです。

未定義の動作は、適切なヘッダーを含めずにprintfを使用しているためです。¹

C++ 17§20.5.2.2

変換ユニットは、宣言または定義の外側にのみヘッダーを含め、その変換ユニットの任意の参照への最初の参照の前に字句的にヘッダーを含めるものとします。そのヘッダーで宣言されたエンティティの。診断は必要ありません。

C++コードで<iostream><stdio.h>に変更して、有効なC++コードを取得します。Cプログラムと同じ結果が得られます。


C++コードがコンパイルされるのはなぜですか?

Cとは異なり、C++では、標準ライブラリヘッダーを他のヘッダーにドラッグできます。そして明らかにg ++では、<iostream>ヘッダーがprintfの宣言にドラッグします。完全に正しいものではありません。

詳細:MinGW g ++ 7.3.0では、printfの宣言/定義はマクロシンボル__USE_MINGW_ANSI_STDIOに依存します。デフォルトでは、<stdio.h>printfを宣言するだけです。ただし、__USE_MINGW_ANSI_STDIOが論理的なtrueとして定義されている場合、<stdio.h>__mingw_vprintfを呼び出すprintfのオーバーライド定義を提供します。そして、たまたま<cstdio>ヘッダーは__USE_MINGW_ANSI_STDIOをインクルードする前に(間接インクルードを介して)<stdio.h>を定義します。

<_mingw.h>にはコメントがあります。「C++の_GNU_SOURCEでも有効にしますが、Cの場合は有効にしないことに注意してください」。

C++では、このコンパイラの関連バージョンでは、<stdio.h>を含めることとprintfを使用すること、または<cstdio>を含めること、using std::printf;と言うこと、およびprintfを使用することの違いが事実上あります。


について

また、小数点以下55桁までどのように移動できますか? IEEE 754浮動小数点の小数部のビット数は52ビットで、10桁の15桁の精度を得ることができます。バイナリで保存されます。どうして10進数の解釈がより多くを格納するのでしょうか

...これは、10進数表現だけです。内部表現の精度(64ビットIEEE 754の場合は約15桁)を超える数字は、基本的にゴミですが、元のビットを正確に再構成するために使用できます。ある時点でそれらはすべてゼロになり、C++プログラム出力の最後の桁でそのポイントに到達します。


1Dietrich Epp に感謝します。

81

どちらの場合も56桁の10進数を出力するように思えるので、質問は技術的には欠陥のある前提に基づいています。

また、両方の数値が52ビットの精度内で0.1と等しいため、両方とも正しいことがわかります。

それはあなたの最終的な質問につながります、「どうしてその10進解釈はもっと多くを格納するのですか?」。 store小数点以下はありません。 doubleは小数を格納しません。ビットを保存します。小数点が生成されます。

10
MSalters