4

私はコンピューター工学の学生で、BYU-IdahoでC ++の入門クラスの個別指導を行っていますが、学生は私を困惑させました。

このためのコードを書く場合:

#include <iostream>
using namespace std;
int main()
{
   float y = .59;
   int x = (int)(y * 100.0);
   cout << x << endl;
   return 0;
}

結果=58

#include <iostream>
using namespace std;
int main()
{
   double y = .59;
   int x = (int)(y * 100.0);
   cout << x << endl;
   return 0;
}

結果=59

これは精度の問題であり、intはfloatよりも正確であるため、情報が失われることを彼に伝えました。ダブルはフロートよりも正確なので、機能します。

しかし、私が言ったことが正しいかどうかはわかりません。これは、intがゼロで埋められ、その結果、キャストされている間に「切り捨て」られることと関係があると思いますが、よくわかりません。

このすべての「下」で何が起こっているのかを説明したい人がいたら、それは面白いと思います!

4

4 に答える 4

7

問題は、正確な値0.59floatを保持するのに十分な精度がないことです。このような値を格納すると、(コンパイル時にすでに)バイナリ表現で別の値に丸められます。この場合、これは0.59よりわずかに小さい値でした(必要な値よりもわずかに大きい場合もあります)。 )。これに100を掛けると、59よりわずかに小さい値が得られます。このような値を整数に変換すると、0に向かって丸められるため、58になります。

フロートとしての0.59は、次のように格納されます(現在は人間が読める10進数として表されています)。

0.589999973773956298828125

doubleタイプに。このタイプには本質的に同じ問題がありますが、期待される結果が得られる理由は2つあります。希望する正確なdouble値を保持できる(0.59の場合はそうではありませんが、他の値の場合はそうなる可能性があります)。コンパイラはそれを切り上げることを決定します。したがって、これに100を掛けると、59以上の値になり、予想どおり0から59に丸められます。

doubleここで、aとしての0.59がまだコンパイラによって切り捨てられている場合があることに注意してください。確かに、私はちょうどチェックしました、そしてそれはそうです。0.59は、次のdoubleように保存されます。

0.58999999999999996891375531049561686813831329345703

ただし、整数に変換する前に、この値に100を掛けています。ここで興味深い点があります。100を掛けると、0.59 * 100を正確に格納できないためy、コンパイラによる0.59との差がなくなります。実際、プロセッサは計算します。これは59に0.58999999999999996891375531049561686813831329345703 * 100.0切り上げられます。これは、 !で表すことができる数値です。double

詳細については、次のコードを参照してください:http: //ideone.com/V0essb

ここで、なぜ同じものがカウントされないのか不思議に思うかもしれませんfloat。これはまったく同じように動作しますが、精度が異なるはずです。問題は、切り上げられない0.589999973773956298828125 * 100.0ことです(これはで表すこともできます)。計算後の丸め動作は実際には定義されていません。59float

実際、浮動小数点数の操作は正確に指定されていません。つまり、マシンごとに異なる結果が発生する可能性があります。これにより、丸めが含まれていない場合でも、わずかに不正確な結果につながるパフォーマンスの微調整を実装できます。別のマシンでは期待どおりの結果が得られ、他のマシンではそうではない場合があります。

于 2013-02-01T17:44:06.493 に答える
2

0.59は、2進浮動小数点では正確に表現できません。したがってx、実際には0.59よりわずかに上または下の値になります。どちらを使用するかによって影響を受ける可能性がありfloatますdouble。これにより、プログラムの結果が58か59かが決まります。

于 2013-02-01T17:42:26.990 に答える
2

これは精度の問題であり、aまたはaの.59 いずれかで正確に表現できないという事実と関係があります。そうではありません; それは非常に近いものです (わずかに多かれ少なかれ)。による乗算 は正確ですが、元の値がそうではなかったため、。よりわずかに多いまたはわずかに少ない値が得られます。 ゼロに切り捨てられるように変換すると、またはのいずれかが得られます。doublefloaty .59.5910059int5958

于 2013-02-01T17:44:50.983 に答える
0

これは、古い電卓を使用して行う場合と同じ問題であり、1 / 3 * 3または同様の問題が発生します2.9999999(int)(float_value)これを、がの小数を単純に切り刻むという事実と組み合わせると、私のマシンが取得するようなものであれfloatvalueば、結果になります。これは、ほぼ59ですが、最初の2桁だけを切り取ると、実際には58になるためです。58.9999961855858.999996185

浮動小数点数は多くのことを計算するのに最適ですが、「結果は何か」に関しては非常に注意する必要があります。これは概算であり、精度は無限ではなく、中間結果の丸めが発生します。

doubleの場合、桁数が多くなり、0.58999999999999 x 100を計算すると、最後のビットが0ではなく1になるため、結果は59.00000000001などになり、59になります。整数。

于 2013-02-01T17:56:39.213 に答える