floatのrange()


140

range()Pythonのフロートに相当するものはありますか?

>>> range(0.5,5,1.5)
[0, 1, 2, 3, 4]
>>> range(0.5,5,0.5)

Traceback (most recent call last):
  File "<pyshell#10>", line 1, in <module>
    range(0.5,5,0.5)
ValueError: range() step argument must not be zero

1
それらは分数ではなく浮動です。そして、フロートは...まあ、予想とは異なる結果をもたらす可能性があります。

6
迅速な回避策は、例えば、小数として扱う整数に次のようになりますrange(5, 50, 5)、その後、ちょうど10で、すべての数を分割する
NullUserException

@delnan-更新されました。浮動小数点数の範囲を持っているという便宜のために、ちょっとした不正確さを受け入れたいと思います
Jonathan


@NullUserException-これは単なる例です-実際のコードはもちろんパラメトリックです:)
Jonathan

回答:


97

組み込み関数はわかりませんが、このような関数の記述はそれほど複雑ではないはずです。

def frange(x, y, jump):
  while x < y:
    yield x
    x += jump

コメントが言及するように、これは次のような予測できない結果をもたらす可能性があります。

>>> list(frange(0, 100, 0.1))[-1]
99.9999999999986

期待される結果を得るには、この質問の他の回答のいずれかを使用するか、@ Tadhgが言及したようにdecimal.Decimaljump引数として使用できます。floatではなく文字列で初期化してください。

>>> import decimal
>>> list(frange(0, 100, decimal.Decimal('0.1')))[-1]
Decimal('99.9')

あるいは:

import decimal

def drange(x, y, jump):
  while x < y:
    yield float(x)
    x += decimal.Decimal(jump)

その後:

>>> list(drange(0, 100, '0.1'))[-1]
99.9

34
Pythonのモットーは、実際には1つ(できれば1つだけ)であるべきです。しかし、Pythonはとにかく最高です:)
ジョナサン

3
>>> print list(frange(0,100,0.1))[-1]==100.0予定False
Volodimir Kopey 2015年

frange予期せず動作する可能性があります。たとえば、浮動小数点演算の呪いにより、frange(0.0, 1.0, 0.1)11個の値が生成されます0.9999999999999999。最後の値はです。実際の改善は、while x + sys.float_info.epsilon < y:これでもおそらく大きな数で失敗する可能性があります
AkseliPalén2016年

10
-1 少なくとも私の人生に影響を与える可能性のあるソフトウェアでは、このコードを使用しないでください。確実に機能させる方法はありません。AkseliPalénの回答も使用しないでください。Xaerxessまたはwimの回答を使用します(範囲に関する部分を無視する場合を除く)。
benrg

3
フロートの代わりにステップとして使用する場合、decimal.Decimalこれはうまく機能します
Tadhg McDonald-Jensen 2016

112

次のいずれかを使用できます。

[x / 10.0 for x in range(5, 50, 15)]

またはラムダ/マップを使用:

map(lambda x: x/10.0, range(5, 50, 15))

1
そして、array(range(5,50,15))/ 10.0 numpy配列には除算や乗算などを処理するための演算子があるため
edvaldig

2
@edvaldig:そうです、私はこれについて知りませんでした...それにもかかわらず、私arange(0.5, 5, 1.5)はIMOの方が読みやすいと思います。
Xaerxess、2011

2
提示された最初の2つのソリューションは整数の反復と、整数からの最終的な浮動小数点数の導出に基づいているため、私は受け入れられたものよりもこの答えを好みます。これはより堅牢です。フロートを直接使用すると、フロートが内部でどのように表現されるかによって、奇妙な1回限りのエラーが発生するリスクがあります。たとえば、を試すとlist(frange(0, 1, 0.5))正常に機能し、1は除外されますが、を試すlist(frange(0, 1, 0.1))と、最後に取得する値は1.0に近くなり、おそらく望んだものとは異なります。ここで紹介するソリューションには、この問題はありません。
blubberdiblub 2015

3
numpy.arangeは絶対に使用しないでください(numpyのドキュメント自体で推奨されていません)。wimが推奨するnumpy.linspace、またはこの回答の他の提案の1つを使用します。
benrg 2016年

79

以前は使用してnumpy.arangeいましたが、浮動小数点エラーのため、返される要素の数を制御するのにいくつかの複雑な問題がありました。だから今私は使用しますlinspace、例えば:

>>> import numpy
>>> numpy.linspace(0, 10, num=4)
array([  0.        ,   3.33333333,   6.66666667,  10.        ])

ただし、浮動小数点エラーはまだありますがdecimal、を使用していません。例:np.linspace(-.1,10,num=5050)[0]
TNT

2
@TNTいいえ、それはエラーではありません。あなたnp.linspace(-.1,10,num=5050)[0] == -.1は真実であることがわかります。repr(np.float64('-0.1'))より多くの桁が表示されるだけです。
2017

1
この特定の例では、過剰な丸め誤差は示されていませんが、失敗する場合があります。たとえば、理想的な結果がである場合にprint(numpy.linspace(0, 3, 148)[49])印刷0.9999999999999999します1.0linspaceはに比べてはるかに優れていますがarange、可能な最小の丸め誤差が生成されるとは限りません。
user2357112は

正しいエンドポイント処理を実行し、常に要求された数の要素を正確に生成すること保証されています。
user2357112は

40

Pylabにはfrange(実際のラッパーmatplotlib.mlab.frange)があります。

>>> import pylab as pl
>>> pl.frange(0.5,5,0.5)
array([ 0.5,  1. ,  1.5,  2. ,  2.5,  3. ,  3.5,  4. ,  4.5,  5. ])

4
Frangeは、matplotlibバージョン2.2以降非推奨です。numpy.arangeを使用する必要があります。
kuzavas 2018年

13

熱心に評価された(2.x range):

[x * .5 for x in range(10)]

遅延評価(2.x xrange、3.x range):

itertools.imap(lambda x: x * .5, xrange(10)) # or range(10) as appropriate

代わりに:

itertools.islice(itertools.imap(lambda x: x * .5, itertools.count()), 10)
# without applying the `islice`, we get an infinite stream of half-integers.

4
+1; しかし、なぜ(x * .5 for x in range(10))遅延評価のジェネレータ式としてではないのですか?
Tim Pietzcker、2011

2
それは簡単すぎると思いますか?:)
Karl Knechtel、2011

11

使用itertools:遅延評価された浮動小数点範囲:

>>> from itertools import count, takewhile
>>> def frange(start, stop, step):
        return takewhile(lambda x: x< stop, count(start, step))

>>> list(frange(0.5, 5, 1.5))
# [0.5, 2.0, 3.5]

3
を使用するための+1 itertools.takewhile。ただし、itertools.count(start, step)蓄積された浮動小数点エラーの影響を受けます。(takewhile(lambda x: x < 100, count(0, 0.1))例えば、評価します。)takewhile(lambda x: x < stop, (start + i * step for i in count()))代わりに私は書きます。
musiphil 2016

6

関数numeric_rangeをパッケージmore-itertoolsに追加するのを手伝いました。

more_itertools.numeric_range(start, stop, step) 組み込み関数の範囲と同様に機能しますが、float、decimal、およびfraction型を処理できます。

>>> from more_itertools import numeric_range
>>> tuple(numeric_range(.1, 5, 1))
(0.1, 1.1, 2.1, 3.1, 4.1)

4

そのような組み込み関数はありませんが、次の(Python 3コード)を使用して、Pythonで可能な限り安全に作業を行うことができます。

from fractions import Fraction

def frange(start, stop, jump, end=False, via_str=False):
    """
    Equivalent of Python 3 range for decimal numbers.

    Notice that, because of arithmetic errors, it is safest to
    pass the arguments as strings, so they can be interpreted to exact fractions.

    >>> assert Fraction('1.1') - Fraction(11, 10) == 0.0
    >>> assert Fraction( 0.1 ) - Fraction(1, 10) == Fraction(1, 180143985094819840)

    Parameter `via_str` can be set to True to transform inputs in strings and then to fractions.
    When inputs are all non-periodic (in base 10), even if decimal, this method is safe as long
    as approximation happens beyond the decimal digits that Python uses for printing.


    For example, in the case of 0.1, this is the case:

    >>> assert str(0.1) == '0.1'
    >>> assert '%.50f' % 0.1 == '0.10000000000000000555111512312578270211815834045410'


    If you are not sure whether your decimal inputs all have this property, you are better off
    passing them as strings. String representations can be in integer, decimal, exponential or
    even fraction notation.

    >>> assert list(frange(1, 100.0, '0.1', end=True))[-1] == 100.0
    >>> assert list(frange(1.0, '100', '1/10', end=True))[-1] == 100.0
    >>> assert list(frange('1', '100.0', '.1', end=True))[-1] == 100.0
    >>> assert list(frange('1.0', 100, '1e-1', end=True))[-1] == 100.0
    >>> assert list(frange(1, 100.0, 0.1, end=True))[-1] != 100.0
    >>> assert list(frange(1, 100.0, 0.1, end=True, via_str=True))[-1] == 100.0

    """
    if via_str:
        start = str(start)
        stop = str(stop)
        jump = str(jump)
    start = Fraction(start)
    stop = Fraction(stop)
    jump = Fraction(jump)
    while start < stop:
        yield float(start)
        start += jump
    if end and start == stop:
        yield(float(start))

いくつかのアサーションを実行することで、すべてを確認できます。

assert Fraction('1.1') - Fraction(11, 10) == 0.0
assert Fraction( 0.1 ) - Fraction(1, 10) == Fraction(1, 180143985094819840)

assert str(0.1) == '0.1'
assert '%.50f' % 0.1 == '0.10000000000000000555111512312578270211815834045410'

assert list(frange(1, 100.0, '0.1', end=True))[-1] == 100.0
assert list(frange(1.0, '100', '1/10', end=True))[-1] == 100.0
assert list(frange('1', '100.0', '.1', end=True))[-1] == 100.0
assert list(frange('1.0', 100, '1e-1', end=True))[-1] == 100.0
assert list(frange(1, 100.0, 0.1, end=True))[-1] != 100.0
assert list(frange(1, 100.0, 0.1, end=True, via_str=True))[-1] == 100.0

assert list(frange(2, 3, '1/6', end=True))[-1] == 3.0
assert list(frange(0, 100, '1/3', end=True))[-1] == 100.0

GitHubで利用可能なコード


4

標準ライブラリに浮動小数点範囲の実装がないのはなぜですか?

ここのすべての投稿から明らかなように、の浮動小数点バージョンはありませんrange()。とは言え、range()関数がインデックス(そしてもちろん、アクセサーを意味する)ジェネレーターとして頻繁に使用されることを考えると、省略は理にかなっています。したがって、を呼び出すとrange(0,40)、実際には0から40までの40個の値が必要ですが、40自体は含まれません。

インデックスの生成はインデックスの数と同じくらい重要であると考えるとrange()、標準ライブラリでのfloat実装の使用はあまり意味がありません。たとえば、関数を呼び出した場合frange(0, 10, 0.25)、0と10の両方が含まれると予想されますが、これにより41の値を持つベクトルが生成されます。

したがって、frange()その使用に依存する関数は、常に直感に反する動作を示します。インデックス作成の観点から認識される値が多すぎるか、数学的な観点から合理的に返される数値が含まれていないかのいずれかです。

数学的ユースケース

そうは言っても、議論したようにnumpy.linspace()、数学的な見方でうまく生成を実行します:

numpy.linspace(0, 10, 41)
array([  0.  ,   0.25,   0.5 ,   0.75,   1.  ,   1.25,   1.5 ,   1.75,
         2.  ,   2.25,   2.5 ,   2.75,   3.  ,   3.25,   3.5 ,   3.75,
         4.  ,   4.25,   4.5 ,   4.75,   5.  ,   5.25,   5.5 ,   5.75,
         6.  ,   6.25,   6.5 ,   6.75,   7.  ,   7.25,   7.5 ,   7.75,
         8.  ,   8.25,   8.5 ,   8.75,   9.  ,   9.25,   9.5 ,   9.75,  10.
])

インデックスの使用例

そして、インデックス作成の観点から、小数点以下の桁数を指定できるようにするための少し厄介な文字列マジックを使用して、少し異なるアプローチを記述しました。

# Float range function - string formatting method
def frange_S (start, stop, skip = 1.0, decimals = 2):
    for i in range(int(start / skip), int(stop / skip)):
        yield float(("%0." + str(decimals) + "f") % (i * skip))

同様に、組み込みround関数を使用して小数点以下の桁数を指定することもできます。

# Float range function - rounding method
def frange_R (start, stop, skip = 1.0, decimals = 2):
    for i in range(int(start / skip), int(stop / skip)):
        yield round(i * skip, ndigits = decimals)

簡単な比較とパフォーマンス

もちろん、上記の説明を踏まえると、これらの関数のユースケースはかなり限定されています。それにもかかわらず、ここに簡単な比較があります:

def compare_methods (start, stop, skip):

    string_test  = frange_S(start, stop, skip)
    round_test   = frange_R(start, stop, skip)

    for s, r in zip(string_test, round_test):
        print(s, r)

compare_methods(-2, 10, 1/3)

結果はそれぞれ同じです:

-2.0 -2.0
-1.67 -1.67
-1.33 -1.33
-1.0 -1.0
-0.67 -0.67
-0.33 -0.33
0.0 0.0
...
8.0 8.0
8.33 8.33
8.67 8.67
9.0 9.0
9.33 9.33
9.67 9.67

そしていくつかのタイミング:

>>> import timeit

>>> setup = """
... def frange_s (start, stop, skip = 1.0, decimals = 2):
...     for i in range(int(start / skip), int(stop / skip)):
...         yield float(("%0." + str(decimals) + "f") % (i * skip))
... def frange_r (start, stop, skip = 1.0, decimals = 2):
...     for i in range(int(start / skip), int(stop / skip)):
...         yield round(i * skip, ndigits = decimals)
... start, stop, skip = -1, 8, 1/3
... """

>>> min(timeit.Timer('string_test = frange_s(start, stop, skip); [x for x in string_test]', setup=setup).repeat(30, 1000))
0.024284090992296115

>>> min(timeit.Timer('round_test = frange_r(start, stop, skip); [x for x in round_test]', setup=setup).repeat(30, 1000))
0.025324633985292166

私のシステムでは、文字列のフォーマット方法が勝っているようです。

制限

そして最後に、上記の議論からのポイントのデモンストレーションと最後の1つの制限:

# "Missing" the last value (10.0)
for x in frange_R(0, 10, 0.25):
    print(x)

0.25
0.5
0.75
1.0
...
9.0
9.25
9.5
9.75

さらに、skipパラメータがstop値で割り切れない場合、後者の問題を考えるとあくびのギャップが生じる可能性があります。

# Clearly we know that 10 - 9.43 is equal to 0.57
for x in frange_R(0, 10, 3/7):
    print(x)

0.0
0.43
0.86
1.29
...
8.14
8.57
9.0
9.43

この問題に対処する方法はいくつかありますが、結局のところ、最善のアプローチはおそらくNumpyを使用することでしょう。


これはかなりねじれた議論です。range()は単に反復ジェネレーターを調べ、それがforループで使用されているのか、またはインデックス付けに使用されているのかは、呼び出し元に任せる必要があります。人々はミレニアのforループでフロートを使用しており、上記の正当化は無意味です。Python委員会の人々はここで大いに時間を浪費し、良い議論はおそらく上記のようなねじれた正当化によっておおわれてしまいました。それは単純で単純です。上記のようにPython言語にまとめられた決定が多すぎます。
Shital Shah

3

numpyの依存関係などを含まない溶液を kichikによって提供されたが、原因に浮動小数点演算、それは多くの場合、予期せずに動作します。blubberdiblubが指摘したように、追加の要素は結果に簡単に忍び込みます。たとえば、最後の値としてnaive_frange(0.0, 1.0, 0.1)生成さ0.999...れるため、合計11個の値が生成されます。

堅牢なバージョンがここに提供されています:

def frange(x, y, jump=1.0):
    '''Range for floats.'''
    i = 0.0
    x = float(x)  # Prevent yielding integers.
    x0 = x
    epsilon = jump / 2.0
    yield x  # yield always first value
    while x + epsilon < y:
        i += 1.0
        x = x0 + i * jump
        yield x

乗算なので、丸め誤差は蓄積されません。epsilonもちろん問題が非常に小さく、非常に大きい場合に発生する可能性がありますが、を使用すると、乗算の丸め誤差の可能性に対処できます。さて、期待どおり:

> a = list(frange(0.0, 1.0, 0.1))
> a[-1]
0.9
> len(a)
10

そして、やや大きな数で:

> b = list(frange(0.0, 1000000.0, 0.1))
> b[-1]
999999.9
> len(b)
10000000

コードはGitHub Gistとしても入手できます。


これはfrange(2.0、17.0 / 6.0、1.0 / 6.0)で失敗します。堅牢にすることはできません。
benrg 2016年

@benrgこれを指摘してくれてありがとう!イプシロンはジャンプに依存する必要があることに気づき、アルゴリズムを見直して問題を修正しました。この新しいバージョンは、はるかに堅牢ですよね。
AkseliPalén16年

2

ライブラリなしのシンプルなバージョン

ああ、一体-私は単純なライブラリなしのバージョンで投げます。自由に改善してください[*]:

def frange(start=0, stop=1, jump=0.1):
    nsteps = int((stop-start)/jump)
    dy = stop-start
    # f(i) goes from start to stop as i goes from 0 to nsteps
    return [start + float(i)*dy/nsteps for i in range(nsteps)]

核となる考えは、nsteps最初から最後まであなたを得るステップ数であり、range(nsteps)常に整数を放出するので、正確さの損失はありません。最後のステップは、[0..nsteps]を[start..stop]に線形にマッピングすることです。

編集する

alancalvittiのように、シリーズに正確な有理表現を持たせたい場合は、常にFractionsを使用できます。

from fractions import Fraction

def rrange(start=0, stop=1, jump=0.1):
    nsteps = int((stop-start)/jump)
    return [Fraction(i, nsteps) for i in range(nsteps)]

[*]特に、frange()ジェネレータではなくリストを返します。しかし、それは私のニーズには十分でした。


出力にストップ値を含める場合は、stop + jumpを追加することにより、このメソッドは中間に不良浮動小数点を含む単純な結果に戻りfrange(0,1.1,0.1)、さらに次のような選択肢を持つものを試しますfrange(0,1.05,0.1)
alancalvitti

@alancalvitti:「悪い」浮動小数点の定義は何ですか?はい、結果はうまく印刷されない可能性がありますが、frange()は、浮動小数点表現の制限内で最も近い等間隔の値のセットを提供します。どのように改善しますか?
fearless_fool

良い点、私はあなたがそのようなタスクのために有理数に及ぶような高級言語に慣れているので、Pyはアセンブリのように感じます。
alancalvitti

アセンブリ?うん!;)もちろんPythonは画分に正確な表現を提供することができます:docs.python.org/3/library/fractions.htmlを
fearless_fool

そうです、ありがとうございます。たとえば、私が好きな言語はこれらの型を自動的に変換します。そのため、1/2は有理であり、1 / 2.0は浮動小数点であるので、そのように宣言する必要はありません。宣言はJavaに任せてください。 Pyよりも低い/アセンブリ。
alancalvitti

2

これはnumpy.arange(start、stop、stepsize)で実行できます

import numpy as np

np.arange(0.5,5,1.5)
>> [0.5, 2.0, 3.5, 5.0]

# OBS you will sometimes see stuff like this happening, 
# so you need to decide whether that's not an issue for you, or how you are going to catch it.
>> [0.50000001, 2.0, 3.5, 5.0]

注1: ここのコメントセクションでの議論から、「絶対に使用しないでくださいnumpy.arange()(numpyのドキュメント自体が推奨していません。wimが推奨するnumpy.linspaceを使用するか、この回答の他の提案の1つを使用してください」

注2: 私はここでいくつかのコメントで議論を読みましたが、この質問に3回目に戻った後、この情報はより読みやすい位置に配置する必要があると思います。


2

以下のようkichikが書いた、これはあまりにも複雑ではありません。ただし、このコード:

def frange(x, y, jump):
  while x < y:
    yield x
    x += jump

フロートを操作するときのエラー累積的な影響のため、不適切です。そのため、次のようなものが表示されます。

>>>list(frange(0, 100, 0.1))[-1]
99.9999999999986

予想される動作は次のとおりです。

>>>list(frange(0, 100, 0.1))[-1]
99.9

解決策1

累積誤差は、インデックス変数を使用することで簡単に減らすことができます。次に例を示します。

from math import ceil

    def frange2(start, stop, step):
        n_items = int(ceil((stop - start) / step))
        return (start + i*step for i in range(n_items))

この例は期待どおりに動作します。

解決策2

入れ子関数はありません。しばらくの間とカウンター変数:

def frange3(start, stop, step):
    res, n = start, 1

    while res < stop:
        yield res
        res = start + n * step
        n += 1

この関数は、逆の範囲が必要な場合を除いて、うまく機能します。例えば:

>>>list(frange3(1, 0, -.1))
[]

この場合のソリューション1は期待どおりに機能します。このような状況でこの関数を機能させるには、次のようなハックを適用する必要があります。

from operator import gt, lt

def frange3(start, stop, step):
    res, n = start, 0.
    predicate = lt if start < stop else gt
    while predicate(res, stop):
        yield res
        res = start + n * step
        n += 1

このハックを使用すると、これらの関数を負のステップで使用できます。

>>>list(frange3(1, 0, -.1))
[1, 0.9, 0.8, 0.7, 0.6, 0.5, 0.3999999999999999, 0.29999999999999993, 0.19999999999999996, 0.09999999999999998]

解決策3

単純な標準ライブラリをさらに使用して、ほとんどの数値型の範囲関数を作成できます。

from itertools import count
from itertools import takewhile

def any_range(start, stop, step):
    start = type(start + step)(start)
    return takewhile(lambda n: n < stop, count(start, step))

このジェネレーターは、Fluent Pythonの本(第14章Iterables、イテレーター、ジェネレーター)から改変されています。減少する範囲では機能しません。前のソリューションと同様に、ハックを適用する必要があります。

このジェネレーターは、たとえば次のように使用できます。

>>>list(any_range(Fraction(2, 1), Fraction(100, 1), Fraction(1, 3)))[-1]
299/3
>>>list(any_range(Decimal('2.'), Decimal('4.'), Decimal('.3')))
[Decimal('2'), Decimal('2.3'), Decimal('2.6'), Decimal('2.9'), Decimal('3.2'), Decimal('3.5'), Decimal('3.8')]

もちろん、floatintでも使用できます。

注意してください

これらの関数を負のステップで使用する場合は、ステップ記号のチェックを追加する必要があります。例:

no_proceed = (start < stop and step < 0) or (start > stop and step > 0)
if no_proceed: raise StopIteration

ここでの最良のオプションはStopIterationrange関数自体を模倣したい場合にを発生させることです。

模倣範囲

range関数インターフェイスを模倣したい場合は、いくつかの引数チェックを提供できます。

def any_range2(*args):
    if len(args) == 1:
        start, stop, step = 0, args[0], 1.
    elif len(args) == 2:
        start, stop, step = args[0], args[1], 1.
    elif len(args) == 3:
        start, stop, step = args
    else:
        raise TypeError('any_range2() requires 1-3 numeric arguments')

    # here you can check for isinstance numbers.Real or use more specific ABC or whatever ...

    start = type(start + step)(start)
    return takewhile(lambda n: n < stop, count(start, step))

私はあなたがポイントを持っていると思います。あなたは(非常に最初のものを除く)これらの関数のいずれかで行くことができますし、すべてのあなたが彼らのために必要ではPython標準ライブラリです。


1

100分の1を超える小数点以下の桁数のない倍精度浮動小数点数の範囲のタプルを返す関数を書きました。それは単に、文字列のような範囲の値を解析し、超過分を分割することの問題でした。UI内から選択する範囲を表示するために使用します。他の誰かがそれが役に立つと思うことを望みます。

def drange(start,stop,step):
    double_value_range = []
    while start<stop:
        a = str(start)
        a.split('.')[1].split('0')[0]
        start = float(str(a))
        double_value_range.append(start)
        start = start+step
    double_value_range_tuple = tuple(double_value_range)
   #print double_value_range_tuple
    return double_value_range_tuple

1

使用法

# Counting up
drange(0, 0.4, 0.1)
[0, 0.1, 0.2, 0.30000000000000004, 0.4]

# Counting down
drange(0, -0.4, -0.1)
[0, -0.1, -0.2, -0.30000000000000004, -0.4]

各ステップを小数点以下N桁に丸めるには

drange(0, 0.4, 0.1, round_decimal_places=4)
[0, 0.1, 0.2, 0.3, 0.4]

drange(0, -0.4, -0.1, round_decimal_places=4)
[0, -0.1, -0.2, -0.3, -0.4]

コード

def drange(start, end, increment, round_decimal_places=None):
    result = []
    if start < end:
        # Counting up, e.g. 0 to 0.4 in 0.1 increments.
        if increment < 0:
            raise Exception("Error: When counting up, increment must be positive.")
        while start <= end:
            result.append(start)
            start += increment
            if round_decimal_places is not None:
                start = round(start, round_decimal_places)
    else:
        # Counting down, e.g. 0 to -0.4 in -0.1 increments.
        if increment > 0:
            raise Exception("Error: When counting down, increment must be negative.")
        while start >= end:
            result.append(start)
            start += increment
            if round_decimal_places is not None:
                start = round(start, round_decimal_places)
    return result

なぜこの答えを選ぶのですか?

  • カウントダウンを求められたときに他の多くの答えがハングします。
  • 他の多くの回答では、正しく丸められた結果が得られます。
  • に基づく他の答えnp.linspaceはヒットアンドミスです。正しい分割数を選択するのが難しいため、それらは機能する場合と機能しない場合があります。np.linspace10進数の増分0.1で実際に苦労しており、増分を分割数に変換する数式の除算の順序は、正しいコードまたは壊れたコードになる可能性があります。
  • に基づく他の回答np.arangeは非推奨です。

疑問がある場合は、上記の4つのテストケースを試してください。


0
def Range(*argSequence):
    if len(argSequence) == 3:
        imin = argSequence[0]; imax = argSequence[1]; di = argSequence[2]
        i = imin; iList = []
        while i <= imax:
            iList.append(i)
            i += di
        return iList
    if len(argSequence) == 2:
        return Range(argSequence[0], argSequence[1], 1)
    if len(argSequence) == 1:
        return Range(1, argSequence[0], 1)

Rangeの最初の文字は大文字です。この命名方法は、Pythonの関数では推奨されません。必要に応じてRangeをdrangeやfrangeなどに変更できます。「範囲」関数は、期待どおりに動作します。マニュアルはこちら[ http://reference.wolfram.com/language/ref/Range.html ]で確認できます。


0

floatとintegerの両方について、範囲のすべての機能を実際にエミュレートする非常に単純な答えがあると思います。このソリューションでは、デフォルトの近似が1e-7(または選択したもの)であると想定し、関数を呼び出すときにそれを変更できます。

def drange(start,stop=None,jump=1,approx=7): # Approx to 1e-7 by default
  '''
  This function is equivalent to range but for both float and integer
  '''
  if not stop: # If there is no y value: range(x)
      stop= start
      start= 0
  valor= round(start,approx)
  while valor < stop:
      if valor==int(valor):
          yield int(round(valor,approx))
      else:
          yield float(round(valor,approx))
      valor += jump
  for i in drange(12):
      print(i)

0

もちろん、いくつかの丸め誤差があるので、これは完璧ではありませんが、これは、高精度を必要としないアプリケーションで一般的に使用するものです。これをより正確にしたい場合は、引数を追加して、丸めエラーの処理方法を指定できます。おそらく、丸め関数を渡すと、これが拡張可能になり、プログラマーが丸めエラーの処理方法を指定できるようになります。

arange = lambda start, stop, step: [i + step * i for i in range(int((stop - start) / step))]

私が書いた場合:

arange(0, 1, 0.1)

それは出力します:

[0.0, 0.1, 0.2, 0.30000000000000004, 0.4, 0.5, 0.6000000000000001, 0.7000000000000001, 0.8, 0.9]

-1

Pythonのfloatに相当するrange()はありますか?いいえこれを使用してください:

def f_range(start, end, step):
    a = range(int(start/0.01), int(end/0.01), int(step/0.01))
    var = []
    for item in a:
        var.append(item*0.01)
    return var

3
かなり悪い解決策、試してみてくださいf_range(0.01,0.02,0.001)...最も実用的な目的のためにarange、Numpyはシンプルで安全かつ高速な解決策です。
Bart

あなたが正しいです。numpyを使用すると、私のコードよりも1.8倍速くなります。
Grigor Kolev 2017年

あなたが正しいです。numpyを使用すると、私のコードよりも1.8倍速くなります。しかし、私が働いているシステムは完全に閉鎖されています。Pythonとpyserialのみです。
Grigor Kolev 2017年

-2

ネガティブステップ、間違った開始、停止などの単純なエッジケースを処理しないいくつかの回答があります。ネイティブと同じ動作を正しく提供するこれらのケースの多くを処理するバージョンは次のrange()とおりです。

def frange(start, stop=None, step=1):
  if stop is None:
    start, stop = 0, start
  steps = int((stop-start)/step)
  for i in range(steps):
    yield start
    start += step  

これは、ネイティブと同じようにstep = 0でエラーになることに注意してくださいrange。1つの違いは、ネイティブ範囲は、インデックス化可能で可逆的であるオブジェクトを返しますが、上記ではそうではありません。

このコードとテストケースをここで試すことができます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.