概要
- Pythonで小数点以下の任意の桁で切り捨てをする時に少しハマったのでやり方をまとめます。
桁数が小さい場合
import math
n = 2 # 切り捨てしたい桁
x = 1.555
y = math.floor(x * 10 ** n) / (10 ** n)
print(x, "=>", y) # 1.555 => 1.55
考え方としては、切り捨てたい桁数の数字が整数になるまで10^nをかけて、そこでmath.floor
を使う。その後、10^nで割って小数に戻す。標準ライブラリのmath.floor
が小数点以下を全て切り捨てとなるため。
例で言ったら、1.555
を155.5
にして切り捨て。その後、1.55
に戻している。
桁数が大きい場合
from decimal import *
root2 = Decimal(2) ** Decimal(0.5)
n = 18 # 小数第18位
y = Decimal(str(root2)).quantize(Decimal(str(10**(n*-1))), rounding=ROUND_DOWN)
print(root2, "=>", y)
# 1.414213562373095048801688724 => 1.414213562373095048
ハマったのはこっち。有効桁数が大きい(18桁くらい?)になるとどうしても誤差が入る。decimalのROUND_DOWNを使うと高い精度で切り捨てできる。
DecimalのROUND_DOWNを使わない場合
n = 18 # 切り捨てしたい桁
x = 2 ** 0.5
y = math.floor(x * 10 ** n) / (10 ** n)
print(Decimal(x), "=>", y)
# 1.4142135623730951454746218587388284504413604736328125
# => 1.4142135623730951 ※切り捨て前の値で誤差が出ている
(2019/7/21: コメントいただいて修正しました。ありがとうございます)
Decimalで文字列として設定すれば桁数の大きい値も保持できる。
>>> Decimal('123456.1234567890123')
Decimal('123456.1234567890123')
ただ、Decimalではない変数に入れた時点で誤差含みになる。この例だと、小数第11位からずれる。解決策は無さそう。
>>> d = {"value": 123456.1234567890123}
>>> Decimal(d["value"])
Decimal('123456.1234567890060134232044219970703125')
>>> Decimal(str(d["value"]))
Decimal('123456.123456789')
# 文字列で設定すると15桁の有効数字で表示