55

サードパーティが提供するライブラリのテストを依頼されました。ライブラリは有効数字n桁まで正確であることが知られています。重要度の低いエラーは無視しても問題ありません。結果を比較するのに役立つ関数を書きたい:

def nearlyequal( a, b, sigfig=5 ):

この関数の目的は、2 つの浮動小数点数 (a と b) がほぼ等しいかどうかを判断することです。a==b (完全一致) の場合、または a と b が10 進数で書かれたsigfig有効数字に丸められたときに同じ値を持つ場合、関数は True を返します。

誰かが良い実装を提案できますか? ミニユニットテストを書きました。私のテストでバグが見られない限り、適切な実装は以下に合格する必要があります。

assert nearlyequal(1, 1, 5) 
assert nearlyequal(1.0, 1.0, 5) 
assert nearlyequal(1.0, 1.0, 5) 
assert nearlyequal(-1e-9, 1e-9, 5) 
assert nearlyequal(1e9, 1e9 + 1 , 5) 
assert not nearlyequal( 1e4, 1e4 + 1, 5) 
assert nearlyequal( 0.0, 1e-15, 5 ) 
assert not nearlyequal( 0.0, 1e-4, 6 ) 

その他の注意事項:

  1. 値 a および b は、int、float、または numpy.float64 型の可能性があります。値 a と b は常に同じ型になります。変換によって関数に追加のエラーが発生しないことが重要です。
  2. これを数値のままにしておきます。そのため、文字列に変換したり、数学以外のトリックを使用したりする関数は理想的ではありません。このプログラムは、関数が本来の機能を果たしていることを証明したいと考えている数学者によって監査されます。
  3. 速さ…たくさんの数字を比較しなければならないので、速ければ速いほどいいです。
  4. numpy、scipy、および標準ライブラリがあります。特にプロジェクトのこのような小さな部分については、他のものを手に入れるのは難しいでしょう.
4

11 に答える 11

123

Python 3.5 の時点で、(標準ライブラリを使用して) これを行う標準的な方法は、math.isclose関数を使用することです。

次の署名があります。

isclose(a, b, rel_tol=1e-9, abs_tol=0.0)

絶対許容誤差の使用例:

from math import isclose
a = 1.0
b = 1.00000001
assert isclose(a, b, abs_tol=1e-8)

有効桁数nの精度が必要な場合は、最後の行を次のように置き換えます。

assert isclose(a, b, abs_tol=10**-n)
于 2016-04-04T16:24:31.437 に答える
29

(ソースはこちら)assert_approx_equalに関数があり、これは良い出発点になる可能性があります。numpy.testing

def assert_approx_equal(actual,desired,significant=7,err_msg='',verbose=True):
    """
    Raise an assertion if two items are not equal up to significant digits.

    .. note:: It is recommended to use one of `assert_allclose`,
              `assert_array_almost_equal_nulp` or `assert_array_max_ulp`
              instead of this function for more consistent floating point
              comparisons.

    Given two numbers, check that they are approximately equal.
    Approximately equal is defined as the number of significant digits
    that agree.
于 2009-02-17T19:16:25.010 に答える
7

これがテイクです。

def nearly_equal(a,b,sig_fig=5):
    return ( a==b or 
             int(a*10**sig_fig) == int(b*10**sig_fig)
           )
于 2009-02-17T19:07:04.783 に答える
4

すでに素晴らしい答えがたくさんありますが、ここで考えてみましょう:

def closeness(a, b):
  """Returns measure of equality (for two floats), in unit
     of decimal significant figures."""
  if a == b:
    return float("infinity")
  difference = abs(a - b)
  avg = (a + b)/2
  return math.log10( avg / difference )


if closeness(1000, 1000.1) > 3:
  print "Joy!"
于 2009-02-19T05:50:20.877 に答える
2

これは、浮動小数点数でかなり一般的な問題です。Demmel[1]のセクション1.5での議論に基づいてそれを解決します。(1)丸め誤差を計算します。(2)丸め誤差がイプシロンよりも小さいことを確認します。私はしばらくの間Pythonを使用しておらず、バージョン2.4.3しか持っていませんが、これを正しくするように努めます。

手順1.丸め誤差

def roundoff_error(exact, approximate):
    return abs(approximate/exact - 1.0)

ステップ2.浮動小数点の等式

def float_equal(float1, float2, epsilon=2.0e-9):
    return (roundoff_error(float1, float2) < epsilon)

このコードには明らかな欠陥がいくつかあります。

  1. 正確な値がゼロの場合、ゼロ除算エラー。
  2. 引数が浮動小数点値であることを確認しません。

リビジョン1。

def roundoff_error(exact, approximate):
    if (exact == 0.0 or approximate == 0.0):
        return abs(exact + approximate)
    else:
        return abs(approximate/exact - 1.0)

def float_equal(float1, float2, epsilon=2.0e-9):
    if not isinstance(float1,float):
        raise TypeError,"First argument is not a float."
    elif not isinstance(float2,float):
        raise TypeError,"Second argument is not a float."
    else:
        return (roundoff_error(float1, float2) < epsilon)

それは少し良いです。正確な値または近似値のいずれかがゼロの場合、エラーはもう一方の値と等しくなります。浮動小数点値以外のものが提供された場合、TypeErrorが発生します。

この時点で難しいのは、イプシロンの正しい値を設定することだけです。バージョン2.6.1のドキュメントで、sys.float_infoにイプシロン属性があることに気づきました。そのため、その値の2倍をデフォルトのイプシロンとして使用します。ただし、正しい値は、アプリケーションとアルゴリズムの両方によって異なります。

[1] James W. Demmel、Applied Numerical Linear Algebra、SIAM、1997年。

于 2009-02-19T04:30:15.123 に答える
2

小数の「有効数字」とは、小数点を調整して整数に切り捨てることです。

>>> int(3.1415926 * 10**3)
3141
>>> int(1234567 * 10**-3)
1234
>>>
于 2009-02-17T19:10:06.993 に答える
1

Oren Shemeshは、述べられているように問題の一部を取得しましたが、それ以上のものがあります。

ほぼ等しいと主張する(0.0、1e-15、5)

また、2番目の定義に失敗します(そしてそれは私が学校で学んだ定義です)。

表示している桁数に関係なく、0はゼロ以外と等しくなりません。正解がゼロのケースがある場合、これはそのようなテストの頭痛の種になる可能性があります。

于 2009-02-19T04:55:15.780 に答える
1

"Comparing Floating Point Numbers"に、B. Dawson (C++ コードを使用) による興味深い解決策があります。彼のアプローチは、2 つの数値の厳密な IEEE 表現と、数値が符号なし整数として表される場合の強制的な辞書式順序付けに依存しています。

于 2009-10-20T14:36:50.867 に答える
0

2 つの数値を比較して、N 桁の有効数字に一致するかどうかを確認する方法はたくさんあります。大まかに言えば、それらの差が、比較される 2 つの数値の最大値の 10^-N 倍未満であることを確認したいだけです。それは簡単です。

しかし、数字の 1 つがゼロの場合はどうなるでしょうか。ゼロと比較すると、相対差または有効桁数の概念全体が低下します。その場合を処理するには、絶対差も必要です。これは、相対差とは別に指定する必要があります。

このブログ投稿では、浮動小数点数を比較する際の問題 (ゼロを処理する特定のケースを含む) について説明します。

http://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/

于 2013-12-14T17:11:49.207 に答える