Apakah ada yang range()
setara untuk mengapung di 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
range(5, 50, 5)
Jawaban:
Saya tidak tahu fungsi bawaan, tetapi menulis yang seperti ini seharusnya tidak terlalu rumit.Seperti yang disebutkan dalam komentar, ini dapat menghasilkan hasil yang tidak terduga seperti:
Untuk mendapatkan hasil yang diharapkan, Anda dapat menggunakan salah satu jawaban lain dalam pertanyaan ini, atau seperti yang disebutkan @Tadhg, Anda dapat menggunakan
decimal.Decimal
sebagaijump
argumen. Pastikan untuk menginisialisasi dengan string daripada float.Atau bahkan:
Lalu:
sumber
>>> print list(frange(0,100,0.1))[-1]==100.0
akanFalse
frange
dapat bekerja secara tidak terduga. Karena kutukan floating point arithmetics , misalnyafrange(0.0, 1.0, 0.1)
menghasilkan 11 nilai, di mana nilai terakhir adalah0.9999999999999999
. Peningkatan praktis akan terjadiwhile x + sys.float_info.epsilon < y:
walaupun ini mungkin bisa gagal dengan jumlah besar .decimal.Decimal
sebagai langkah alih-alih mengapung.Anda dapat menggunakan:
atau gunakan lambda / peta:
sumber
arange(0.5, 5, 1.5)
IMO lebih mudah dibaca.list(frange(0, 1, 0.5))
, itu berfungsi dengan baik dan 1 dikecualikan, tetapi jika Anda mencobalist(frange(0, 1, 0.1))
, nilai terakhir yang Anda dapatkan dekat dengan 1,0, yang mungkin bukan yang Anda inginkan. Solusi yang disajikan di sini tidak memiliki masalah ini.Saya dulu menggunakan
numpy.arange
tetapi memiliki beberapa komplikasi mengendalikan jumlah elemen yang dikembalikan, karena kesalahan floating point. Jadi sekarang saya gunakanlinspace
, misalnya:sumber
decimal
, misalnya:np.linspace(-.1,10,num=5050)[0]
np.linspace(-.1,10,num=5050)[0] == -.1
itu Benar. Hanya sajarepr(np.float64('-0.1'))
menunjukkan angka lebih banyak.print(numpy.linspace(0, 3, 148)[49])
mencetak0.9999999999999999
ketika hasil yang ideal adalah1.0
.linspace
melakukan pekerjaan yang jauh lebih baik daripadaarange
, tetapi tidak dijamin untuk menghasilkan kesalahan pembulatan seminimal mungkin.Pylab memiliki
frange
(pembungkus, sebenarnya, untukmatplotlib.mlab.frange
):sumber
Dievaluasi dengan penuh semangat (2.x
range
):Dievaluasi dengan sederhana (2.x
xrange
, 3.xrange
):Bergantian:
sumber
(x * .5 for x in range(10))
sebagai ekspresi generator untuk evaluasi malas?menggunakan
itertools
: rentang floating point yang dievaluasi dengan malas:sumber
itertools.takewhile
. Namun,itertools.count(start, step)
menderita akumulasi kesalahan floating-point. (Evaluatetakewhile(lambda x: x < 100, count(0, 0.1))
misalnya.) Saya akan menulistakewhile(lambda x: x < stop, (start + i * step for i in count()))
sebagai gantinya.Saya membantu menambahkan fungsi numeric_range ke paket more-itertools .
more_itertools.numeric_range(start, stop, step)
bertindak seperti rentang fungsi bawaan tetapi dapat menangani tipe mengapung, Desimal, dan Fraksi.sumber
Tidak ada fungsi bawaan seperti itu, tetapi Anda dapat menggunakan yang berikut (kode Python 3) untuk melakukan pekerjaan seaman Python memungkinkan Anda untuk melakukannya.
Anda dapat memverifikasi semua itu dengan menjalankan beberapa pernyataan:
Kode tersedia di GitHub
sumber
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 bahwarange()
fungsi tersebut sering digunakan sebagai indeks (dan tentu saja, itu berarti accessor ) generator. Jadi, ketika kita meneleponrange(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: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.
Demikian pula, kita juga dapat menggunakan
round
fungsi bawaan dan menentukan jumlah desimal:Perbandingan & Kinerja Cepat
Tentu saja, mengingat pembahasan di atas, fungsi-fungsi ini memiliki kasus penggunaan yang cukup terbatas. Meskipun demikian, inilah perbandingan cepat:
Hasilnya identik untuk masing-masing:
Dan beberapa timing:
Sepertinya metode pemformatan string menang dengan rambut di sistem saya.
Keterbatasan
Dan akhirnya, demonstrasi poin dari diskusi di atas dan satu batasan terakhir:
Lebih lanjut, ketika
skip
parameter tidak dapat dibagi denganstop
nilai, mungkin ada kesenjangan menguap mengingat masalah yang terakhir:Ada beberapa cara untuk mengatasi masalah ini, tetapi pada akhirnya, pendekatan terbaik mungkin hanya menggunakan Numpy.
sumber
Sebuah solusi tanpa ketergantungan numpy dll disediakan oleh kichik tetapi karena aritmatika floating point , sering berperilaku tak terduga. Seperti dicatat oleh saya dan blubberdiblub , elemen tambahan dengan mudah menyelinap ke hasilnya. Misalnya
naive_frange(0.0, 1.0, 0.1)
akan menghasilkan0.999...
sebagai nilai terakhirnya dan dengan demikian menghasilkan 11 nilai secara total.Versi yang kuat disediakan di sini:
Karena perkalian, kesalahan pembulatan tidak menumpuk. Penggunaan
epsilon
mengurus kemungkinan kesalahan pembulatan perkalian, meskipun masalah tentu saja bisa muncul di ujung yang sangat kecil dan sangat besar. Sekarang, seperti yang diharapkan:Dan dengan angka yang agak besar:
Kode ini juga tersedia sebagai GitHub Gist .
sumber
Versi perpustakaan-kurang sederhana
Ah, sial - Saya akan melemparkan dalam versi perpustakaan-kurang sederhana. Jangan ragu untuk memperbaikinya [*]:
Gagasan intinya adalah
nsteps
jumlah langkah untuk membuat Anda mulai dan berhentirange(nsteps)
selalu mengeluarkan bilangan bulat sehingga tidak ada kehilangan keakuratan. Langkah terakhir adalah memetakan [0..nsteps] secara linear ke [start..stop].sunting
Jika, seperti alancalvitti Anda ingin seri memiliki representasi rasional yang tepat, Anda selalu dapat menggunakan Fraksi :
[*] Secara khusus,
frange()
mengembalikan daftar, bukan generator. Tetapi itu sudah cukup untuk kebutuhan saya.sumber
frange(0,1.1,0.1)
dan bahkan lebih banyak lagi dengan pilihan sepertifrange(0,1.05,0.1)
Catatan 1: Dari diskusi di bagian komentar di sini, "jangan pernah gunakan
numpy.arange()
(dokumentasi numpy sendiri merekomendasikannya). Gunakan numpy.linspace seperti yang direkomendasikan oleh wim, atau salah satu saran lain dalam jawaban ini"Catatan 2: Saya telah membaca diskusi dalam beberapa komentar di sini, tetapi setelah kembali ke pertanyaan ini untuk ketiga kalinya sekarang, saya merasa informasi ini harus ditempatkan pada posisi yang lebih mudah dibaca.
sumber
Seperti yang ditulis kichik , ini seharusnya tidak terlalu rumit. Namun kode ini:
Tidak pantas karena efek kumulatif kesalahan saat bekerja dengan float. Itu sebabnya Anda menerima sesuatu seperti:
Sedangkan perilaku yang diharapkan adalah:
Solusi 1
Kesalahan kumulatif hanya dapat dikurangi dengan menggunakan variabel indeks. Inilah contohnya:
Contoh ini berfungsi seperti yang diharapkan.
Solusi 2
Tidak ada fungsi bersarang. Hanya sementara dan variabel penghitung:
Fungsi ini akan bekerja dengan baik juga, kecuali untuk kasus ketika Anda ingin rentang terbalik. Misalnya:
Solusi 1 dalam hal ini akan berfungsi seperti yang diharapkan. Agar fungsi ini berfungsi dalam situasi seperti itu, Anda harus menerapkan peretasan, mirip dengan yang berikut:
Dengan peretasan ini, Anda dapat menggunakan fungsi-fungsi ini dengan langkah-langkah negatif:
Solusi 3
Anda dapat melangkah lebih jauh dengan pustaka standar biasa dan menyusun fungsi rentang untuk sebagian besar tipe numerik:
Generator ini diadaptasi dari buku Fluent Python (Bab 14. Iterables, Iterators, dan generator). Ini tidak akan bekerja dengan rentang yang menurun. Anda harus menerapkan peretasan, seperti pada solusi sebelumnya.
Anda dapat menggunakan generator ini sebagai berikut, misalnya:
Dan tentu saja Anda bisa menggunakannya dengan float dan int juga.
Hati-hati
Jika Anda ingin menggunakan fungsi-fungsi ini dengan langkah-langkah negatif, Anda harus menambahkan tanda centang untuk tanda langkah, misalnya:
Opsi terbaik di sini adalah menaikkan
StopIteration
, jika Anda ingin menirurange
fungsi itu sendiri.Rentang Mimic
Jika Anda ingin meniru
range
antarmuka fungsi, Anda dapat memberikan beberapa pemeriksaan argumen:Saya pikir, Anda ada benarnya. Anda bisa menggunakan salah satu dari fungsi-fungsi ini (kecuali yang pertama) dan semua yang Anda butuhkan adalah pustaka standar python.
sumber
saya menulis sebuah fungsi yang mengembalikan tuple dari berbagai angka floating point presisi ganda tanpa tempat desimal di luar seratus. itu hanya masalah penguraian nilai rentang seperti string dan memisahkan kelebihannya. Saya menggunakannya untuk menampilkan rentang untuk dipilih dari dalam UI. Saya harap orang lain merasakan manfaatnya.
sumber
Pemakaian
Untuk membulatkan setiap langkah ke N tempat desimal
Kode
Mengapa memilih jawaban ini?
np.linspace
untung-untungan, mereka mungkin atau mungkin tidak bekerja karena kesulitan dalam memilih jumlah divisi yang benar.np.linspace
benar-benar berjuang dengan peningkatan desimal 0,1, dan urutan pembagian dalam rumus untuk mengubah kenaikan menjadi beberapa pemisahan dapat menghasilkan kode yang benar atau rusak.np.arange
sudah usang.Jika ragu, coba empat test case di atas.
sumber
Harap perhatikan huruf Range pertama adalah modal. Metode penamaan ini tidak dianjurkan untuk fungsi dalam Python. Anda dapat mengubah Rentang ke sesuatu seperti drange atau frange jika Anda mau. Fungsi "Rentang" berperilaku seperti yang Anda inginkan. Anda dapat memeriksa manualnya di sini [ http://reference.wolfram.com/language/ref/Range.html ].
sumber
Saya pikir ada jawaban yang sangat sederhana yang benar-benar mengemulasi semua fitur range tetapi untuk float dan integer. Dalam solusi ini, Anda hanya mengira bahwa perkiraan Anda secara default adalah 1e-7 (atau yang Anda pilih) dan Anda dapat mengubahnya ketika Anda memanggil fungsi.
sumber
Tentu saja akan ada beberapa kesalahan pembulatan, jadi ini tidak sempurna, tetapi ini adalah apa yang saya gunakan secara umum untuk aplikasi, yang tidak memerlukan presisi tinggi. Jika Anda ingin menjadikan ini lebih akurat, Anda bisa menambahkan argumen tambahan untuk menentukan cara menangani kesalahan pembulatan. Mungkin lewat fungsi pembulatan mungkin membuat ini dapat diperluas dan memungkinkan programmer untuk menentukan cara menangani kesalahan pembulatan.
Jika saya menulis:
Ini akan menampilkan:
sumber
Apakah ada rentang () yang setara untuk mengapung di Python? TIDAK Gunakan ini:
sumber
f_range(0.01,0.02,0.001)
... Untuk sebagian besar tujuan praktis,arange
dari Numpy adalah solusi yang sederhana, aman dan cepat.Ada beberapa jawaban di sini yang tidak menangani kasus tepi sederhana seperti langkah negatif, mulai salah, berhenti dll. Berikut adalah versi yang menangani banyak kasus ini dengan benar memberikan perilaku yang sama seperti asli
range()
:Perhatikan bahwa ini akan membuat kesalahan langkah = 0 seperti yang asli
range
. Satu perbedaan adalah bahwa rentang asli mengembalikan objek yang dapat diindeks dan dapat dibalik sementara di atas tidak.Anda dapat bermain dengan kode ini dan menguji kasus di sini.
sumber