3

私の基本的な目的は、同等の float であると思われる 2 つを減算することでした。このことを考慮:-

float x=1;
float a=x/30-x/40;    
float b=x/30;
b-=x/40;
std::cout<<a-b<<std::endl;

ゼロにするべきだった。しかし、私はしませんでした。代わりに、約 10^(-10) という非常に小さな数値が得られました。

さて、2つのオプションがありました:-

まず、分数の代わりに有理式を使用し (つまり、分子と分母を扱う)、最終的な有理式を分数に変換することを考えました。Boost.rational を介してこれを行いました。分子と分母が巨大になる可能性があるため、cpp_int を使用して分子と分母を格納しました。それは正常に動作します。しかし、問題は、私が作成しているプログラムが非常に時間がかかっていることです。これは、巨大な整数を扱わなければならないためだと思います。

次に、固定小数点演算を試すように勧められました。私はそれがあまり得意ではありません。それで、固定小数点演算でも正しい答えが得られるかどうかわかりませんか?私が考えていたのはこれでした->減算の結果を50番目の精度まで正しくしたいとします。そこで、適切な 10 の累乗を掛けて、小数点の左側に 50 桁を取得します。小数部分を削除して、cpp_int に変換します。私は両方のフロートでこれを行います。そして、これらの cpp_int で減算を実行します。2 つの問題:- まず、cpp_float_dec_50 を cpp_int に変換できません。Boost では、この種の (損失の多い) 変換を直接行うことはできません。第二に、このアプローチが機能することにまったく自信がありません。

それでは、最後に 2 つの質問: - cpp_float_dec_50 を cpp_int に変換する方法は? 質問でこれまでに提示されたコンテキストで、2つのフロートを2つ減算するのに最適なアプローチはどのようなものですか?

ありがとう。そして、これのいずれかが非常に初心者または愚かな質問に出くわした場合は申し訳ありません. まだ勉強してる。

4

1 に答える 1

3

正確な表現が必要かどうかを決定する必要があります。10^-10 の誤差が大きすぎる場合は、結局のところ正確さが必要になる場合があります。固定小数点表現は、組み込み型自体よりも優れているとは言えません。その精度と機能を拡張すると、多精度ライブラリに到達します:)。

私はboost::multiprecisionをお勧めしますが、かなり簡単だと思いますが、これはブースト テンプレート ライブラリであるため、コンパイラ エラーを突き止めるには余分な労力が必要です。もちろん、「フリーランチ」はありませんが、数値変換は機能します。誤って使用すると、結果は組み込みの数値と同じくらい簡単に台無しになります。

注意事項:

  • パフォーマンスは精度の関数です。制御下に置いてください!
  • 時間をかけて精度を測定します。たとえば、乗算を繰り返すと、精度が際限なく追加される可能性があります。数学で不要な変換を削除します。
  • 多くの関数 (trig、log、exp など) は有理数用に実装されていません。(浮動小数点型を使用して) 制御されたエラーをあきらめて受け入れる必要がある前に、そのような数学を慎重に回避することができます。
  • 精度要件に従ってプログラムを分離することができます。たとえば、2D でレンダリングする場合、ビュー空間 (-1..1) に変換すると、値を浮動小数点に切り捨てて高速に操作できます。
  • boost::multiprecision には、パフォーマンスを向上させる多くのバックエンドがあります (ただし、精度の制御の誤りは修正されません)。

ブースト mp タイプには次の定義を使用します。私の場合、式テンプレートをオフにすると高速になることがわかりました。

namespace mp = boost::multiprecision;
typedef mp::number<mp::cpp_int_backend<>, mp::et_off>       int_mp;
typedef mp::number<mp::cpp_rational_backend, mp::et_off>    rational_mp;
typedef mp::number<mp::cpp_dec_float<0>, mp::et_off>        float_mp;  // 0 means 'unlimited'
于 2014-01-06T11:20:33.707 に答える