Pertimbangkan empat persentase di bawah ini, direpresentasikan sebagai float
angka:
13.626332%
47.989636%
9.596008%
28.788024%
-----------
100.000000%
Saya perlu mewakili persentase ini sebagai bilangan bulat. Jika saya hanya menggunakan Math.round()
, saya berakhir dengan total 101%.
14 + 48 + 10 + 29 = 101
Jika saya gunakan parseInt()
, saya berakhir dengan total 97%.
13 + 47 + 9 + 28 = 97
Apa algoritma yang baik untuk mewakili sejumlah persentase sebagai bilangan bulat dengan tetap mempertahankan total 100%?
Sunting : Setelah membaca beberapa komentar dan jawaban, jelas ada banyak cara untuk menyelesaikannya.
Dalam pikiran saya, untuk tetap setia pada angka-angka, hasil "benar" adalah hasil yang meminimalkan kesalahan keseluruhan, yang ditentukan oleh seberapa banyak pembulatan kesalahan akan diperkenalkan relatif terhadap nilai aktual:
value rounded error decision
----------------------------------------------------
13.626332 14 2.7% round up (14)
47.989636 48 0.0% round up (48)
9.596008 10 4.0% don't round up (9)
28.788024 29 2.7% round up (29)
Dalam kasus seri (3.33, 3.33, 3.33) keputusan sewenang-wenang dapat dibuat (mis. 3, 4, 3).
sumber
Jawaban:
Karena tidak ada jawaban di sini yang tampaknya menyelesaikannya dengan benar, inilah versi semi-membingungkan saya menggunakan underscorejs :
sumber
Ada banyak cara untuk melakukan ini, asalkan Anda tidak khawatir tentang ketergantungan pada data desimal asli.
Metode pertama dan mungkin paling populer adalah Metode Sisa Terbesar
Yang pada dasarnya adalah:
Dalam kasus Anda, akan seperti ini:
Jika Anda mengambil bagian integer, Anda dapatkan
yang menambahkan hingga 97, dan Anda ingin menambahkan tiga lagi. Sekarang, Anda melihat bagian desimal, yaitu
dan ambil yang terbesar sampai total mencapai 100. Jadi Anda akan mendapatkan:
Atau, Anda bisa memilih untuk menunjukkan satu tempat desimal daripada nilai integer. Jadi jumlahnya akan menjadi 48,3 dan 23,9 dll. Ini akan menjatuhkan varians dari 100 oleh banyak.
sumber
Mungkin "terbaik" cara untuk melakukan hal ini (dikutip sejak "terbaik" adalah istilah subjektif) adalah untuk menjaga berjalan (non-integral) penghitungan dari mana Anda berada, dan bulat yang nilai.
Kemudian gunakan itu bersama dengan sejarah untuk mencari tahu nilai apa yang harus digunakan. Misalnya, menggunakan nilai yang Anda berikan:
Pada setiap tahap, Anda tidak membulatkan angka itu sendiri. Alih-alih, Anda membulatkan nilai akumulasi dan mencari bilangan bulat terbaik yang mencapai nilai itu dari baseline sebelumnya - bahwa baseline adalah nilai kumulatif (bulat) dari baris sebelumnya.
Ini berfungsi karena Anda tidak kehilangan informasi di setiap tahap, tetapi menggunakan informasi itu dengan lebih cerdas. Nilai bulat 'benar' ada di kolom terakhir dan Anda dapat melihat bahwa jumlahnya berjumlah 100.
Anda dapat melihat perbedaan antara ini dan membulatkan setiap nilai secara buta, pada nilai ketiga di atas. Sementara
9.596008
biasanya akan dibulatkan ke atas10
, akumulasi yang71.211976
benar dibulatkan ke71
- ini berarti bahwa hanya9
diperlukan untuk menambah baseline sebelumnya62
.Ini juga berfungsi untuk urutan "bermasalah" seperti tiga nilai kasar , di mana salah satunya harus dibulatkan:
1/3
sumber
26, 25, 26, 23
, yang kedua1, 0, 1, 0, 1, 0, ...
.Tujuan pembulatan adalah untuk menghasilkan jumlah kesalahan paling sedikit. Saat Anda membulatkan satu nilai, proses itu sederhana dan mudah dan kebanyakan orang memahaminya dengan mudah. Saat Anda membulatkan banyak angka sekaligus, prosesnya menjadi lebih rumit - Anda harus menentukan bagaimana kesalahan akan digabungkan, yaitu apa yang harus diminimalkan.
The jawaban baik sebagai oleh Varun Vohra meminimalkan jumlah kesalahan mutlak, dan itu sangat sederhana untuk menerapkan. Namun ada kasus tepi yang tidak ditangani - apa yang harus menjadi hasil pembulatan
24.25, 23.25, 27.25, 25.25
? Salah satu dari itu perlu dibulatkan ke atas bukannya ke bawah. Anda mungkin akan secara sewenang-wenang memilih yang pertama atau terakhir dalam daftar.Mungkin lebih baik menggunakan kesalahan relatif daripada kesalahan absolut . Pembulatan 23,25 hingga 24 mengubahnya dengan 3,2% sementara pembulatan 27,25 hingga 28 hanya mengubahnya dengan 2,8%. Sekarang ada pemenang yang jelas.
Dimungkinkan untuk mengubah ini lebih jauh. Salah satu teknik yang umum adalah menguadratkan masing-masing kesalahan, sehingga kesalahan besar dihitung secara tidak proporsional lebih dari yang kecil. Saya juga menggunakan pembagi non-linear untuk mendapatkan kesalahan relatif - tampaknya tidak benar bahwa kesalahan pada 1% adalah 99 kali lebih penting daripada kesalahan pada 99%. Dalam kode di bawah ini saya telah menggunakan root kuadrat.
Algoritma lengkap adalah sebagai berikut:
Anda mungkin masih memiliki lebih dari satu kombinasi dengan jumlah kesalahan yang sama, misalnya
33.3333333, 33.3333333, 33.3333333
. Ini tidak bisa dihindari, dan hasilnya akan sepenuhnya arbitrer. Kode yang saya berikan di bawah ini lebih suka mengumpulkan nilai di sebelah kiri.Menyatukan semuanya dalam Python terlihat seperti ini.
Seperti yang dapat Anda lihat dengan contoh terakhir itu, algoritma ini masih mampu memberikan hasil yang tidak intuitif. Meskipun 89.0 tidak perlu dibulatkan apa pun, salah satu nilai dalam daftar itu perlu dibulatkan; kesalahan relatif terendah dihasilkan dari mengumpulkan nilai besar itu daripada alternatif yang jauh lebih kecil.
Jawaban ini awalnya menganjurkan melalui setiap kombinasi yang mungkin dari putaran ke atas / ke bawah, tetapi seperti yang ditunjukkan dalam komentar metode yang lebih sederhana bekerja lebih baik. Algoritma dan kode mencerminkan penyederhanaan itu.
sumber
if actual == 0: return 0
untukerror_gen
karya-karya besar.isclose
metode di awalround_to_100
?JANGAN menjumlahkan angka bulat. Anda akan mendapatkan hasil yang tidak akurat. Total dapat dimatikan secara signifikan tergantung pada jumlah istilah dan distribusi bagian fraksional.
Menampilkan angka-angka bulat tetapi menjumlahkan nilai aktual. Tergantung pada bagaimana Anda menyajikan angka-angka, cara aktual untuk melakukan itu akan bervariasi. Dengan begitu kamu bisa
Apa pun cara Anda pergi Anda akan memiliki perbedaan. Tidak ada cara dalam contoh Anda untuk menunjukkan angka yang menambahkan hingga 100 tanpa "membulatkan" satu nilai dengan cara yang salah (kesalahan paling sedikit akan berubah 9.596 menjadi 9)
EDIT
Anda harus memilih salah satu dari yang berikut:
Sebagian besar waktu ketika berhadapan dengan persentase # 3 adalah pilihan terbaik karena lebih jelas ketika totalnya sama dengan 101% daripada ketika masing-masing item tidak mencapai 100, dan Anda menjaga setiap item akurat. "Pembulatan" 9.596 hingga 9 tidak akurat menurut saya.
Untuk menjelaskan hal ini, saya terkadang menambahkan catatan kaki yang menjelaskan bahwa nilai-nilai individual dibulatkan dan mungkin tidak berjumlah 100% - siapa pun yang memahami pembulatan harus dapat memahami penjelasan itu.
sumber
Saya menulis pembantu pembulatan versi C, algoritmenya sama dengan jawaban Varun Vohra , semoga membantu.
Itu lulus tes Unit berikut:
sumber
Anda bisa mencoba melacak kesalahan Anda karena pembulatan, dan kemudian pembulatan terhadap gandum jika akumulasi kesalahan lebih besar dari bagian fraksional dari angka saat ini.
Tidak yakin apakah ini akan berfungsi secara umum, tetapi tampaknya berfungsi serupa jika urutannya terbalik:
Saya yakin ada kasus tepi di mana ini mungkin rusak, tetapi pendekatan apa pun akan setidaknya agak sewenang-wenang karena Anda pada dasarnya memodifikasi data input Anda.
sumber
Saya pernah menulis alat unround, untuk menemukan perturbasi minimal untuk satu set angka untuk mencocokkan suatu gol. Itu adalah masalah yang berbeda, tetapi secara teori seseorang dapat menggunakan ide serupa di sini. Dalam hal ini, kami memiliki serangkaian pilihan.
Jadi untuk elemen pertama, kita bisa membulatkannya hingga 14, atau turun ke 13. Biaya (dalam arti pemrograman bilangan bulat biner) untuk melakukannya lebih sedikit untuk putaran ke atas daripada putaran ke bawah, karena putaran ke bawah mengharuskan kita pindahkan nilai itu ke jarak yang lebih besar. Demikian pula, kita dapat membulatkan setiap angka ke atas atau ke bawah, sehingga ada total 16 pilihan yang harus kita pilih.
Saya biasanya memecahkan masalah umum di MATLAB, di sini menggunakan bintprog, alat pemrograman bilangan bulat biner, tetapi hanya ada beberapa pilihan untuk diuji, jadi cukup mudah dengan loop sederhana untuk menguji masing-masing dari 16 alternatif. Sebagai contoh, anggaplah kita harus melengkapi set ini sebagai:
Total kesalahan absolut yang dibuat adalah 1.25266. Ini dapat dikurangi sedikit dengan pembulatan alternatif berikut:
Bahkan, ini akan menjadi solusi optimal dalam hal kesalahan absolut. Tentu saja, jika ada 20 istilah, ruang pencarian akan berukuran 2 ^ 20 = 1048576. Untuk 30 atau 40 istilah, ruang tersebut akan memiliki ukuran yang signifikan. Dalam hal ini, Anda perlu menggunakan alat yang dapat mencari ruang secara efisien, mungkin menggunakan cabang dan skema terikat.
sumber
Saya pikir yang berikut ini akan mencapai apa yang Anda cari
Satu hal terakhir, saya menjalankan fungsi menggunakan angka-angka yang awalnya diberikan dalam pertanyaan untuk membandingkan dengan output yang diinginkan
Ini berbeda dengan apa yang diinginkan pertanyaan => [48, 29, 14, 9]. Saya tidak dapat memahami hal ini sampai saya melihat total margin of error
Pada dasarnya, hasil dari fungsi saya sebenarnya memperkenalkan jumlah kesalahan paling sedikit.
Biola di sini
sumber
Saya tidak yakin apa tingkat akurasi yang Anda butuhkan, tetapi apa yang akan saya lakukan hanyalah menambahkan 1
n
angka pertama ,n
menjadi langit-langit dari jumlah total desimal. Dalam hal ini3
, jadi saya akan menambahkan 1 ke 3 item pertama dan lantai sisanya. Tentu saja ini tidak super akurat, beberapa angka mungkin dibulatkan ke atas atau ke bawah ketika seharusnya tidak tetapi berfungsi dengan baik dan akan selalu menghasilkan 100%.Jadi
[ 13.626332, 47.989636, 9.596008, 28.788024 ]
akan[14, 48, 10, 28]
karenaMath.ceil(.626332+.989636+.596008+.788024) == 3
Anda selalu dapat memberi tahu pengguna bahwa jumlahnya bulat dan mungkin tidak super akurat ...
sumber
Jika Anda membulatkannya, tidak ada cara yang baik untuk mendapatkannya persis sama dalam semua kasus.
Anda dapat mengambil bagian desimal dari persentase N yang Anda miliki (dalam contoh yang Anda berikan adalah 4).
Tambahkan bagian desimal. Dalam contoh Anda, Anda memiliki total bagian pecahan = 3.
Ceil 3 angka dengan pecahan tertinggi dan lantai sisanya.
(Maaf untuk hasil edit)
sumber
Jika Anda benar-benar harus mengikutinya, sudah ada saran yang sangat bagus di sini (sisanya terbesar, kesalahan relatif paling sedikit, dan sebagainya).
Sudah ada satu alasan bagus untuk tidak membulatkan (Anda akan mendapatkan setidaknya satu nomor yang "terlihat lebih baik" tetapi "salah"), dan bagaimana menyelesaikannya (memperingatkan pembaca Anda) dan itulah yang saya lakukan.
Biarkan saya menambahkan pada bagian nomor "salah".
Misalkan Anda memiliki tiga acara / entitas / ... dengan beberapa persentase yang Anda perkirakan sebagai:
Nanti nilai berubah sedikit, menjadi
Tabel pertama memiliki masalah yang telah disebutkan memiliki nomor "salah": 33,34 lebih dekat ke 33 daripada ke 34.
Tetapi sekarang Anda memiliki kesalahan yang lebih besar. Membandingkan hari 2 dengan hari 1, nilai persentase riil untuk A meningkat, sebesar 0,01%, tetapi perkiraan menunjukkan penurunan sebesar 1%.
Itu adalah kesalahan kualitatif, mungkin lebih buruk daripada kesalahan kuantitatif awal.
Orang bisa menyusun perkiraan untuk seluruh set tetapi, Anda mungkin harus menerbitkan data pada hari pertama, sehingga Anda tidak akan tahu tentang hari kedua. Jadi, kecuali Anda benar-benar harus memperkirakan, Anda mungkin lebih baik tidak.
sumber
periksa apakah ini valid atau tidak sejauh kasus pengujian saya, saya bisa membuatnya bekerja.
katakanlah angka adalah k;
sumber
Saya telah menerapkan metode dari jawaban Varun Vohra di sini untuk daftar dan dikte.
sumber
Berikut ini implementasi Python sederhana dari jawaban @ varun-vohra:
Anda perlu
math
,itertools
,operator
.sumber
Bagi mereka yang memiliki persentase dalam Seri panda, berikut adalah implemantasi saya dari metode sisa terbesar (seperti dalam jawaban Varun Vohra ), di mana Anda bahkan dapat memilih desimal yang ingin Anda bulatkan.
sumber
Ini adalah kasus pembulatan bankir, alias 'bulat setengah genap'. Ini didukung oleh BigDecimal. Tujuannya adalah untuk memastikan bahwa pembulatan saldo, yaitu tidak menguntungkan bank atau pelanggan.
sumber