HIT-ICS Lab1 問題プログラム動作解析:浮動小数点数の落とし穴

記事ディレクトリ

問題の説明

注: このトピックは、2022 Spring HIT-ICS Lab1 プログラム動作分析 (2) 浮動小数点数の落とし穴から引用したものですが、
参考のために慎重に書いたつもりです。間違っている場合は、修正してください。

コードの一部を考えると、次のようになります。

int main(){
    
    
	float f;
	for(;;){
    
    
		printf("请输入一个浮点数:");
		scanf("%f", &f);
		printf("这个浮点数的值是:%f\n",f);
		if (f==0) break;
	}
	return 0;
}

実行入力:
61.419997
61.419998
61.419999
61.420000
61.420001
0

実行入力:
10.186810
10.186811
10.186812
10.186813
10.186814
10.186815
0

プログラムを実行して、なぜプログラムの実行結果がこのようになるのかを分析してください。
プログラム内で浮動小数点数と要約統計量を比較する場合、何に注意する必要がありますか?

演算結果

走行結果1
走行結果2

現象分析

あくまで参考ですので、間違っているところがあればご指摘ください。

理由:

  1. コンピュータにおける浮動小数点数の格納 (単精度を例に挙げます) は、1 つの符号ビット、8 ビットの指数コード、および 23 ビットの仮数で構成されます。

  2. 仮数は 23 桁しかなく、一部の 10 進数は無限の 2 進数にのみ変換できるため、記憶域要件は2 進数をインターセプトすることによってのみ満たされます。これには、インターセプト後に丸めるかどうかの問題が含まれます。

  3. 通常、インターセプト後に丸めるかどうかを決定するために偶数への桁上げ方法」が使用されます。

  4. コンピュータは、上記の規則に従って浮動小数点数 61.419997、61.419998、61.419999、61.420000、および 61.420001 を切り捨て、キャリー処理後にコンピュータに格納します。これらの浮動小数点数の 2 進表現の符号ビットと順序コードは同じです以下の図に示すように、ここでは仮数部のみが表示されます。61.419997、61.419998、61.419999、および 61.420000 の切り捨てられた仮数は同じ(上部の赤いボックス)、61.420001 と 61.420002 の仮数も同じ(下部の赤いボックス)ことがわかります。
    図1

  5. したがって、コンピュータにおける 61.419997、61.419998、61.419999、および 61.420000 のバイナリ表現は同じであり、61.420001 と 61.420002 のバイナリ表現も同じです。

  6. C 言語の printf は、数値を %f 形式で出力する場合、まず 2 進浮動小数点数表現を 10 進数に変換し、得られた 10 進数の小数点以下 6 桁を保持します。データを調べたところ、この時点で丸めるかどうかを決定するのが丸めであり、最初の 4 つの浮動小数点数の 10 進数への変換後の 2 進表現は 61.41999816894531、小数点以下 6 桁を保持した後の 61.419998、および 61.420001 と 61.420002 の 2 進表現10 進数に変換すると 61.42000198364258、小数点以下 6 桁を保持すると 61.4200 02 になります。印刷結果は一貫しています。

  7. なぜ右の数値(10.18681x)がエラーなく正常に表示できるのかというと、上と同じ理由ですが、これらの浮動小数点数の2進表現の仮数部を下図に示します。仮数部が違っていて、たまたま10進数に変換して小数点以下の桁が切り取られた場合は、元の結果と同じなので、エラーなく正常に表示できます。
    図2

おすすめ

転載: blog.csdn.net/weixin_52027058/article/details/125727962
おすすめ