14

2つの浮動小数点数を次のように比較すると、丸め誤差のために等しくない可能性があるa_float == b_floatため、問題を探しています。a_float / 3.0 * 3.0a_float

通常行うことは、 のようなものfabs(a_float - b_float) < tolです。

どのように計算しtolますか?

理想的には、公差は最下位の 1 桁または 2 桁の値よりも大きくする必要があります。したがって、単精度浮動小数点数が使用されている場合tol = 10E-6は、ほぼ正しいはずです。a_floatただし、これは、非常に小さいか非常に大きい一般的なケースではうまく機能しません。

tolすべての一般的なケースで正しく計算するにはどうすればよいですか? 特に C または C++ のケースに興味があります。

4

7 に答える 7

10

私の知る限り、そうではありません。

アプリケーションの精度要件に依存する可能性があるため、一般的な「正解」はありません。

たとえば、スクリーン ピクセルで動作する 2D 物理シミュレーションでは、ピクセルの 1/4 で十分であると判断される場合がありますが、原子力発電所の内部構造の設計に使用される 3D CAD システムでは不十分な場合があります。

これを外部からプログラムで決定する方法がわかりません。

于 2013-07-01T12:29:52.743 に答える
5

C ヘッダー ファイル<float.h>は、定数FLT_EPSILONとを提供しますDBL_EPSILON。これは、1.0 と、float/double が表すことができる 1.0 より大きい最小の数値との差です。数値のサイズと許容する丸め誤差によってそれをスケーリングできます。

#include <float.h>
#ifndef DBL_TRUE_MIN
/* DBL_TRUE_MIN is a common non-standard extension for the minimum denorm value
 * DBL_MIN is the minimum non-denorm value -- use that if TRUE_MIN is not defined */
#define DBL_TRUE_MIN DBL_MIN
#endif

/* return the difference between |x| and the next larger representable double */
double dbl_epsilon(double x) {
    int exp;
    if (frexp(x, &exp) == 0.0)
        return DBL_TRUE_MIN;
    return ldexp(DBL_EPSILON, exp-1);
}
于 2013-07-01T16:46:26.250 に答える
4

トラップ、スネア、抜け穴の世界へようこそ。他の場所で述べたように、浮動小数点の等価性と許容誤差の汎用ソリューションは存在しませ。それを考えると、プログラマーが特定のケースで使用できるツールと公理があります。

fabs(a_float - b_float) < tol言及されている欠点OPがあります:「a_floatが非常に小さいか非常に大きい可能性がある一般的なケースではうまく機能しません。」 fabs(a_float - ref_float) <= fabs(ref_float * tol)バリアント範囲をはるかにうまく処理します。

OPの「単精度浮動小数点数はtol = 10E-6を使用しています」は、CおよびC ++にとって少し気になるので、float算術を簡単に昇格させてから、 ではなくdoubleの「許容範囲」が作用します。 非常に多くの新しいプログラマーが、精度計算が原因であることに気付いていないことを考慮してください。大量のデータで小さいサイズが必要な場合を除いて、コード全体を使用することをお勧めします。doublefloatfloat f = 1.0; printf("%.20f\n", f/7.0);7.0doubledoublefloat

C99 はnextafter()、「許容度」を測定するのに役立つものを提供します。それを使用して、次の表現可能な数を決定できます。これは、OP「...ストレージタイプの有効桁数から1を引いた数...丸め誤差を許容する」に役立ちます。 if ((nextafter(x, -INF) <= y && (y <= nextafter(x, +INF))) ...

使用される「許容度」の種類は、多くの場合、問題の核心です。tolほとんどの場合 (IMHO)相対的な許容範囲が重要です。例: 「x と y は 0.0001% 以内ですか?」絶対的な許容範囲が必要な場合もあります。例: 「x と y は 0.0001 以内ですか?」

公差のは、多くの場合、最良の値が状況に依存するため、議論の余地があります。0.01 以内の比較は、ドルの金融アプリケーションでは機能しますが、円では機能しない可能性があります。(ヒント: 簡単に更新できるコーディング スタイルを使用してください。)

于 2013-07-01T16:19:05.960 に答える
1

丸め誤差は、演算に使用する値によって異なります。

固定許容誤差の代わりに、おそらく次のようなイプシロンの係数を使用できます。

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-07T12:03:11.083 に答える
0

許容値は状況によって異なりますが、精度の比較を探している場合は、マシンのイプシロン値、numeric_limits::epsilon() (ライブラリの制限) を許容値として使用できます。この関数は、1 と、データ型で表現可能な 1 より大きい最小値との差を返します。 http://msdn.microsoft.com/en-us/library/6x7575x3.aspx

float と double を比較する場合、epsilon の値は異なります。たとえば、私のコンピューターでは、float を比較すると、epsilon の値は 1.1920929e-007 になり、double を比較すると、epsilon の値は 2.2204460492503131e-016 になります。

x と y を相対的に比較するには、イプシロンに x と y の最大絶対値を掛けます。

上記の結果に ulp (最後の桁の単位) を掛けることで、精度を高めることができます。

#include <iostream>
#include <cmath>
#include <limits>

template<class T> bool are_almost_equal(T x, T y, int ulp)
{
    return std::abs(x-y) <= std::numeric_limits<T>::epsilon() * std::max(std::abs(x), std::abs(y)) * ulp
}
于 2014-02-06T13:04:03.697 に答える
-3

フロートを比較する必要があるときは、次のようなコードを使用します

bool same( double a, double b, double error ) {
    double x;
    if( a == 0 ) {
        x = b;
    } else if( b == 0 ) {
        x = a;
    } else {
        x = (a-b) / a;
    }
    return fabs(x) < error;
}
于 2013-07-01T13:52:58.603 に答える