[解決済み] 浮動小数点数のコレクションに対するPythonのユニットテスト(assertAlmostEqual)
質問
その
assertAlmostEqual(x, y)
メソッドで
Python のユニットテストフレームワーク
は
x
と
y
は浮動小数点数であると仮定するとほぼ等しくなります。
の問題点は
assertAlmostEqual()
は浮動小数点数に対してのみ動作するということです。私は、以下のようなメソッドを探しています。
assertAlmostEqual()
のような、float のリスト、float のセット、float の辞書、float のタプル、float のタプルのリスト、float のリストのセット、などに対して機能するメソッドを探しています。
例えば
x = 0.1234567890
,
y = 0.1234567891
.
x
そして
y
は、最後の一桁を除くすべての桁で一致するため、ほぼ等しくなります。したがって
self.assertAlmostEqual(x, y)
は
True
なぜなら
assertAlmostEqual()
は浮動小数点数に対して機能するからです。
より一般的な
assertAlmostEquals()
への次の呼び出しを評価するような
True
:
-
self.assertAlmostEqual_generic([x, x, x], [y, y, y])
. -
self.assertAlmostEqual_generic({1: x, 2: x, 3: x}, {1: y, 2: y, 3: y})
. -
self.assertAlmostEqual_generic([(x,x)], [(y,y)])
.
そのような方法があるのでしょうか、それとも自分で実装しなければならないのでしょうか。
明確にしてください。
-
assertAlmostEquals()
は、オプションのパラメータplaces
というオプションのパラメータがあり、小数点以下を丸めた差分を計算することで比較されます。places
. デフォルトではplaces=7
であり、したがってself.assertAlmostEqual(0.5, 0.4)
は偽であるのに対してself.assertAlmostEqual(0.12345678, 0.12345679)
は真である。私の推測ではassertAlmostEqual_generic()
は同じ機能を持つはずです。 -
二つのリストは、全く同じ順番でほぼ同じ数を持っている場合、ほぼ等しいとみなされます。 正式には
for i in range(n): self.assertAlmostEqual(list1[i], list2[i])
. -
同様に、2つの集合は、(各集合に順序を割り当てることによって)ほぼ等しいリストに変換できる場合、ほぼ等しいとみなされます。
-
同様に、2つの辞書は、それぞれの辞書のキーセットがもう一方の辞書のキーセットにほぼ等しく、そのようなほぼ等しいキーペアごとに対応するほぼ等しい値が存在する場合、ほぼ等しいと見なされます。
-
一般的には 私は、2 つのコレクションが、互いにほぼ等しいだけのいくつかの対応する浮動小数点数を除いて等しい場合、ほぼ等しいと考えます。言い換えれば、私はオブジェクトを本当に比較したいのですが、途中で浮動小数点数を比較するときは、低い (カスタマイズされた) 精度で比較したいと思います。
どのように解決するのですか?
ここでは、一般的な
is_almost_equal(first, second)
機能
:
まず、比較する必要のあるオブジェクトを複製します (
first
と
second
しかし、正確なコピーを作成しないでください。オブジェクトの内部で遭遇した浮動小数点以下の桁をカットしてください。
のコピーができたので
first
と
second
を比較すると、小数点以下が消えています。
first
と
second
を使用して
==
演算子を使っています。
があると仮定しましょう。
cut_insignificant_digits_recursively(obj, places)
を複製する関数があるとします。
obj
を複製するが
places
の各浮動小数点の最上位桁を残し、元の
obj
. 以下は,実際に動作する
is_almost_equals(first, second, places)
:
from insignificant_digit_cutter import cut_insignificant_digits_recursively
def is_almost_equal(first, second, places):
'''returns True if first and second equal.
returns true if first and second aren't equal but have exactly the same
structure and values except for a bunch of floats which are just almost
equal (floats are almost equal if they're equal when we consider only the
[places] most significant digits of each).'''
if first == second: return True
cut_first = cut_insignificant_digits_recursively(first, places)
cut_second = cut_insignificant_digits_recursively(second, places)
return cut_first == cut_second
そして、これは
cut_insignificant_digits_recursively(obj, places)
:
def cut_insignificant_digits(number, places):
'''cut the least significant decimal digits of a number,
leave only [places] decimal digits'''
if type(number) != float: return number
number_as_str = str(number)
end_of_number = number_as_str.find('.')+places+1
if end_of_number > len(number_as_str): return number
return float(number_as_str[:end_of_number])
def cut_insignificant_digits_lazy(iterable, places):
for obj in iterable:
yield cut_insignificant_digits_recursively(obj, places)
def cut_insignificant_digits_recursively(obj, places):
'''return a copy of obj except that every float loses its least significant
decimal digits remaining only [places] decimal digits'''
t = type(obj)
if t == float: return cut_insignificant_digits(obj, places)
if t in (list, tuple, set):
return t(cut_insignificant_digits_lazy(obj, places))
if t == dict:
return {cut_insignificant_digits_recursively(key, places):
cut_insignificant_digits_recursively(val, places)
for key,val in obj.items()}
return obj
コードとそのユニットテストはこちらで公開されています。 https://github.com/snakile/approximate_comparator . 改善やバグフィックスを歓迎します。
関連
-
[解決済み] for'ループでインデックスにアクセスする?
-
[解決済み] Pythonには文字列の'contains'サブストリングメソッドがありますか?
-
[解決済み] ファイルのコピー方法について教えてください。
-
[解決済み] Pythonで例外を手動で発生(スロー)させる
-
[解決済み] Pythonでシングルトンを作成する
-
[解決済み】forループを使った辞書の反復処理
-
[解決済み】Pythonに三項条件演算子はありますか?
-
[解決済み] pandasのDataFrameから空のセルを含む行を削除する
-
[解決済み] Jupyter (IPython)ノートブックのセッションをpickleして保存する方法
-
[解決済み] CSVデータを処理する際、1行目のデータを無視する方法を教えてください。
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] pandasのDataFrameから空のセルを含む行を削除する
-
[解決済み] スペースがないテキストを単語のリストに分割する方法
-
[解決済み] SQLAlchemy - テーブルのリストを取得する
-
[解決済み] Ctrl-CでPythonスクリプトを終了できない
-
[解決済み] 異なる順序で同じ要素を持つ2つのJSONオブジェクトを等しく比較するには?
-
[解決済み] Python Logging でログメッセージが2回表示される件
-
[解決済み] virtualenv の `--no-site-packages` オプションを元に戻す。
-
[解決済み] Python 言語を決定するには?
-
[解決済み] Pythonの文字列書式をリストで使う
-
[解決済み] virtualenvsはどこに作成するのですか?