Standart Kütüphanede Neden Kayan Nokta Aralığı Uygulaması Yok?
Buradaki tüm gönderiler tarafından açıkça belirtildiği gibi, kayan nokta sürümü yoktur range(). Bununla birlikte, range()işlevin genellikle bir dizin (ve tabii ki bu bir erişimci anlamına gelir ) üreticisi olarak kullanıldığını düşünürsek, ihmal mantıklıdır . Yani, dediğimizde range(0,40), 0'dan 40'a kadar olan ancak 40'ın kendisini içermeyen 40 değer istediğimizi söyleriz.
Endeks üretiminin değerleri kadar endeks sayısıyla ilgili olduğunu düşündüğümüzde range(), standart kütüphanede şamandıra uygulamasının kullanımı daha az mantıklıdır. Örneğin, işlevi çağırırsak frange(0, 10, 0.25), hem 0 hem de 10'un dahil edilmesini beklerdik, ancak bu 41 değere sahip bir vektör verir.
Böylece, frange() kullanımına bağlı işlev her zaman karşı sezgisel davranış sergileyecektir; ya indeksleme perspektifinden algılanan çok fazla değere sahiptir ya da matematiksel perspektiften döndürülmesi gereken bir sayıyı içermez.
Matematiksel Kullanım Örneği
Bununla birlikte, tartışıldığı gibi numpy.linspace(), nesli matematiksel bakış açısıyla güzel bir şekilde gerçekleştirir:
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.
])
Dizin Oluşturma Kullanım Örneği
Ve indeksleme perspektifi için, ondalık basamak sayısını belirtmemize izin veren bazı hileli dize büyüsü ile biraz farklı bir yaklaşım yazdım.
# 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))
Benzer şekilde, yerleşik roundişlevi de kullanabilir ve ondalık sayısını belirleyebiliriz:
# 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)
Hızlı Karşılaştırma ve Performans
Tabii ki, yukarıdaki tartışma göz önüne alındığında, bu işlevlerin oldukça sınırlı bir kullanım durumu vardır. Yine de, hızlı bir karşılaştırma:
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)
Sonuçlar her biri için aynıdır:
-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
Ve bazı zamanlamalar:
>>> 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
Dize biçimlendirme yönteminin sistemimdeki bir saç tarafından kazanıldığı anlaşılıyor.
Sınırlamalar
Ve son olarak, yukarıdaki tartışmadaki noktanın bir gösterimi ve son bir sınırlama:
# "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
Ayrıca, skipparametre stopdeğere bölünemezse , ikinci sorun göz önüne alındığında esneme boşluğu olabilir:
# 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
Bu sorunu ele almanın yolları var, ancak günün sonunda en iyi yaklaşım muhtemelen sadece Numpy'yi kullanmak olacaktır.