2018年9月28日金曜日

開発環境

  • macOS High Sierra - Apple
  • Emacs (Text Editor)
  • Python 3.7 (プログラミング言語)
Python3で巨大な浮動小数計算の結果が変だったので理由を調べてみた - paiza開発日誌
ちなみに、他の解決手段としては Decimal を使うという手もあります。

正確な計算結果を得るために、さらに他の2つの解決手段を用いてコードを書いてみた。それと、Decimalを使用した場合のちょっとした修正や気になったことについてのお話も。

コード(Emacs)

Python 3

#!/usr/bin/env python3

a = 10 ** 23

print('標準ライブラリのみで解決する1つ目の方法')

import fractions

print(fractions.Fraction(11 * a, 10))
print(fractions.Fraction(11 * 10 ** 23, 10))
# 補足: print関数を使わず対話型インタプリタで実行する場合は暗黙的にint型に変換されない
print(repr(fractions.Fraction(11 * a, 10)))

print('サードパーティのSymPyを利用する方法')

from sympy import Rational

print(Rational(11 * a, 10))
print(Rational(11 * 10 ** 23, 10))

print('Decimalを使用した場合のちょっとした修正')

import decimal

# 分子は正確な整数で、暗黙的な変換が行われるから一つで十分
print(11 * a/decimal.Decimal(10))

入出力結果(Terminal, Jupyter(IPython))

$ ./sample.py
標準ライブラリのみで解決する1つ目の方法
110000000000000000000000
110000000000000000000000
Fraction(110000000000000000000000, 1)
サードパーティのSymPyを利用する方法
110000000000000000000000
110000000000000000000000
Decimalを使用した場合のちょっとした修正
110000000000000000000000
$

今回の場合にはどちらも結果が同じにも関わらず、標準ライブラリのFractionだけではなく、あえてSymPyのRational利用した方法を紹介したのは、SymPyを利用すれば浮動小数点数の場合だけではなく無理数等のコンピューターでは正確に計算するのが困難な場合にも正確に整数の計算結果が得られる場合があり、応用範囲が広いと考えたから。

あともう一つ、ちょっとだけ気になったところ。

「//」演算子を使用した場合は、一度も float になることがないはずなので、正しい計算結果が出るのですね。

今回の場合は問題ないけど、「//」演算子は切り捨て(商と剰余(余り)の商を得る)演算子だから、正しい計算結果を得るために使うと問題が発生することもあったり。

単純な例。

コード(Emacs)

Python 3

#!/usr/bin/env python3

print(f'/ : {1 / 2}')
print(f'//: {1 // 2}')

入出力結果(Terminal, Jupyter(IPython))

$ ./sample.py
/ : 0.5
//: 0
$

0 コメント:

コメントを投稿