S0-ma's Blog

s0-maのブログです。

Pythonのrange関数をfloat型に拡張してみた

Abstract

Pythonのrange関数はInt型しか扱えない。0.1 ステップ刻みのようなfloat型でも同じことをやりたかったので、作ってみた。

Introduction

Pythonのrange関数は、整数値にしか使えない。 float型でやろうとするとnumpyのarrange関数を使うという手があるが、そのためだけに "import numpy"するのも気が引ける。

検索すると、以下のような関数を自分で定義するというのが割と知られているらしい。

def frange(start, end, step):
    for i in range(int((end-start)/step)):
        yield start + i*step

が、これを実際につかってみると、丸め誤差の影響が出るのであまり美しくない。

for f in frange(1.3, 2.1, 0.1):
    print(f)
    
#1.3
#1.4000000000000001
#1.5
#1.6
#1.7000000000000002
#1.8
#1.9000000000000001
#2.0

やりたいこと

float型に拡張したrange関数で、かつ、丸め誤差が乗らないようなものを作りたい。

コードと実行結果

from decimal import Decimal
def drange(start, end, step):
    start = Decimal(str(start))
    end = Decimal(str(end))
    step = Decimal(str(step))

    for i in range(int((end-start)/step)):
        yield float(start + i*step)
for f in drange(1.3, 2.1, 0.1):
    print(f)
#1.3
#1.4
#1.5
#1.6
#1.7
#1.8
#1.9
#2.0

Conclusion

今回は、一度Decimal型に内部で変換して扱うことで丸め誤差を抑えた。 Pythonの標準ライブラリの一部なので、numpyのようにインストールせずとも使えるのがメリット。

Reference

github.com

docs.python.jp