iPhone アプリケーションでフロートの丸めに問題があります。
float f=4.845;
float s= roundf(f * 100.0)/100;
NSLog(@"Output-1: %.2f",s);
s= roundf(484.5)/100;
NSLog(@"Output-2: %.2f",s);
Output-1: 4.84
Output-2: 4.85
これで何が問題なのか、これを解決する方法を教えてください。
iPhone アプリケーションでフロートの丸めに問題があります。
float f=4.845;
float s= roundf(f * 100.0)/100;
NSLog(@"Output-1: %.2f",s);
s= roundf(484.5)/100;
NSLog(@"Output-2: %.2f",s);
Output-1: 4.84
Output-2: 4.85
これで何が問題なのか、これを解決する方法を教えてください。
問題は、浮動小数点に固有の問題の 1 つ、つまりほとんどの数値を正確に(a)で表すことができないという事実をまだ認識していないことです。
これは4.845
、実際には、4.8449999999999
それを丸めると、4.84
期待したものではなく、 のようなものになる可能性が高いことを意味します4.85
。
また、最終的にどのような値になるかは、計算方法によっても異なります。そのため、異なる結果が得られます。
そしてもちろん、信頼できる What Every Computer Scientist Should Know About Floating-Point Arithmetic がなければ、浮動小数点の「不正確さ」の答えは SO では完全ではありません。
(a) IEEE754 で正確にレンダリングできるのは、特定の類似した範囲内の 2 の正確な累乗の合計のみです。たとえば484.5
、
256 + 128 + 64 + 32 + 4 + 0.5
( )。28 + 27 + 26 + 25 + 22 + 2-1
IEEE754 形式の詳細については、この回答を参照してください。
それを解決するには、いくつかの選択肢があります。double
1 つはの代わりに使用することですfloat
。これにより、精度が向上し、数値の範囲が広がりますが、実際に問題を解決するのではなく、問題を遠ざけるだけです。0.1
は IEEE754 の繰り返し分数であるため、正確に表すことのできるビット数 (無限を除く) はありません。
もう 1 つの選択肢は、big decimal 型のようなカスタム ライブラリを使用することです。これは、任意の精度の小数を表すことができます (これは、メモリによって制限されるため、何人かの人々が示唆するように、無限の精度ではありません)。これにより、2 進数と 10 進数の不一致によるエラーが減少します。
調べることもできますNSDecimalNumber
-これにより任意の精度が得られるわけではありませんが、正確な10進数表現で広い範囲が得られます。
PI や 2 の平方根、その他の無理数など、表現できない数値はまだありますが、ほとんどの場合をカバーするはずです。これらの他の値を本当に処理する必要がある場合は、シンボリック数値表現に切り替える必要があります。
float *484.5
として正確に表現できるものとは異なり、は次のように表されます (他の数値を試したい場合は、この計算機を参照してください)。100 を掛けると、数値はに保たれ、正確に に丸められます。
4.845
4.8449998
484.49998
484
0.5
が 2 のべき乗 (つまり2^-1
) であるため、正確な表現が可能です。