Saya membayangkan ini adalah pertanyaan presisi floating point klasik, tapi saya mencoba untuk membungkus kepala saya di sekitar hasil ini, berjalan 1//0.01
dengan hasil Python 3.7.5 99
.
Saya membayangkan ini adalah hasil yang diharapkan, tetapi apakah ada cara untuk memutuskan kapan lebih aman untuk digunakan int(1/f)
daripada 1//f
?
round()
dan tidak pernah//
atauint()
. Pertanyaan terkait adalah tentang perbandingan float tidak ada hubungannya dengan pemotongan dan tidak ada perbaikan yang mudah.Jawaban:
Jika ini adalah pembagian dengan bilangan real,
1//0.01
akan menjadi tepat 100. Karena mereka adalah perkiraan floating-point,0.01
sedikit lebih besar dari 1/100, berarti hasil bagi itu sedikit lebih kecil dari 100. Nilai 99 ini. Nilai tertentu yang kemudian dipasangkan ke 99.sumber
Alasan untuk hasil ini seperti yang Anda sebutkan, dan dijelaskan dalam Apakah matematika floating point rusak? dan banyak tanya jawab serupa lainnya.
Saat Anda mengetahui jumlah desimal pembilang dan penyebut, cara yang lebih andal adalah mengalikan angka-angka itu terlebih dahulu sehingga mereka dapat diperlakukan sebagai bilangan bulat, dan kemudian melakukan pembagian bilangan bulat di atasnya:
Jadi dalam kasus Anda
1//0.01
harus dikonversi dulu1*100//(0.01*100)
yang 100.Dalam kasus yang lebih ekstrim, Anda masih bisa mendapatkan hasil yang "tidak terduga". Mungkin perlu menambahkan
round
panggilan ke pembilang dan penyebut sebelum melakukan pembagian integer:Tetapi, jika ini adalah tentang bekerja dengan desimal tetap (uang, sen), maka pertimbangkan bekerja dengan sen sebagai satuan , sehingga semua aritmatika dapat dilakukan sebagai bilangan bulat aritmatika, dan hanya mengkonversi ke / dari satuan moneter utama (dolar) saat melakukan I / O.
Atau sebagai alternatif, gunakan perpustakaan untuk desimal, seperti desimal , yang:
sumber
Apa yang harus Anda memperhitungkan adalah bahwa
//
adalahfloor
operator dan dengan demikian Anda pertama harus berpikir seperti jika Anda memiliki probabilitas yang sama untuk jatuh 100 seperti dalam 99 (*) (karena operasi akan100 ± epsilon
denganepsilon>0
ketentuan bahwa kemungkinan mendapatkan persis 100.00 ..0 sangat rendah.)Anda benar-benar dapat melihat hal yang sama dengan tanda minus,
dan Anda harus kaget.
Di sisi lain,
int(-1/.01)
lakukan pertama divisi dan kemudian menerapkanint()
dalam angka, yang bukan lantai tetapi pemotongan menuju 0 ! artinya dalam hal itu,karenanya,
Namun pembulatan, akan memberi Anda hasil yang ANDA harapkan untuk operator ini karena sekali lagi, kesalahannya kecil untuk angka-angka itu.
(*) Saya tidak mengatakan bahwa probabilitasnya sama, saya hanya mengatakan bahwa apriori ketika Anda melakukan perhitungan dengan aritmatika apung yang merupakan perkiraan dari apa yang Anda dapatkan.
sumber
Angka floating point tidak dapat mewakili angka desimal paling tepat, jadi ketika Anda mengetik floating point literal Anda benar-benar mendapatkan perkiraan dari literal itu. Perkiraan mungkin lebih besar atau lebih kecil dari angka yang Anda ketikkan.
Anda dapat melihat nilai tepat angka floating point dengan memberikannya ke Desimal atau Fraksi.
Kita dapat menggunakan tipe Fraksi untuk menemukan kesalahan yang disebabkan oleh literal tidak tepat kita.
Kita juga bisa mengetahui bagaimana angka floating point presisi granular ganda sekitar 100 adalah dengan menggunakan selanjutnya dari numpy.
Dari sini kita dapat menduga bahwa angka floating point terdekat
1/0.01000000000000000020816681711721685132943093776702880859375
sebenarnya adalah 100.Perbedaan antara
1//0.01
danint(1/0.01)
merupakan pembulatan. 1 // 0,01 membulatkan hasil yang pasti ke seluruh angka berikutnya dalam satu langkah. Jadi kami mendapatkan hasil 99.int (1 / 0,01) di sisi lain putaran dalam dua tahap, pertama putaran hasil ke nomor floating point presisi ganda terdekat (yang persis 100), kemudian bulat bahwa angka floating point turun ke bilangan bulat berikutnya (yaitu lagi tepat 100).
sumber
int(0.9) == 0
danint(-0.9) == 0
Jika Anda menjalankan yang berikut ini
Outputnya adalah:
Ini adalah bagaimana itu direpresentasikan secara internal, jadi membulatkannya
//
akan memberi99
sumber
Decimal(0.01)
Anda terlambat, kesalahan sudah merayap masuk sebelum Anda meneleponDecimal
. Saya tidak yakin bagaimana ini merupakan jawaban untuk pertanyaan ... Anda harus terlebih dahulu menghitung 0,01 dengan tepatDecimal(1) / Decimal(100)
, seperti yang saya tunjukkan dalam jawaban saya.