- 浮動小数点変数はおおよその表現であり、正確なものではありません。すべての数値が float 変数に「収まる」わけではありません。たとえば、1/10 (0.1) を 2 進変数に入れる方法はありません。ちょうど 1/3 を 10 進数の 1 に入れることができないのと同じです (無限の 0.33333 で近似することしかできません)。
- このような変数を出力する場合、多くの丸めオプションを適用するのが通常です。それらをすべて設定しない限り、どれが適用されているかを確認することはできません。これは、ストリームに BEFORE << の丸め方を指示できるため、特に << 演算子に当てはまります。
Printf は丸めも行います。http://codepad.org/LLweoeHpを検討してください:
float t = 0.1f;
printf("result: %f\n", t);
--
result: 0.100000
まあ、それはうまく見えます。なんで?printf はデフォルトである程度の精度になり、出力を切り上げたためです。小数点以下 50 桁でダイヤルしてみましょう: http://codepad.org/frUPOvcI
float t = 0.1f;
printf("result: %.50f\n", t);
--
result: 0.10000000149011611938476562500000000000000000000000
それは違いますね。625 の後、float はより多くのデータを保持するための容量を使い果たしました。そのため、ゼロが表示されます。double はより多くの桁数を保持できますが、バイナリの 0.1 は有限ではありません。Double は最終的にあきらめなければなりません: http://codepad.org/RAd7Yu2r
double t = 0.1;
printf("result: %.70f\n", t);
--
result: 0.1000000000000000055511151231257827021181583404541015625000000000000000
あなたの例では、321.12 だけで問題を引き起こすのに十分です: http://codepad.org/cgw3vUKn
float t = 321.12f;
printf("and the result is: %.50f\n", t);
result: 321.11999511718750000000000000000000000000000000000000
これが、人間に提示する前に浮動小数点値を切り上げる必要がある理由です。
電卓プログラムは、float や double をまったく使用しません。10 進数形式を実装します。例えば:
struct decimal
{
int mantissa; //meaningfull digits
int exponent; //number of decimal zeroes
};
足し算、引き算、掛け算、割り算など、すべての操作を再発明する必要があります。または、10 進ライブラリを探してください。