Ondalık aralık () adım değeri nasıl kullanılır?


744

0 ile 1 arasında 0,1 adım atmanın bir yolu var mı?

Bunu aşağıdaki gibi yapabileceğimi düşündüm, ancak başarısız oldu:

for i in range(0, 1, 0.1):
    print i

Bunun yerine, adım argümanının sıfır olamayacağını, ki beklemediğimi söylüyor.


17
int (0.1) == 0, yani adım aslında sıfırdır. Beklenmedik olabilir, ancak sıfırdır. Bunu beklemediğiniz gerçeğini yansıtmak için sorunuzu yeniden ifade etmek isteyebilirsiniz. "Değil" demek yanlış ve yanıltıcıdır.
S.Lott

3
BTW Kısa bir astar itertools.takewhileve ve kullanılarak sarılabilir itertools.count. Yine de drangeperformans açısından daha iyi değil .
Kos

1
Yuvarlama hataları birikmeden bile bunu yapan bir jeneratörün uygulanmasının ne kadar kolay olduğu göz önüne alındığında, python'un aralığının buna izin vermemesi utanç vericidir. Heck, seqGNU coreutils'deki araç bile, seq 0 0.1 1yuvarlama hataları olmadan yapmanıza izin verir !
josch

3
@josch: seqC kullanır long doubleiçten türü ve olduğunu yuvarlama hataları tabi. Benim makinede Örneğin, seq 0 0.1 1verir 1(beklendiği gibi) onun son çıkış olarak değil seq 1 0.1 2verir 1.9(beklenen ziyade son çıkış olarak 2).
Mark Dickinson

Kolaylık sağlamak için, @ Kos'un önerisi (sizden sonra ) olarak itertools.takewhile(lambda x: (x+0.05)<1, itertools.count(0,0.1))veya uygulanabilir , ancak daha verimli olanı test etmedimitertools.islice(itertools.count(0,0.1), 10)import itertools
Anonim

Yanıtlar:


906

Doğrudan bir ondalık basamak kullanmak yerine, bunu kaç puan istediğinizi ifade etmek çok daha güvenlidir. Aksi takdirde, kayan nokta yuvarlama hatasının size yanlış bir sonuç vermesi olasıdır.

Sen kullanabilirsiniz linspace gelen işlevi NumPy (standart kütüphanenin parçası değildir ama elde etmek nispeten kolaydır) kütüphanesinde. linspacedöndürülecek birkaç nokta alır ve ayrıca doğru uç noktanın dahil edilip edilmeyeceğini belirlemenizi sağlar:

>>> np.linspace(0,1,11)
array([ 0. ,  0.1,  0.2,  0.3,  0.4,  0.5,  0.6,  0.7,  0.8,  0.9,  1. ])
>>> np.linspace(0,1,10,endpoint=False)
array([ 0. ,  0.1,  0.2,  0.3,  0.4,  0.5,  0.6,  0.7,  0.8,  0.9])

Gerçekten bir kayan nokta adım değeri kullanmak istiyorsanız, ile yapabilirsiniz numpy.arange.

>>> import numpy as np
>>> np.arange(0.0, 1.0, 0.1)
array([ 0. ,  0.1,  0.2,  0.3,  0.4,  0.5,  0.6,  0.7,  0.8,  0.9])

Kayan nokta yuvarlama hatası sorunlara neden olacaktır . Yuvarlama hatasının arangesadece 3 sayı üretmesi gerektiğinde bir length-4 dizisi üretmesine neden olduğu basit bir durum :

>>> numpy.arange(1, 1.3, 0.1)
array([1. , 1.1, 1.2, 1.3])

51
numpy, bu cevabın her yerde en çok 'pythonic' olduğunu düşündüğüm çok yaygın bir bileşen.
hava saldırısı

21
@AndreTerra Sorun @ numpy @ 'nin bir üçüncü taraf paketi olması ve bağımlılık yönetimi, depolama (paketin kendisi için) vb. Açısından çok fazla ek yük getirmesidir. o.
rbaleksandar

Affedersiniz, ama o zamandan beri son bölümde kayan nokta yuvarlama hatasını anlamadım np.linspace(1.,1.3,4)ve np.arange(1.,1.3,0.1)tam olarak aynı çıktıyı
verdim

4
@deadcode Bunun nedeni, np.arange öğesinin bir aralık [start,stop)(yani hariç stop) üretmek üzere tanımlanmış olmasıdır , bu nedenle 1.3'ün listeye dahil edilmesini beklemezsiniz. Neden hala dahil edildiğini ve buna karşı ne yapılacağını öğrenmek için bu soruya bakın .
dennis

5
Bir paketin ne kadar kullanıldığının tartışmalı olarak "Pythonic" olup olmadığının göstergesi değildir.
Alex Hall

213

Python'un range () öğesi yalnızca tamsayılar yapabilir, kayan nokta değil. Özel durumunuzda bunun yerine bir liste kavrama kullanabilirsiniz:

[x * 0.1 for x in range(0, 10)]

(Aralık aramasını bu ifadeyle değiştirin.)

Daha genel bir durum için, özel bir işlev veya jeneratör yazmak isteyebilirsiniz.


36
Daha da iyisi, Python 2.4+ ile çalışıyorsanız bir jeneratör kavrayışı kullanabilirsiniz. (x * 0.1 for x in range(0, 10)).
JAB

42
Daha da iyisi, x/10yerine koymak x * 0.1: D Aslında özel bir şey yok, ama orada bazı sayılar daha kesin olacak, örneğin 3*0.1sizin için olsun 0.30000000000000004, 3/10 için olsun 0.3:)
Bloke

4
3/10 bana 0,3 değil, 0 verir. 3 / 10.0, 0.29999999999999999 verir. Python 2.6.

19
@LarsWirzenius: Python 2.2+ sürümünde from __future__ import division; 3/100,3 döndürür. Bu davranış Python 3.x varsayılan değerdir.
Benjamin Hodgson

2
yuvarlak işlev de (0,10) aralığında x için lst = [yuvarlak (x * 0.10,2)] kullanılabilir
MARK

148

'Xrange ([start], stop [, step])' üzerine inşa ederek, seçtiğiniz herhangi bir türü kabul eden ve üreten bir jeneratör tanımlayabilirsiniz (destekleyici türlere sadık kalın+ ve <):

>>> def drange(start, stop, step):
...     r = start
...     while r < stop:
...         yield r
...         r += step
...         
>>> i0=drange(0.0, 1.0, 0.1)
>>> ["%g" % x for x in i0]
['0', '0.1', '0.2', '0.3', '0.4', '0.5', '0.6', '0.7', '0.8', '0.9', '1']
>>> 

45
Bunun yuvarlanma sorunları var. Lütfen buraya bakın: code.activestate.com/recipes/66472
Christian Oudard

Ben (r> stop) ve karşıt yön vermek için karşılık gelen bir r - = adım ile diğer yön için biraz uzatmak.
user318904

1
Yukarıda belirtilen şamandıra hassas sorunları olmadan bir xfrange işlevi yaptım. Check it out;) stackoverflow.com/questions/477486/…
Carlos Vega

1
Yuvarlama hataları biriktiriyorsunuz. Lütfen bunun yerine şunu kullanın: `i = 0; r = r <dururken başla: i + = 1; r = başlat + i * adım; verim r`
Cees Timmerman

1
Bu pythoncentral.io/pythons-range-function- açıklamalı (ve diğer Python dokümantasyon kaynaklarından)
Apostolos

31

iDöngünün büyüklüğünü artırın ve sonra ihtiyacınız olduğunda küçültün.

for i * 100 in range(0, 100, 10):
    print i / 100.0

EDIT: dürüstçe neden sözdizimsel olarak işe yaradığını düşündüğümü hatırlayamıyorum

for i in range(0, 11, 1):
    print i / 10.0

Bu istenen çıktıya sahip olmalıdır.


Bence range () tamsayılar çalışır, bu durumda en az aynı işlevi kullanarak, bu tek çözüm olurdu.
Matthew Scharley

1
@cmsjr creative: D Sadece küçük bir şey: Python 2.x kullanıyorsanız Python'un sonucu kesmesini önlemek için 100.0'a bölün. Sanırım 3.0'da kodladığınız gibi çalışacak.
Dana

2
for i * 100 in range(0, 100, 10)Hata: operatöre atayamazsınız
Anne van Rossum

25

scipyşamandıra taşıma gereksiniminizi karşılamak için arangePython'un range()yapıcısını genelleştiren yerleşik bir işleve sahiptir .

from scipy import arange


8
Bu aslında arangenumpy'de bulabileceğiniz tam olarak aynıdır : >>> import scipy >>> import numpy >>> numpy.arange is scipy.arangedönecektir True.
iFreilicht

from nump import arange as range
shrewmouse

24

NumPy biraz abartılı olduğunu düşünüyorum.

[p/10 for p in range(0, 10)]
[0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9]

Genellikle sisteminde adım yapmak, konuşma 1/xadede kadar yyapardın

x=100
y=2
[p/x for p in range(0, int(x*y))]
[0.0, 0.01, 0.02, 0.03, ..., 1.97, 1.98, 1.99]

( 1/xtest ettiğimde daha az yuvarlama sesi çıkardı).


18

R'nin seq fonksiyonuna benzer şekilde , bu, doğru adım değeri verilen herhangi bir sırayla bir dizi döndürür. Son değer, durdurma değerine eşittir.

def seq(start, stop, step=1):
    n = int(round((stop - start)/float(step)))
    if n > 1:
        return([start + step*i for i in range(n+1)])
    elif n == 1:
        return([start])
    else:
        return([])

Sonuçlar

seq(1, 5, 0.5)

[1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0]

seq(10, 0, -1)

[10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]

seq(10, 0, -2)

[10, 8, 6, 4, 2, 0]

seq(1, 1)

[1]


2
Bu, python'a çok fazla girmeden bir tane almak isteyen biri için harika bir cevaptır.
Chani

1
Neredeyse aradığım şey buydu - seq(0.5, 3.0)geri dönen not [0.5, 1.5, 2.5, 3.5]. Son girdileri dışı aralığında olmak önlemek için, yerine n = int(round(...ile n = int(floor(...çizgi ile from math import floorüst (yukarıda at def seq(...).
FriendFX

2
@FriendFX Bunu yapma! Eğer floorkullanılırsa, seq(0.2, 0.9, 0.1)doğru noktasına ulaşmak için başarısız olur ve dönecektir[0.2, 0.30000000000000004, 0.4, 0.5, 0.6000000000000001, 0.7, 0.8]
fdermishin

@ user502144: İyi yakaladın, teşekkürler. Sanırım genel tutmak için daha karmaşık çözümlerden birine razı olmalıyım.
FriendFX

14

Range () yerleşik işlevi bir tamsayı değerleri dizisi döndürür, korkarım, bu nedenle ondalık bir adım yapmak için kullanamazsınız.

Ben sadece bir while döngüsü kullanın söyleyebilirim:

i = 0.0
while i <= 1.0:
    print i
    i += 0.1

Merak ediyorsanız, Python 0,1'inizi 0'a dönüştürüyor, bu yüzden argümanın sıfır olamayacağını söylüyor.


2
Bunu yapma! .110 kez eklemek , eklemekle aynı şey değildir 1! docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html
kedi

12

İşte itertools kullanarak bir çözüm :

import itertools

def seq(start, end, step):
    if step == 0:
        raise ValueError("step must not be 0")
    sample_count = int(abs(end - start) / step)
    return itertools.islice(itertools.count(start, step), sample_count)

Kullanım Örneği:

for i in seq(0, 1, 0.1):
    print(i)

Tamlık uğruna, sample_count değişkeni için mutlak değeri hesaplamanız gerekir, böylece işleviniz negatif bir başlangıç ​​için de çalışır (yani -10'dan 10'a kadar)
Deleteman

10
[x * 0.1 for x in range(0, 10)] 

Python 2.7x'te size şu sonuçları verir:

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

ancak kullanırsanız:

[ round(x * 0.1, 1) for x in range(0, 10)]

size istediğinizi verir:

[0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9]



5

Bunu sık sık yaparsanız, oluşturulan listeyi kaydetmek isteyebilirsiniz r

r=map(lambda x: x/10.0,range(0,10))
for i in r:
    print i

5

more_itertoolsbir numeric_rangearacı uygulayan bir üçüncü taraf kütüphanesidir :

import more_itertools as mit


for x in mit.numeric_range(0, 1, 0.1):
    print("{:.1f}".format(x))

Çıktı

0.0
0.1
0.2
0.3
0.4
0.5
0.6
0.7
0.8
0.9

Bu araç ayrıca Decimalve için de çalışır Fraction.


4

Sürümlerim, vardiya için çarpımsal endeksler oluşturmak için orijinal aralık işlevini kullanır. Bu, orijinal aralık işleviyle aynı sözdizimine izin verir. Biri float, diğeri Decimal kullanarak iki versiyon yaptım, çünkü bazı durumlarda kayan nokta aritmetiğinin getirdiği yuvarlanma sapmasını önlemek istedim.

Aralık / x aralığı gibi boş küme sonuçlarıyla tutarlıdır.

Her iki işleve de yalnızca tek bir sayısal değer iletilmesi, standart aralık çıktısını giriş parametresinin tamsayı tavan değerine döndürür (bu nedenle 5.5 verdiyseniz, aralık (6) döndürür).

Düzenleme: aşağıdaki kod artık pypi'de paket olarak kullanılabilir: Franges

## frange.py
from math import ceil
# find best range function available to version (2.7.x / 3.x.x)
try:
    _xrange = xrange
except NameError:
    _xrange = range

def frange(start, stop = None, step = 1):
    """frange generates a set of floating point values over the 
    range [start, stop) with step size step

    frange([start,] stop [, step ])"""

    if stop is None:
        for x in _xrange(int(ceil(start))):
            yield x
    else:
        # create a generator expression for the index values
        indices = (i for i in _xrange(0, int((stop-start)/step)))  
        # yield results
        for i in indices:
            yield start + step*i

## drange.py
import decimal
from math import ceil
# find best range function available to version (2.7.x / 3.x.x)
try:
    _xrange = xrange
except NameError:
    _xrange = range

def drange(start, stop = None, step = 1, precision = None):
    """drange generates a set of Decimal values over the
    range [start, stop) with step size step

    drange([start,] stop, [step [,precision]])"""

    if stop is None:
        for x in _xrange(int(ceil(start))):
            yield x
    else:
        # find precision
        if precision is not None:
            decimal.getcontext().prec = precision
        # convert values to decimals
        start = decimal.Decimal(start)
        stop = decimal.Decimal(stop)
        step = decimal.Decimal(step)
        # create a generator expression for the index values
        indices = (
            i for i in _xrange(
                0, 
                ((stop-start)/step).to_integral_value()
            )
        )  
        # yield results
        for i in indices:
            yield float(start + step*i)

## testranges.py
import frange
import drange
list(frange.frange(0, 2, 0.5)) # [0.0, 0.5, 1.0, 1.5]
list(drange.drange(0, 2, 0.5, precision = 6)) # [0.0, 0.5, 1.0, 1.5]
list(frange.frange(3)) # [0, 1, 2]
list(frange.frange(3.5)) # [0, 1, 2, 3]
list(frange.frange(0,10, -1)) # []

frangeStop ise nasıl çalışabilir None? Kodun bu kısmı artık adım boyutunu dikkate almıyor.
josch

1
@josch'un rangeiki imzası vardır: range(stop)varsayılan olarak kabul edilen start=0, step=1ve range(start, stop, step)hiçbir varsayım yapılmayan. frangebunu yansıtır. range(stop)İmzayı kullanırken , her ikisi de 0 frangeile drangebaşlayın ve 1 ile artırın, bu nedenle davranışları range(stop)en yakın tamsayıya yuvarlanan durma ile normal davranışla aynıdır .
Nisan.H

4

Şamandıra basamakları ile aralıkları elde etmek için bu benim çözümüm.
Bu işlevi kullanarak numpy'yi içe aktarmaya veya yüklemeye gerek yoktur.
Geliştirilebileceğinden ve optimize edileceğinden eminim. Bunu yapmaktan ve buraya göndermekten çekinmeyin.

from __future__ import division
from math import log

def xfrange(start, stop, step):

    old_start = start #backup this value

    digits = int(round(log(10000, 10)))+1 #get number of digits
    magnitude = 10**digits
    stop = int(magnitude * stop) #convert from 
    step = int(magnitude * step) #0.1 to 10 (e.g.)

    if start == 0:
        start = 10**(digits-1)
    else:
        start = 10**(digits)*start

    data = []   #create array

    #calc number of iterations
    end_loop = int((stop-start)//step)
    if old_start == 0:
        end_loop += 1

    acc = start

    for i in xrange(0, end_loop):
        data.append(acc/magnitude)
        acc += step

    return data

print xfrange(1, 2.1, 0.1)
print xfrange(0, 1.1, 0.1)
print xfrange(-1, 0.1, 0.1)

Çıktı:

[1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0]
[0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1]
[-1.0, -0.9, -0.8, -0.7, -0.6, -0.5, -0.4, -0.3, -0.2, -0.1, 0.0]

1
Durdurma değerinin 1 adımındaysa, son değeri kaçırmayla ilgili bir hata var. yani xfrange (1,10,2) yalnızca 1,3,5,7 yapar, 9 eksik
Lobe

Referans ve diğer okuyucular için lütfen bu uygulamayı bu stackoverflow.com/a/477610/54964 ile karşılaştırın . Bunun büyük float problemleri yok gibi görünüyor.
Léo Léopold Hertz 준영

@carlosvega Lobe'un sonucunu neden aldığını doğrulayabilir misiniz?
Léo Léopold Hertz 준영

3

Butikin eksiksiz olması için fonksiyonel bir çözüm:

def frange(a,b,s):
  return [] if s > 0 and a > b or s < 0 and a < b or s==0 else [a]+frange(a+s,b,s)

2

Bu işlevi kullanabilirsiniz:

def frange(start,end,step):
    return map(lambda x: x*step, range(int(start*1./step),int(end*1./step)))

Doğru çalışmıyor gibi, örneğinlist(frange(99.8, 100.1, 0.1)) => [99.7, 99.80000000000001, 99.9]
Shai Coleman

2

Hile önlemek için yuvarlama sorunu , hareketi aralığı boyunca ayrı numara kullanmak olduğunu başlar ve yarım adım öncesinde başlangıcı .

# floating point range
def frange(a, b, stp=1.0):
  i = a+stp/2.0
  while i<b:
    yield a
    a += stp
    i += stp

Alternatif numpy.arangeolarak kullanılabilir.


2

Numpy kütüphanesi kullanılarak yapılabilir. arange () işlevi şamandıradaki adımlara izin verir. Ancak, kolaylık olması için tolist () kullanılarak listeye dönüştürülebilen bir numpy dizisi döndürür.

for i in np.arange(0, 1, 0.1).tolist():
   print i

2

Cevabım numPy'ye ihtiyaç duymadan ve lambda kullanmadan map () kullanan diğerlerine benziyor. Dt adımlarında 0,0 ile t_max arasında kayan noktalı değerlerin bir listesini almak için:

def xdt(n):
    return dt*float(n)
tlist  = map(xdt, range(int(t_max/dt)+1))

2

Şaşırtıcı kimse Python 3 belgelerinde önerilen çözümden henüz bahsetmedi :

Ayrıca bakınız:

  • Linspace tarifi noktası uygulamaları yüzen o kadar uygun aralığın tembel versiyonunu nasıl uygulanacağı gösterilmektedir.

Bir kez tanımlandığında, tarifin kullanımı kolaydır ve numpyherhangi bir harici kütüphane gerektirmez , ancak gibi işlev görür numpy.linspace(). stepÜçüncü numbağımsız değişkenin, bağımsız değişken yerine istenen değerlerin sayısını belirttiğini unutmayın, örneğin:

print(linspace(0, 10, 5))
# linspace(0, 10, 5)
print(list(linspace(0, 10, 5)))
# [0.0, 2.5, 5.0, 7.5, 10]

Andrew Barnert'ın tam Python 3 tarifinin değiştirilmiş bir versiyonunu aşağıda belirtiyorum:

import collections.abc
import numbers

class linspace(collections.abc.Sequence):
    """linspace(start, stop, num) -> linspace object

    Return a virtual sequence of num numbers from start to stop (inclusive).

    If you need a half-open range, use linspace(start, stop, num+1)[:-1].
    """
    def __init__(self, start, stop, num):
        if not isinstance(num, numbers.Integral) or num <= 1:
            raise ValueError('num must be an integer > 1')
        self.start, self.stop, self.num = start, stop, num
        self.step = (stop-start)/(num-1)
    def __len__(self):
        return self.num
    def __getitem__(self, i):
        if isinstance(i, slice):
            return [self[x] for x in range(*i.indices(len(self)))]
        if i < 0:
            i = self.num + i
        if i >= self.num:
            raise IndexError('linspace object index out of range')
        if i == self.num-1:
            return self.stop
        return self.start + i*self.step
    def __repr__(self):
        return '{}({}, {}, {})'.format(type(self).__name__,
                                       self.start, self.stop, self.num)
    def __eq__(self, other):
        if not isinstance(other, linspace):
            return False
        return ((self.start, self.stop, self.num) ==
                (other.start, other.stop, other.num))
    def __ne__(self, other):
        return not self==other
    def __hash__(self):
        return hash((type(self), self.start, self.stop, self.num))

2

Şamandıra hassasiyeti sorunlarına karşı koymak için Decimalmodülü kullanabilirsiniz .

Bu dönüşümün bir ekstra çaba gerektirir Decimalgelen intveya floatkod yazarken, ancak bunun yerine geçebilir strve rahatlık bu tür gerçekten gerekli olup olmadığını işlevini değiştirin.

from decimal import Decimal
from decimal import Decimal as D


def decimal_range(*args):

    zero, one = Decimal('0'), Decimal('1')

    if len(args) == 1:
        start, stop, step = zero, args[0], one
    elif len(args) == 2:
        start, stop, step = args + (one,)
    elif len(args) == 3:
        start, stop, step = args
    else:
        raise ValueError('Expected 1 or 2 arguments, got %s' % len(args))

    if not all([type(arg) == Decimal for arg in (start, stop, step)]):
        raise ValueError('Arguments must be passed as <type: Decimal>')

    # neglect bad cases
    if (start == stop) or (start > stop and step >= zero) or \
                          (start < stop and step <= zero):
        return []

    current = start
    while abs(current) < abs(stop):
        yield current
        current += step

Örnek çıktılar -

list(decimal_range(D('2')))
# [Decimal('0'), Decimal('1')]
list(decimal_range(D('2'), D('4.5')))
# [Decimal('2'), Decimal('3'), Decimal('4')]
list(decimal_range(D('2'), D('4.5'), D('0.5')))
# [Decimal('2'), Decimal('2.5'), Decimal('3.0'), Decimal('3.5'), Decimal('4.0')]
list(decimal_range(D('2'), D('4.5'), D('-0.5')))
# []
list(decimal_range(D('2'), D('-4.5'), D('-0.5')))
# [Decimal('2'),
#  Decimal('1.5'),
#  Decimal('1.0'),
#  Decimal('0.5'),
#  Decimal('0.0'),
#  Decimal('-0.5'),
#  Decimal('-1.0'),
#  Decimal('-1.5'),
#  Decimal('-2.0'),
#  Decimal('-2.5'),
#  Decimal('-3.0'),
#  Decimal('-3.5'),
#  Decimal('-4.0')]

2
Benzer Decimalgirişlerle np.arangeaynı çalışır:np.arange(Decimal('-2.0'), Decimal('2.0'), Decimal('0.1'))
hpaulj

2
Evet, teşekkürler. Bununla birlikte, bunun harici (numpy) bir lib'e ihtiyacı olacaktır.
shad0w_wa1k3r

1

Adımda yanlış oturum açma olasılığı için otomatik düzeltme ekleyin:

def frange(start,step,stop):
    step *= 2*((stop>start)^(step<0))-1
    return [start+i*step for i in range(int((stop-start)/step))]

1

Çözümüm:

def seq(start, stop, step=1, digit=0):
    x = float(start)
    v = []
    while x <= stop:
        v.append(round(x,digit))
        x += step
    return v

1

En İyi Çözüm: yuvarlama hatası yok
_________________________________________________________________________________

>>> step = .1
>>> N = 10     # number of data points
>>> [ x / pow(step, -1) for x in range(0, N + 1) ]

[0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0]

_________________________________________________________________________________

Veya ayarlanmış veri noktaları (örneğin sürekli işlev) yerine belirli bir aralık için şunları kullanın:

>>> step = .1
>>> rnge = 1     # NOTE range = 1, i.e. span of data points
>>> N = int(rnge / step
>>> [ x / pow(step,-1) for x in range(0, N + 1) ]

[0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0]

Bir fonksiyonu uygulamak için: değiştirmek x / pow(step, -1)ile f( x / pow(step, -1) )ve tanımlar f.
Örneğin:

>>> import math
>>> def f(x):
        return math.sin(x)

>>> step = .1
>>> rnge = 1     # NOTE range = 1, i.e. span of data points
>>> N = int(rnge / step)
>>> [ f( x / pow(step,-1) ) for x in range(0, N + 1) ]

[0.0, 0.09983341664682815, 0.19866933079506122, 0.29552020666133955, 0.3894183423086505, 
 0.479425538604203, 0.5646424733950354, 0.644217687237691, 0.7173560908995228,
 0.7833269096274834, 0.8414709848078965]

1

start ve stop, biri veya diğeri yerine kapsayıcıdır (genellikle durdurma hariç tutulur) ve ithalat olmadan ve jeneratörleri kullanma

def rangef(start, stop, step, fround=5):
    """
    Yields sequence of numbers from start (inclusive) to stop (inclusive)
    by step (increment) with rounding set to n digits.

    :param start: start of sequence
    :param stop: end of sequence
    :param step: int or float increment (e.g. 1 or 0.001)
    :param fround: float rounding, n decimal places
    :return:
    """
    try:
        i = 0
        while stop >= start and step > 0:
            if i==0:
                yield start
            elif start >= stop:
                yield stop
            elif start < stop:
                if start == 0:
                    yield 0
                if start != 0:
                    yield start
            i += 1
            start += step
            start = round(start, fround)
        else:
            pass
    except TypeError as e:
        yield "type-error({})".format(e)
    else:
        pass


# passing
print(list(rangef(-100.0,10.0,1)))
print(list(rangef(-100,0,0.5)))
print(list(rangef(-1,1,0.2)))
print(list(rangef(-1,1,0.1)))
print(list(rangef(-1,1,0.05)))
print(list(rangef(-1,1,0.02)))
print(list(rangef(-1,1,0.01)))
print(list(rangef(-1,1,0.005)))
# failing: type-error:
print(list(rangef("1","10","1")))
print(list(rangef(1,10,"1")))

Python 3.6.2 (v3.6.2: 5fd33b5, 8 Tem 2017, 04:57:36) [MSC v.1900 64 bit (AMD64)]


1

Burada partiye geç kaldığımı biliyorum, ama burada 3.6'da çalışan önemsiz bir jeneratör çözümü var:

def floatRange(*args):
    start, step = 0, 1
    if len(args) == 1:
        stop = args[0]
    elif len(args) == 2:
        start, stop = args[0], args[1]
    elif len(args) == 3:
        start, stop, step = args[0], args[1], args[2]
    else:
        raise TypeError("floatRange accepts 1, 2, or 3 arguments. ({0} given)".format(len(args)))
    for num in start, step, stop:
        if not isinstance(num, (int, float)):
            raise TypeError("floatRange only accepts float and integer arguments. ({0} : {1} given)".format(type(num), str(num)))
    for x in range(int((stop-start)/step)):
        yield start + (x * step)
    return

o zaman orijinali gibi arayabilirsiniz range()... hiçbir hata işleme yoktur, ancak makul bir şekilde yakalanabilecek bir hata olup olmadığını bana bildirin ve güncelleyeceğim. veya güncelleyebilirsiniz. bu StackOverflow.


0

İşte float_range (-1, 0, 0.01) ile iyi çalışan ve kayan nokta gösterim hataları olmadan çalışan benim çözüm. Çok hızlı değil, ama iyi çalışıyor:

from decimal import Decimal

def get_multiplier(_from, _to, step):
    digits = []
    for number in [_from, _to, step]:
        pre = Decimal(str(number)) % 1
        digit = len(str(pre)) - 2
        digits.append(digit)
    max_digits = max(digits)
    return float(10 ** (max_digits))


def float_range(_from, _to, step, include=False):
    """Generates a range list of floating point values over the Range [start, stop]
       with step size step
       include=True - allows to include right value to if possible
       !! Works fine with floating point representation !!
    """
    mult = get_multiplier(_from, _to, step)
    # print mult
    int_from = int(round(_from * mult))
    int_to = int(round(_to * mult))
    int_step = int(round(step * mult))
    # print int_from,int_to,int_step
    if include:
        result = range(int_from, int_to + int_step, int_step)
        result = [r for r in result if r <= int_to]
    else:
        result = range(int_from, int_to, int_step)
    # print result
    float_result = [r / mult for r in result]
    return float_result


print float_range(-1, 0, 0.01,include=False)

assert float_range(1.01, 2.06, 5.05 % 1, True) ==\
[1.01, 1.06, 1.11, 1.16, 1.21, 1.26, 1.31, 1.36, 1.41, 1.46, 1.51, 1.56, 1.61, 1.66, 1.71, 1.76, 1.81, 1.86, 1.91, 1.96, 2.01, 2.06]

assert float_range(1.01, 2.06, 5.05 % 1, False)==\
[1.01, 1.06, 1.11, 1.16, 1.21, 1.26, 1.31, 1.36, 1.41, 1.46, 1.51, 1.56, 1.61, 1.66, 1.71, 1.76, 1.81, 1.86, 1.91, 1.96, 2.01]

0

Ben sadece bir acemiyim, ama bazı hesaplamaları simüle ederken de aynı problemi yaşadım. İşte bunu çözmeye çalıştım, ondalık basamaklarla çalışıyor gibi görünüyor.

Ayrıca oldukça tembelim ve bu yüzden kendi menzil fonksiyonumu yazmakta zorlandım.

Temelde yaptığım şey benim xrange(0.0, 1.0, 0.01)için değiştirildi xrange(0, 100, 1)ve bölümü 100.0döngü içinde kullandı. Yuvarlama hataları olacaksa ben de endişeliydim. Bu yüzden, var olup olmadığını test etmeye karar verdim. Şimdi duydum ki, örneğin 0.01bir hesaplamadan tam olarak şamandıra değilse0.01 onları karşılaştıran değilse Yanlış döndürmelidir (eğer yanılıyorsam, lütfen bana bildirin).

Bu yüzden kısa bir test yaparak çözümümün menzil için çalışıp çalışmayacağını test etmeye karar verdim:

for d100 in xrange(0, 100, 1):
    d = d100 / 100.0
    fl = float("0.00"[:4 - len(str(d100))] + str(d100))
    print d, "=", fl , d == fl

Ve her biri için True yazdı.

Şimdi, tamamen yanlış anlıyorsam, lütfen bana bildirin.


0

Bu bir astar kodunuzu karıştırmaz. Step parametresinin işareti önemlidir.

def frange(start, stop, step):
    return [x*step+start for x in range(0,round(abs((stop-start)/step)+0.5001),
        int((stop-start)/step<0)*-2+1)]
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.