7

eps特定の double 変数vの最小値を決定する問題があります。

v+eps != v

epsこれは、任意の数に依存するため、典型的な問題シート タスクではないことに注意してくださいv

これは、for ループでこの値をシークして行うべきではありません。ビットシフトなど、これを行うための高速な方法はありますか? コンパイラ、最適化フラグ、プラットフォームに依存しない...

回答ありがとうございます

4

3 に答える 3

3

C99 関数nextafterが必要です。または、Boost.Math を使用しますnextafter。これは、定義によって定義される実装です (メモリ内の内部表現に依存しdoubleます)。

執筆時点でここの回答に示されているすべての方法の比較については、ライブデモを参照して、他のソリューションがどのように失敗するかを確認してください。


参考までに、独自のシステムで実行する場合のテスト コードを次に示します。

#include <cmath>
#include <cfloat>
#include <limits>
#include <iostream>
using std::cout;
#include <iomanip>
using std::setprecision;

#include <boost/math/special_functions/next.hpp>

double
epsFor( double x )
{
  union
  {
    double d;
    unsigned long long i;
  } tmp;
  tmp.d = x;
  ++ tmp.i;
  return tmp.d - x;
}

void test(double d)
{
  double d1 = std::nextafter(d,DBL_MAX);
  double d2 = d+std::numeric_limits<double>::epsilon() * d;
  double d3 = d+epsFor(d);
  double d4 = boost::math::nextafter(d, DBL_MAX);
  cout << setprecision(40)
       << "For value of d = " << d << '\n'
       << " std::nextafter: " << d1 << '\n'
       << " Boost solution: " << d4 << '\n'
       << " undefined beh.: " << d3 << '\n'
       << " numeric_limits: " << d2 << '\n';
}

int main()
{
  test(0.1);
  test(986546357654.354687);
}
于 2013-10-10T09:53:24.773 に答える
1

タイプパニングを使用します:

double
epsFor( double x )
{
    union
    {
        double d;
        unsigned long long i;
    } tmp;
    tmp.d = x;
    ++ tmp.i;
    double results = tmp.d - x;
    return results;
}

(正式には、これは未定義の動作ですが、実際には、最新のコンパイラで失敗するかどうかはわかりません。)

編集:

C++ では、中間式で過度の精度が許容されることに注意してください。ここでは正確な結果に関心があるため、最初に投稿された関数をdouble. これを回避するために関数に割り当てを追加しましたが、多くのコンパイラは、少なくともデフォルトでは、この点に関して標準に準拠していないことに注意してください。(g++ は、少なくとも最適化がオンになっている場合に、準拠した動作を行うために特別なオプションが必要な場合の良い例です。g++ を使用している場合、 -ffloat-store正しい結果が必要な場合はオプションを指定する必要があります。)

于 2013-10-10T09:36:48.520 に答える
0
eps = std::numeric_limits<double>::epsilon() * v;
于 2013-10-10T09:25:52.393 に答える