-1

次のC++プログラムについて考えてみます。

#include <iostream>
using std::cout;
using std::endl;

int main () {
   float x = 0.0001;
   float y = 0;
   for (int i=0; i < 10000; i++) {
      y += x;
   }
   cout << y << endl;
   return 0;
}

このプログラムをコンパイルして実行し、次の質問に答えてください。このプログラムの実際の動作は、予想される動作とどのように異なりますか?

期待される動作が見られないのはなぜですか?

プログラムのセマンティクスが同じままであることを確認しながら、期待される動作と実際の動作が一致するように、このプログラムにどのような変更を加えますか?

上記は私の割り当てです。私は自分で宿題をすることになっていることを知っていますが、行き詰まっています。

  • パートa)については、2つの数字が異なると単純に言いました。

  • パートc)フロートをダブルにしました。(セマンティクスは同じままだと思います)

  • パートb)については、これが壊滅的なキャンセルと呼ばれることを知っていますが、教授はおそらくそれ以上のものを見たいと思っており、他に何を言うべきかわかりません。誰かが私を助けることができますか?

ご協力いただきありがとうございます

4

2 に答える 2

1

このプログラムの「予想される動作」とは、ゼロに初期化された合計に.0001を10,000回加算することであり、すべての算術演算は数学的に1になります。実際の動作は、10進数の「.0001」をdoubleに変換することです。 (おそらくIEEE-754 64ビットバイナリ浮動小数点)、次にその値を浮動小数点数に変換し(おそらく、IEEE-754 32ビットバイナリ浮動小数点)、次にその浮動小数点数を合計に10,000回追加します。毎回浮動小数点演算。したがって、実際の動作には、数値をdoubleに変換するとき、doubleをfloatに変換するとき、および各加算で、潜在的な丸め誤差があります。

この状況でエラーを回避する1つの方法は、整数演算を使用することです。.0001に設定float xする代わりに、1に設定することもできint xます。同様にy、intになり、ループが完了するまですべての整数演算を使用します。最終的な合計を取得した後、それをfloatに変換します。次に、整数演算を使用できるようにするために使用したスケーリングを調整する必要があります。.0001の代わりに1を追加していたので、最終結果10000.fを調整するために除算する必要があります。(この手法は、すべての状況でエラーを完全に回避するわけではありません。他の状況でエラーを減らすための他の手法があります。)

キャンセルがないため、壊滅的なキャンセルはありません。キャンセルは、2つの数値を加算または減算して結果を小さくする場合に発生します(したがって、+ 8と-6を加算して+2を取得するなど、反対の符号の2つの数値を加算する場合、または減算など、同じ符号の2つの数値を減算する場合)。 +8から-6で+2を取得します)。結果が元の2つの数値よりもはるかに小さい場合、壊滅的なキャンセルが発生します。この状況では、作業している値ははるかに小さくなりますが、元の数値にあったエラーは通常同じサイズのままであるため、エラーは比較的大きくなります。私たちが取り組んでいる価値に。たとえば、8.01から8を引いて.01を得ることになっていると仮定しますが、小さなエラーのため、8の代わりに7.99があります。8.01から7.99を引くと、.02になります。この結果.02は、目的の結果.01の2倍であるため、相対誤差は非常に大きくなります。

于 2012-10-14T11:02:17.437 に答える
1

このプログラムの実際の動作は、予想される動作とどのように異なりますか?-このプログラムの実際の動作は、0.0001のIEEE表現を10000回合計しています。0.0001のIEEE表現!=実際の0.0001

期待される動作が見られないのはなぜですか?-0.0001は0.0001として正確に表されると想定していますが、実際には、base10ではなくbase2のすべてのフローティングポイントを表す必要があるため、IEEEフローティングポイントは0.0001を正確に表すことができないためです。

プログラムのセマンティクスが同じままであることを確認しながら、期待される動作と実際の動作が一致するように、このプログラムにどのような変更を加えますか?-この場合、floatをdoubleに変更すると機能します。これは、doubleの方がfloatよりも小数点以下の精度が高いためです。-別の解決策は、floatを維持し、合計を行う代わりに、y = 10000 * xを割り当てることです(これにより、エラーが少なくなり、丸めエラーや近似エラーを回避する場合に適しています)

于 2012-10-14T04:31:23.180 に答える