質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Q&A

解決済

6回答

252閲覧

float型でも取り扱えるようにrange関数のような関数を作る

yamatail

総合スコア77

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

0グッド

0クリップ

投稿2019/01/23 06:27

前提・実現したいこと

range関数がfloat型に対応していないので、
関数を定義したが、stepを0.1にすると
すごく細かい少数が出てきてしまう。
これは、2進法のためというのも何となく理解できました。

何か良い方法はないものでしょうか?

発生している問題・エラーメッセージ

python

1In:list(drange(17.8,20,0.1)) 2Out: 3[17.8, 4 17.900000000000002, 5 18.000000000000004, 6 18.100000000000005, 7 18.200000000000006, 8 18.300000000000008, 9 18.40000000000001, 10 18.50000000000001, 11 18.600000000000012, 12 18.700000000000014, 13 18.800000000000015, 14 18.900000000000016, 15 19.000000000000018, 16 19.10000000000002, 17 19.20000000000002, 18 19.300000000000022, 19 19.400000000000023, 20 19.500000000000025, 21 19.600000000000026, 22 19.700000000000028, 23 19.80000000000003]

該当のソースコード

python

1def drange(start, end, step): 2 n =start 3 while n + step < end: 4 yield n 5 n += step

試したこと

補足情報(FW/ツールのバージョンなど)

python3

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答6

0

見た目だけの問題なら気にするほうがおかしいのでそのまま使う、ということでいいんじゃないでしょうか。
この配列でいかに見た目を気にしたところで、その値を使うときには必ずその数値(あなたの言う細かい小数)になるので意味ありません

投稿2019/01/23 06:38

y_waiwai

総合スコア87774

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

maisumakun

2019/01/23 06:39

単純に0.2(誤差含み)を足していくと、同じ方向に誤差が蓄積していってしまいます。
yamatail

2019/01/24 00:27

そうなんですよね、実際。 ただ、私の作った関数の場合、誤差の累積も考えられるようなので、 他の方の指摘にもあるように、それならnp.arangeでいけばいいかなと思っております。 見た目もきれいにしてくれるようですし(笑)
guest

0

numpyを使える環境ならnp.arangeがあるので、車輪の再開発をやる必要はありません。

python

1>>> import numpy as np 2>>> np.arange(17.8,20,0.1) 3array([17.8, 17.9, 18. , 18.1, 18.2, 18.3, 18.4, 18.5, 18.6, 18.7, 18.8, 4 18.9, 19. , 19.1, 19.2, 19.3, 19.4, 19.5, 19.6, 19.7, 19.8, 19.9])

ただしnumpy配列は綺麗に表示するために表示桁数を少なくしているので注意。実際には浮動小数点数なので、下の方の桁には誤差がある場合もあります(というかほぼ当然にある)。

自分で作る場合は、毎回stepを足していくのではなく、先に全体に含まれる要素数を計算してからループを要素数分だけ回して処理するか、(同じことですが)整数のカウンタを別途用意してそちらをインクリメントしながらループを回し、(start + count*stepみたいにして)出していった方が誤差が累積しないはずです。

投稿2019/01/23 06:37

編集2019/01/23 07:07
hayataka2049

総合スコア30933

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

yamatail

2019/01/24 00:23

np.arangeなんていうのがあるのですね、勉強不足です。。。 誤差の累積を考慮する点も自分では考えてもなかったので、とても参考になりました。 ありがとうございます。
guest

0

小数点刻みを実装しているnumpy.arangeのドキュメントに

https://docs.scipy.org/doc/numpy-1.15.0/reference/generated/numpy.arange.html

When using a non-integer step, such as 0.1, the results will often not be consistent. It is better to use linspace for these cases.

と書いてあって、その用途にはnumpy.linspaceを使うのがいい、とあります。

で、numpy.linspaceの実装はというと、np.linspace(17.8,19.9,22)np.arange(22) * 0.1 + 17.8と同等です。(こことかここ
誤差を積み重ねないために、整数で要素を組み上げてから演算で作ってます。

「range関数がfloat型に対応していない」というよりも、うかつに対応すると誤差を累積したデータを簡単に作れてしまうからデザインとして採用していないのかと思いました。

投稿2019/01/23 07:35

quickquip

総合スコア11038

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

yamatail

2019/01/24 00:33

ほー!公式にはfloat型の場合は、arangeよりもlinespaceをお勧めしているのですね。 2つともfloat型にも対応しているが、 arangeは、毎回stepを足す作り方で、 linespaceは、(start + count*step)ということでしょうかね。 それなら、linespeceの方がよさげですね!ありがとうございます。
guest

0

美しくはありませんが、分数を使って

python

1from fractions import Fraction 2 3def drange(start, stop, step): 4 while start < stop: 5 yield float(start) 6 start += step 7 8a = Fraction(178, 10) 9b = 20 10c = Fraction(1, 10) 11 12print(list(drange(a, b, c)))

という手もあります。

投稿2019/01/23 09:06

kts_h

総合スコア207

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

Fraction を使った回答がでますが、 Fraction をつかわないならこんな感じにすると
float の足し算の誤差の集積を防ぐことができます。
(stop 値付近の値がループにあらわれるか否かの判定はちょっと不安定かもしれません。)

python3

1def drange(start, stop, step = 1.0): 2 count = int((stop - start) / step + 2) 3 for t in range(0, count): 4 v = start + t * step 5 if v < stop: 6 yield v 7 8print(list(drange(17.8, 20, 0.1))) 9 10print(list(drange(0.0, 0.5, 0.1))) 11print(list(drange(10000.0, 10000.5, 0.1)))

実行例
イメージ説明

投稿2019/01/25 23:14

katoy

総合スコア22324

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

ベストアンサー

もう少し美しくできるようになりました。

python

1from fractions import Fraction 2 3def drange(start, stop, step): 4 start = Fraction(str(start)) 5 step = Fraction(str(step)) 6 while start < stop: 7 yield float(start) 8 start += step 9 10print(list(drange(17.8, 20, 0.1)))

投稿2019/01/23 12:19

kts_h

総合スコア207

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

yamatail

2019/01/24 00:45

これは、きれいにでますね!理想的なlistが作れます。 ちょっとどうなってるか勉強してみたいと思います。 大変参考になりました。ありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問