36

新しいプロジェクトを開始するたびに、float 変数または double 変数を比較する必要があるときは、次のようなコードを記述します。

if (fabs(prev.min[i] - cur->min[i]) < 0.000001 &&
    fabs(prev.max[i] - cur->max[i]) < 0.000001) {
        continue;
}

次に、これらの魔法の変数 0.000001 (および double の場合は 0.00000000001) と fabs を取り除きたいので、インライン関数といくつかの定義を記述します。

#define FLOAT_TOL 0.000001

だから、これを行う標準的な方法があるのだろうか?いくつかの標準ヘッダーファイルでしょうか?float と double の制限 (最小値と最大値) があるとよいでしょう。

4

8 に答える 8

21

浮動小数点ガイドから:

これは悪い方法です。「小さく見える」という理由で選択された固定イプシロンは、比較される数値が非常に小さい場合、実際には大きすぎる可能性があるためです。数値がまったく異なる場合、比較は「true」を返します。また、数値が非常に大きい場合、イプシロンが最小の丸め誤差よりも小さくなる可能性があるため、比較では常に「false」が返されます。

ここでの「マジック ナンバー」の問題は、それがハードコードされていることではなく、「マジック」であることです。0.000005 または 0.0000000000001 よりも 0.000001 を選択する理由はありませんでしたね。は、後者とさらに小さい値をほぼ表すことができることに注意してください。最初の非ゼロ桁のfloatの精度は、約 7桁です。

固定イプシロンを使用する場合は、それを使用する特定のコードの要件に従って実際に選択する必要があります。別の方法としては、相対誤差マージン (詳細については上部のリンクを参照) を使用するか、浮動小数点数を整数として比較することをお勧めします。

于 2010-12-28T19:50:09.293 に答える
14

標準はイプシロン値を提供します。にあり、と<limits>で値にアクセスできます。そこには他の値がありますが、私は正確に何であるかを確認しませんでした。std::numeric_limits<float>::epsilonstd::numeric_limits<double>::epsilon

于 2010-12-28T18:16:45.960 に答える
14

値の最小のイプシロン (または最小のイプシロンの係数) を持つstd::nextafter2 つのテストに使用できます。double

bool nearly_equal(double a, double b)
{
  return std::nextafter(a, std::numeric_limits<double>::lowest()) <= b
    && std::nextafter(a, std::numeric_limits<double>::max()) >= b;
}

bool nearly_equal(double a, double b, int factor /* a factor of epsilon */)
{
  double min_a = a - (a - std::nextafter(a, std::numeric_limits<double>::lowest())) * factor;
  double max_a = a + (std::nextafter(a, std::numeric_limits<double>::max()) - a) * factor;

  return min_a <= b && max_a >= b;
}
于 2016-02-07T11:34:47.547 に答える
8

あなたの答えをありがとう、彼らは私を大いに助けてくれました。私はこれらの資料を読みました: 1 番目2 番目

答えは、相対比較のために独自の関数を使用することです。

bool areEqualRel(float a, float b, float epsilon) {
    return (fabs(a - b) <= epsilon * std::max(fabs(a), fabs(b)));
}

これは私のニーズに最も適したソリューションです。ただし、いくつかのテストとその他の比較方法を作成しました。これが誰かに役立つことを願っています。areEqualRel はこれらのテストに合格しますが、他は合格しません。

#include <iostream>
#include <limits>
#include <algorithm>

using std::cout;
using std::max;

bool areEqualAbs(float a, float b, float epsilon) {
    return (fabs(a - b) <= epsilon);
}

bool areEqual(float a, float b, float epsilon) {
    return (fabs(a - b) <= epsilon * std::max(1.0f, std::max(a, b)));
}

bool areEqualRel(float a, float b, float epsilon) {
    return (fabs(a - b) <= epsilon * std::max(fabs(a), fabs(b)));
}

int main(int argc, char *argv[])
{
    cout << "minimum: " << FLT_MIN      << "\n";
    cout << "maximum: " << FLT_MAX      << "\n";
    cout << "epsilon: " << FLT_EPSILON  << "\n";

    float a = 0.0000001f;
    float b = 0.0000002f;
    if (areEqualRel(a, b, FLT_EPSILON)) {
        cout << "are equal a: " << a << " b: " << b << "\n";
    }
    a = 1000001.f;
    b = 1000002.f;
    if (areEqualRel(a, b, FLT_EPSILON)) {
        cout << "are equal a: " << a << " b: " << b << "\n";
    }
}
于 2011-01-04T21:56:03.617 に答える
4

float.h で標準の define を使用する必要があります。

#define DBL_EPSILON     2.2204460492503131e-016 /* smallest float value such that 1.0+DBL_EPSILON != 1.0 */

または numeric_limits クラス:

// excerpt
template<>
class numeric_limits<float> : public _Num_float_base
{
public:
    typedef float T;

    // return minimum value
    static T (min)() throw();

    // return smallest effective increment from 1.0
    static T epsilon() throw();

    // return largest rounding error
    static T round_error() throw();

    // return minimum denormalized value
     static T denorm_min() throw();
};

[編集: もう少し読みやすくしました。]

しかし、さらに、それはあなたが何を求めているかによって異なります。

于 2010-12-28T18:30:54.303 に答える
4

@geotavros のソリューションの c++11 実装を次に示します。新しい関数と、とが、 、のオーバーロードを持っているstd::numeric_limits<T>::epsilon()という事実を利用します。std::fabs()std::fmax()floatdoublelong float

template<typename T>
static bool AreEqual(T f1, T f2) { 
  return (std::fabs(f1 - f2) <= std::numeric_limits<T>::epsilon() * std::fmax(std::fabs(f1), std::fabs(f2)));
}
于 2016-10-14T09:11:40.050 に答える
4

2 つの float が等しいかどうかを比較している場合、本質的に間違ったことをしていることに注意してください。比較にスロップ ファクターを追加するだけでは十分ではありません。

于 2010-12-28T17:44:06.997 に答える