Mengapa Tidak Ada Implementasi Floating Point Range di Perpustakaan Standar?
Sebagaimana dijelaskan oleh semua posting di sini, tidak ada versi floating point dari range()
. Yang mengatakan, kelalaian masuk akal jika kita menganggap bahwa range()
fungsi tersebut sering digunakan sebagai indeks (dan tentu saja, itu berarti accessor ) generator. Jadi, ketika kita menelepon range(0,40)
, kita sebenarnya mengatakan kita ingin 40 nilai mulai dari 0, hingga 40, tetapi tidak termasuk 40 itu sendiri.
Ketika kami menganggap bahwa pembuatan indeks sama banyaknya dengan jumlah indeks sebagaimana nilainya, penggunaan implementasi float range()
di perpustakaan standar kurang masuk akal. Misalnya, jika kita memanggil fungsifrange(0, 10, 0.25)
, kita akan mengharapkan 0 dan 10 untuk dimasukkan, tetapi itu akan menghasilkan vektor dengan 41 nilai.
Dengan demikian, suatu frange()
fungsi tergantung pada penggunaannya akan selalu menunjukkan perilaku kontra intuitif; itu baik memiliki nilai terlalu banyak yang dirasakan dari perspektif pengindeksan atau tidak termasuk nomor yang wajar harus dikembalikan dari perspektif matematika.
Kasus Penggunaan Matematika
Dengan itu, seperti yang dibahas, numpy.linspace()
melakukan generasi dengan perspektif matematika dengan baik:
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.
])
Kotak Penggunaan Pengindeksan
Dan untuk perspektif pengindeksan, saya telah menulis pendekatan yang sedikit berbeda dengan beberapa trik sulap yang memungkinkan kita menentukan jumlah tempat desimal.
# 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))
Demikian pula, kita juga dapat menggunakan round
fungsi bawaan dan menentukan jumlah desimal:
# 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)
Perbandingan & Kinerja Cepat
Tentu saja, mengingat pembahasan di atas, fungsi-fungsi ini memiliki kasus penggunaan yang cukup terbatas. Meskipun demikian, inilah perbandingan cepat:
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)
Hasilnya identik untuk masing-masing:
-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
Dan beberapa timing:
>>> 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
Sepertinya metode pemformatan string menang dengan rambut di sistem saya.
Keterbatasan
Dan akhirnya, demonstrasi poin dari diskusi di atas dan satu batasan terakhir:
# "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
Lebih lanjut, ketika skip
parameter tidak dapat dibagi dengan stop
nilai, mungkin ada kesenjangan menguap mengingat masalah yang terakhir:
# 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
Ada beberapa cara untuk mengatasi masalah ini, tetapi pada akhirnya, pendekatan terbaik mungkin hanya menggunakan Numpy.