すべての数値をIEEE754浮動小数点値で表すことができるわけではないためです。ある時点で、あなたは完全に表現できない数を得るでしょう、そしてコンピュータは最も近いものを選ばなければならないでしょう。
IEEE754-1985のWikipediaエントリに0.05を入力しHarald Schmidt's excellent online converter
て参照すると、次のビットになります(私の説明は次のとおりです)。
s eeeeeeee mmmmmmmmmmmmmmmmmmmmmmm
0 01111010 10011001100110011001101
|||||||| |||||||||||||||||||||||
128 -+||||||| ||||||||||||||||||||||+- 1 / 8388608
64 --+|||||| |||||||||||||||||||||+-- 1 / 4194304
32 ---+||||| ||||||||||||||||||||+--- 1 / 2097152
16 ----+|||| |||||||||||||||||||+---- 1 / 1048576
8 -----+||| ||||||||||||||||||+----- 1 / 524288
4 ------+|| |||||||||||||||||+------ 1 / 262144
2 -------+| ||||||||||||||||+------- 1 / 131072
1 --------+ |||||||||||||||+-------- 1 / 65536
||||||||||||||+--------- 1 / 32768
|||||||||||||+---------- 1 / 16384
||||||||||||+----------- 1 / 8192
|||||||||||+------------ 1 / 4096
||||||||||+------------- 1 / 2048
|||||||||+-------------- 1 / 1024
||||||||+--------------- 1 / 512
|||||||+---------------- 1 / 256
||||||+----------------- 1 / 128
|||||+------------------ 1 / 64
||||+------------------- 1 / 32
|||+-------------------- 1 / 16
||+--------------------- 1 / 8
|+---------------------- 1 / 4
+----------------------- 1 / 2
符号は0であり、正です。指数は、左側の数値への1ビットマッピングで示されます。64+32+16+8+2 = 122 - 127 bias = -5
したがって、乗数は2-5または1/32
です。バイアスは、非常に小さい数の127
表現を可能にすることです(大きな大きさの負の数ではなく、ゼロに近い場合など)。
仮数はもう少し複雑です。1ビットごとに、右側に数値を累積します(暗黙的に追加した後1
)。したがって、数をの合計として計算できます{1, 1/2, 1/16, 1/32, 1/256, 1/512, 1/4096, 1/8192, 1/65536, 1/131072, 1/1048576, 1/2097152, 1/8388608}
。
これらすべてを合計すると、が得られます1.60000002384185791015625
。
これに乗数(指数ビットから以前に計算された)を掛けると、が得られるので、それがすでに正確に表されていないことがわかります。仮数のこのビットパターンは実際にはと同じですが、指数が-5ではなく-4であるため、が等しくなることはめったにありません(これはお気に入りのインタビューの質問のようです)。1/32
0.0500000001
0.05
0.1
0.1 + 0.1 + 0.1
0.3
それらを合計し始めると、その小さなエラーが累積されます。これは、0.05
それ自体にエラーが表示されるだけでなく、累積の各段階でエラーが発生する可能性があるためです。すべての数値、、0.1
など0.15
を0.2
表すことができるわけではありません。まさにどちらか。
最終的に、デフォルトの精度を使用すると、エラーが十分に大きくなり、数値に表示されるようになります。次のような独自の精度を選択することで、これを少し延期することができます。
#include <iostream>
#include <iomanip>
:
std::cout << std::setprecison (2) << time << '\n';
変数値は修正されませんが、エラーが表示される前に、より多くの呼吸スペースが与えられます。
余談std::endl
ですが、バッファのフラッシュを強制するため、避けることをお勧めする人もいます。実装がそれ自体で動作している場合、とにかく改行を送信すると、端末デバイスでこれが発生します。また、標準出力を非終端記号にリダイレクトした場合は、おそらくすべての行でフラッシュする必要はありません。あなたの質問とはあまり関係がなく、おそらくほとんどの場合、実際の違いはないでしょう。私が提起したいと思った点です。