6
$ printf "%0.2f\n" 41.495
41.49
$ printf "%0.2f\n" 41.485
41.49
$ printf "%0.2f\n" 41.475
41.47
$ printf "%0.2f\n" 41.465
41.47
$ printf "%0.2f\n" 41.455
41.46
$ printf "%0.2f\n" 41.445
41.44
$ printf "%0.2f\n" 41.435
41.44
$ printf "%0.2f\n" 41.425
41.42
$ printf "%0.2f\n" 41.415
41.42
$ printf "%0.2f\n" 41.405
41.40

2 番目の小数が奇数である数値が正しく丸められず、偶数であるのはなぜですか? さらに、丸められない.445の何が問題なのですか?

4

4 に答える 4

7

これは浮動小数点に関係していますが、倍精度には関係ありません。

あなたが書くとき

printf "%0.2f\n" 41.495

システムでは、最初に最も近い x87 80 ビット浮動小数点数にprintf丸められます[1]。41.495それはどのように機能しますか?最初にバイナリで 41.495 を書き込みます。

b101001.0111 11101011100001010001 11101011100001010001 11101011100001010001 ...

(分離されたグループは無限に繰り返されます)。次に、この数値を 64 桁の 2 進数に丸めます。

b101001.0111111010111000010100011110101110000101000111101011100001

これは、printf によって実際にフォーマットされた数値です。10 進数で書くと、正確には次のようになります。

41.4949999999999999990285548534529880271293222904205322265625

ご覧のとおり、41.495 より少し小さいので、printf が小数点以下 2 桁に丸めると、切り捨てられて41.49出力されます。

次に 41.485 を見てください。64 桁の 2 進数に丸めた後、次の値が得られます。

41.48500000000000000055511151231257827021181583404541015625

これは41.485よりも少し大きいため、printf は切り上げます。

私のシステムでは、printf 管理にこれに関する警告があります。

浮動小数点数は ASCII から浮動小数点に変換されてから再び変換されるため、浮動小数点の精度が失われる可能性があります。


  1. bash は、すべてのオペレーティング システムで x87 形式を使用しているわけではありません (実際、すべてのアーキテクチャで使用できるわけではありません)。他の一部のシステムでは、これらの値は double として解釈され (したがって、64 ビットではなく 53 ビットに丸められ)、結果は異なります。
于 2012-08-24T17:22:48.983 に答える
2

shellまたはprintfコマンドは、Intelの80ビット浮動小数点などの拡張精度浮動小数点を使用している可能性があります。printf一部のシェルに直接実装されており、などの個別の実行可能ファイルとして使用できます/usr/bin/printf

41.495に最も近い単精度値(IEEE 754)は41.494998931884765625です。したがって、テキスト「41.495」が単精度値として解釈される場合、それは正確に41.494998931884765625を表します。この値を小数点以下2桁に四捨五入すると、「499…」が切り捨てられるため、41.49になります。

41.495に最も近い拡張精度の値は、41.4949999999999999990285548534529880271293222904205322265625です。したがって、テキスト「41.495」を解釈すると、正確に41.4949999999999999990285548534529880271293222904205322265625を表します。小数点以下2桁に四捨五入すると、41.49になります。

41.485に最も近い拡張精度の値は、41.48500000000000000055511151231257827021181583404541015625です。四捨五入すると、41.49になります。

41.475に最も近い拡張精度の値は、41.474999999999999998612221219218554324470460414886474609375です。四捨五入すると、41.47になります。

41.465に最も近い拡張精度の値は、41.4650000000000000001387778780781445675529539585113525390625です。四捨五入すると、41.47になります。

41.455に最も近い拡張精度の値は、41.45500000000000000166533453693773481063544750213623046875です。四捨五入すると、41.46になります。

41.445に最も近い拡張精度の値は、41.444999999999999999722444243843710864894092082977294921875です。四捨五入すると、41.44になります。

41.435に最も近い拡張精度の値は、41.4350000000000000012490009027033011079765856266021728515625です。四捨五入すると、41.44になります。

41.425に最も近い拡張精度の値は、41.4249999999999999993061106096092771622352302074432373046875です。四捨五入すると、41.42になります。

41.415に最も近い拡張精度の値は、41.415000000000000000832667268468867405317723751068115234375です。四捨五入すると、41.42になります。

41.405に最も近い拡張精度の値は41.4049999999999999988897769753748434595763683319091796875です。四捨五入すると41.40になります。

于 2012-08-24T17:26:17.810 に答える
2

IEEE倍精度浮動小数点型と関係があることに大きな可能性を置いています。つまり、10 進数は内部的に指数と分数のコンポーネントで表されますが、10 進数ではなく 2 進数で表されます。これは 100% の説明ではなく、この記事の方がはるかに適切に説明されていますが、基本的に浮動小数点数は実際の値に「近い」形で表され、入力したとおりであるとは限りません。したがって、丸めも少し奇妙になることがあります。

ウィキの記事を読んでください。それは役立つはずです。正確さが必要な場合は、この標準を使用しない他の数値表現を調べてください。

于 2012-08-24T16:59:35.917 に答える
0

bash が内部で何を行っているかを正確に示すことができます:printf "%0.20f\n" 41.495試行錯誤の結果、異なる表現を登録する次に小さい数値は:printf "%0.20f\n" 41.495000000000000001であり、これは実際には倍精度よりも正確です。実際、これはすべてprintfコマンドです。bash は実際には浮動小数点数を認識しません。

于 2012-08-24T18:01:43.100 に答える