2013-10-20 100 views
8

私は平方根に近似する関数を書こうとしていました(私は数学モジュールがあることを知っています...自分でやりたいと思います)、私は浮動小数点演算に惑わされていました。どのようにそれを避けることができますか?浮動小数点エラーを回避する方法は?

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

私はちょうどround()を使用することができます実現が、私はこれは本当に正確に行うことができるようにしたい:これを使用して

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

は、これらの結果を持っています。私は6桁または7桁まで計算できるようにしたい。私が四捨五入しているなら、それは可能ではありません。 Pythonで浮動小数点計算を適切に処理する方法を理解したい。

+0

を計算するための「ニュートン法」見上げる多分ある、[小数](http://docs.python.org/2/library/decimal.html)モジュールを試してみてください精度のために設計された? – Michael0x2a

答えて

15

これは実際にはPythonとは関係がありません。ハードウェアのバイナリ浮動小数点演算を使用すると、どの言語でも同じ動作が見られます。最初はread the docsです。

これを読んだら、ではなく、がコードの1/100を追加していることがわかります。

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

を正確進値0.01に近似バイナリ浮動(Cで「倍精度」)の正確な小数の値を示している文字列:これは、あなたが追加しているまさにです。あなたが実際に追加しているものは1/100より少し大きいです。

浮動小数点数値エラーの制御は「数値解析」と呼ばれるフィールドで、非常に大きく複雑なトピックです。浮動小数点数は小数点の近似値であるという事実に驚かされる限り、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') 

それは本当に、より正確ではないのですが、今、それは正確にを追加しているため、簡単な例ではあまり意外かもしれ百分の一。

代わりに、浮動小数点数に固執し、であるものを、バイナリ浮動小数点として正確に表すことができます:I/2**Jという形式の値。たとえば、0.01を追加する代わりに、0.125(1/8)または0.0625(1/16)を追加します。

次に平方根;-)

+0

私はドキュメントを読んでいましたが、バイナリ表現を保存して浮動小数点精度の問題について知っていました。私はニュートンの方法を忘れていた。あなたはここで私の質問をすべてピックアップしています!私があなたを見つけた幸運な日。私はDecimalモジュールがどのように動作するのだろうかと思います。ソースを読むこと以外に見つける方法はありますか? – Aerovistae

+1

まあ、 'decimal'はもともとはPythonで書かれており、10進数のリスト(0,1,2、...、9)を扱っていました。紙で算術演算を行う方法を非常にエミュレートしています! "浮動小数点"は、表現に(10進)指数を追加するだけで、非常に慎重である必要があります;-)現在の 'decimal'モジュールはC言語でコード化されており、はるかに不明瞭です:-( –

+0

あなたが言ったように、 decimalモジュールを使って '4 - 3.2'を解く。 = DECIMAL(4) B = DECIMAL(3.2) しかし - Bの結果は小数である( '0.7999999999999998223643160600') – Srinesh

関連する問題