web-dev-qa-db-ja.com

浮動小数点エラーを回避する方法は?

私は平方根を近似する関数を書こうとしていて(数学モジュールがあることはわかっています...自分で実行したいのですが)、浮動小数点演算に夢中になってしまいました。どうすればそれを回避できますか?

_def sqrt(num):
    root = 0.0
    while root * root < num:
        root += 0.01
    return root
_

これを使用すると、次のような結果になります。

_>>> sqrt(4)
2.0000000000000013
>>> sqrt(9)
3.00999999999998
_

round()を使用するだけで十分だと思いますが、これを本当に正確にできるようにしたいと思っています。 6桁または7桁まで計算できるようにしたい。私が丸めている場合、それは不可能です。 Pythonで浮動小数点計算を適切に処理する方法を理解したいと思います。

20

Python-ハードウェアの2進浮動小数点演算を使用するどの言語でも同じ動作が見られます。最初に ドキュメントを読んでください

それを読んだ後は、コードに100分の1を追加しているではないことをよりよく理解できます。これはまさにあなたが追加しているものです:

>>> from decimal import Decimal
>>> Decimal(.01)
Decimal('0.01000000000000000020816681711721685132943093776702880859375')

その文字列は、バイナリ浮動(Cの「倍精度」)の正確な10進値を、正確な10進値0.01に示します。実際に追加しているのは、1/100より少し大きいサイズです。

浮動小数点数値エラーの制御は「数値解析」と呼ばれるフィールドであり、非常に大きく複雑なトピックです。浮動小数点数が10進数値の単なる近似であるという事実に驚かされている限り、decimalモジュールを使用してください。それはあなたにとって「浅い」問題の世界を取り除くでしょう。たとえば、関数に次の小さな変更を加えたとします。

from decimal import Decimal as D

def sqrt(num):
    root = D(0)
    while root * root < num:
        root += D("0.01")
    return root

次に:

>>> sqrt(4)
Decimal('2.00')
>>> sqrt(9)
Decimal('3.00')

正確ではありませんが、100分の1を正確に追加しているため、単純な例ではそれほど驚くことではありません。

別の方法は、フロートに固執し、isバイナリフロートとして正確に表現できるものを追加することです:I/2**J形式の値。たとえば、0.01を追加する代わりに、0.125(1/8)または0.0625(1/16)を追加します。

次に、平方根を計算するための「ニュートン法」を調べます;-)

24
Tim Peters