Katakanlah kita punya 0.33
, kita perlu mengeluarkan 1/3
.
Jika sudah 0.4
, kita perlu mengeluarkan 2/5
.
Idenya adalah membuatnya dapat dibaca manusia untuk membuat pengguna memahami " bagian x dari y " sebagai cara yang lebih baik untuk memahami data.
Saya tahu bahwa persentase adalah pengganti yang baik, tetapi saya bertanya-tanya apakah ada cara sederhana untuk melakukan ini?
algorithm
language-agnostic
numbers
Swaroop CH
sumber
sumber
.33
=>"1/3"
menyangkut saya; Saya berharap.33
=>"33/100"
. Saya berasumsi yang Anda maksudkan.33...
, tentu saja, tetapi hal itu mengungkap masalah dengan pertanyaan - sebelum kita dapat menyelesaikan algoritme, kita perlu memutuskan perilaku yang diharapkan. Jawaban Python @ Debilski menggunakan.limit_denominator()
yang defaultnya ke penyebut maksimum 10 ^ 7; mungkin default yang baik dalam praktek, tetapi ini masih bisa memperkenalkan bug jika Anda tidak hati-hati, dan tidak kembali"33/100"
dalam.33
kasus.Jawaban:
Saya telah menemukan pendekatan rasional David Eppstein untuk memberikan kode bilangan real C persis seperti yang Anda minta. Ini didasarkan pada teori pecahan lanjutan dan sangat cepat dan cukup kompak.
Saya telah menggunakan versi ini yang disesuaikan untuk pembilang dan batas penyebut tertentu.
sumber
Dari Python 2.6 ada
fractions
modulnya.(Mengutip dari dokumen.)
sumber
language agnostic
danalgorithm
tag yang memenuhi jawaban Anda?Jika keluarannya adalah untuk memberikan gambaran yang cepat kepada pembaca manusia tentang urutan hasil, tidak masuk akal mengembalikan sesuatu seperti "113/211", jadi keluaran harus membatasi dirinya sendiri untuk menggunakan angka satu digit (dan mungkin 1 / 10 dan 9/10). Jika demikian, Anda dapat mengamati bahwa hanya ada 27 pecahan yang berbeda .
Karena matematika yang mendasari untuk menghasilkan keluaran tidak akan pernah berubah, solusinya bisa dengan membuat kode keras pohon pencarian biner, sehingga fungsi tersebut akan melakukan paling banyak perbandingan log (27) ~ = 4 3/4. Berikut ini adalah versi C kode yang diuji
sumber
1/1000
ini juga dapat dibaca secara manusiawi, tetapi algoritme di atas hanya akan menghasilkan1/10
perkiraan yang sangat kasar ; Saya percaya bahwa perbaikan dapat dilakukan dalam hal yang penyebut dibaca secara manusiawi satu dapat memilih dari, dan / atau penambahan<
,>
,<<
,>>
prefiks untuk memberikan gambaran tentang kekasaran pendekatan tersebut.Berikut tautan yang menjelaskan matematika di balik mengubah desimal menjadi pecahan:
http://www.webmath.com/dec2fract.html
Dan berikut adalah contoh fungsi bagaimana melakukannya menggunakan VB (dari www.freevbcode.com/ShowCode.asp?ID=582):
(Dari pencarian google: ubah desimal menjadi pecahan, ubah desimal menjadi kode pecahan)
sumber
Anda mungkin ingin membaca Yang Harus Diketahui Setiap Ilmuwan Komputer tentang Aritmatika Titik Mengambang .
Anda harus menentukan beberapa presisi dengan mengalikan dengan bilangan besar:
maka Anda dapat membuat pecahan:
dan mengurangi melalui GCD ...
tetapi tidak ada cara untuk mengeluarkan pecahan yang dimaksud . Anda mungkin ingin selalu menggunakan pecahan di seluruh kode Anda - ingat saja untuk mengurangi pecahan bila Anda bisa untuk menghindari luapan!
sumber
Berikut adalah versi Perl dan Javascript dari kode VB yang disarankan oleh devinmoore:
Perl:
Dan javascript yang hampir identik:
sumber
Implementasi AC #
sumber
Pohon Stern-Brocot menginduksi cara yang cukup alami untuk memperkirakan bilangan real dengan pecahan dengan penyebut sederhana.
sumber
Sebagian dari masalahnya adalah begitu banyak pecahan sebenarnya tidak mudah diartikan sebagai pecahan. Misalnya 0,33 bukan 1/3, itu 33/100. Tetapi jika Anda mengingat pelatihan sekolah dasar Anda, maka ada proses untuk mengubah nilai desimal menjadi pecahan, namun tidak mungkin memberikan apa yang Anda inginkan karena sebagian besar waktu angka desimal tidak disimpan di 0,33, tetapi 0,329999999999998 atau semacamnya.
Bantulah diri Anda sendiri dan jangan repot-repot dengan ini, tetapi jika perlu, Anda dapat melakukan hal berikut:
Kalikan nilai awal dengan 10 sampai Anda menghilangkan bagian pecahannya. Simpan angka itu, dan gunakan sebagai pembagi. Kemudian lakukan serangkaian penyederhanaan dengan mencari penyebut yang sama.
Jadi 0,4 akan menjadi 4/10. Anda kemudian akan mencari pembagi persekutuan yang dimulai dengan nilai rendah, mungkin bilangan prima. Dimulai dengan 2, Anda akan melihat apakah 2 membagi pembilang dan penyebutnya secara merata dengan memeriksa apakah lantai pembaginya sama dengan pembagi itu sendiri.
Jadi 5 tidak membagi 2 secara merata. Jadi, kemudian Anda memeriksa angka berikutnya, katakanlah 3. Anda melakukan ini sampai Anda mencapai atau di atas akar kuadrat dari angka yang lebih kecil.
Setelah Anda melakukan itu maka Anda perlu
sumber
Ini bukan "algoritme", hanya solusi Python: http://docs.python.org/library/fractions.html
sumber
"Katakanlah kita memiliki 0,33, kita perlu mengeluarkan" 1/3 "."
Presisi apa yang Anda harapkan dari "solusi" tersebut? 0,33 tidak sama dengan 1/3. Bagaimana Anda mengenali jawaban yang "baik" (mudah dibaca)?
Apa pun yang terjadi, algoritme yang mungkin dapat berupa:
Jika Anda berharap menemukan pecahan terdekat dalam bentuk X / Y di mana Y kurang dari 10, Anda dapat mengulang semua 9 kemungkinan Y, untuk setiap Y menghitung X, lalu memilih yang paling akurat.
sumber
Saya pikir cara terbaik untuk melakukan ini adalah dengan terlebih dahulu mengubah nilai float Anda menjadi representasi ascii. Di C ++ Anda bisa menggunakan ostringstream atau di C, Anda bisa menggunakan sprintf. Begini tampilannya di C ++:
Pendekatan serupa dapat dilakukan pada C.
Setelah itu Anda perlu memeriksa bahwa pecahannya termasuk suku yang paling rendah. Algoritme ini akan memberikan jawaban yang tepat, yaitu 0,33 akan menghasilkan "33/100", bukan "1/3". Namun, 0,4 akan menjadi "4/10", yang bila disederhanakan menjadi "2/5". Ini mungkin tidak sekuat solusi EppStein, tapi saya yakin ini lebih mudah.
sumber
Solusi bawaan di R:
Ini menggunakan metode pecahan lanjutan dan memiliki opsional
cycles
danmax.denominator
argumen untuk menyesuaikan presisi.sumber
library(numbers)
dancontFrac(0.6666)
; untuk mendapatkan keluaran string yang diinginkan:paste(contFrac(0.666, tol=1e-03)$rat, collapse="/")
Anda harus mencari tahu tingkat kesalahan yang ingin Anda terima. Tidak semua pecahan desimal akan menjadi pecahan sederhana. Saya mungkin akan memilih angka yang mudah habis dibagi, seperti 60, dan mencari tahu berapa banyak 60 yang paling dekat dengan nilainya, lalu menyederhanakan pecahannya.
sumber
Anda dapat melakukan ini dalam bahasa pemrograman apa pun menggunakan langkah-langkah berikut:
Contoh: 0,2 = 0,2 x 10 ^ 1/10 ^ 1 = 2/10 = 1/5
Jadi, itu bisa dibaca sebagai '1 bagian dari 5'
sumber
Salah satu solusinya adalah dengan menyimpan semua bilangan sebagai bilangan rasional di tempat pertama. Ada perpustakaan untuk aritmatika bilangan rasional (misalnya GMP ). Jika menggunakan bahasa OO, Anda mungkin dapat menggunakan pustaka kelas bilangan rasional untuk menggantikan kelas bilangan Anda.
Program keuangan, antara lain, akan menggunakan solusi tersebut untuk dapat membuat kalkulasi yang tepat dan menjaga presisi yang mungkin hilang dengan menggunakan pelampung biasa.
Tentu saja akan jauh lebih lambat jadi mungkin tidak praktis untuk Anda. Tergantung pada seberapa banyak kalkulasi yang perlu Anda lakukan, dan seberapa penting ketepatan itu bagi Anda.
sumber
Ini salah dalam kasus umum, karena 1/3 = 0.3333333 = 0. (3) Selain itu, tidak mungkin untuk mengetahui dari solusi yang disarankan di atas adalah desimal dapat diubah menjadi pecahan dengan ketepatan yang ditentukan, karena keluaran selalu pecahan.
TAPI, saya menyarankan fungsi komprehensif saya dengan banyak opsi berdasarkan gagasan deret geometris tak hingga , khususnya rumus:
Pada awalnya fungsi ini mencoba mencari periode pecahan dalam representasi string. Setelah itu rumus di atas diterapkan.
Kode bilangan rasional dipinjam dari implementasi bilangan rasional Stephen M. McKamey di C #. Saya berharap tidak terlalu sulit untuk mem-port kode saya ke bahasa lain.
Ada beberapa contoh penggunaan:
Casing Anda dengan pemangkasan bagian nol bagian kanan:
Periode demostrasi min:
Pembulatan di akhir:
Kasus paling menarik:
Tes dan kode lain dapat ditemukan semua orang di pustaka MathFunctions saya di github .
sumber
Ruby sudah memiliki solusi bawaan:
Di Rails, atribut numerik ActiveRecord juga dapat diubah:
sumber
Jawab dalam C ++, dengan asumsi Anda memiliki kelas 'BigInt', yang dapat menyimpan bilangan bulat ukuran tak terbatas.
Anda dapat menggunakan 'unsigned long long', tetapi ini hanya akan berfungsi untuk nilai-nilai tertentu.
BTW, GetRational (0.0) akan mengembalikan "+0/1", jadi Anda mungkin ingin menangani kasus ini secara terpisah.
PS: Saya telah menggunakan kode ini di kelas 'RationalNum' saya sendiri selama beberapa tahun, dan itu telah diuji secara menyeluruh.
sumber
while
loop dibatasi oleh ukurandouble
, yang biasanya 64 bit. Jadi tidak tergantung pada nilai awal dari input (val
). NamunGCD
fungsinya bergantung pada nilai ini, meskipun biasanya konvergen ke solusi cukup cepat. Apakah mungkin Anda tidak mengimplementasikan fungsi ini dengan benar?unsigned long long
alih-alihBigInt
, maka itu tidak akan selalu menghasilkan hasil yang benar untuk setiap nilai input ... Tetapi bahkan di bawah skenario itu, kodenya tidak seharusnya "masuk ke lingkaran yang sangat panjang".GCD
fungsi tersebut tidak diimplementasikan dengan benar. Sudahkah Anda memeriksa apakah kode berjalan untuk waktu yang lama selamawhile
pengulangan atau setelahnya? Saya akan memeriksa nilai 1,33333, untuk melihat ada apa di balik ini. Terima kasih.Algoritma oleh Ian Richards / John Kennedy ini tidak hanya mengembalikan pecahan yang bagus, tetapi juga bekerja dengan sangat baik dalam hal kecepatan. Ini adalah kode C # yang saya ambil dari jawaban ini .
Itu dapat menangani semua
double
nilai kecuali nilai khusus seperti NaN dan +/- tak terhingga, yang harus Anda tambahkan jika diperlukan.Ini mengembalikan a
new Fraction(numerator, denominator)
. Gantikan dengan tipe Anda sendiri.Untuk nilai contoh lainnya dan perbandingan dengan algoritme lain, buka di sini
Contoh nilai yang dikembalikan oleh algoritma ini:
sumber
Anda akan menghadapi dua masalah dasar yang akan membuat ini sulit:
1) Titik mengambang bukanlah representasi yang tepat yang berarti bahwa jika Anda memiliki pecahan dari "x / y" yang menghasilkan nilai "z", algoritme pecahan Anda dapat mengembalikan hasil selain "x / y".
2) Ada lebih banyak bilangan irasional tak terhingga daripada rasional. Bilangan rasional adalah bilangan yang dapat direpresentasikan sebagai pecahan. Makhluk irasional yang tidak bisa.
Namun, dengan cara yang murah, karena floating point memiliki akurasi batas, maka Anda selalu dapat merepresentasikannya sebagai beberapa bentuk faksi. (Kupikir...)
sumber
Menyelesaikan kode di atas dan mengubahnya menjadi as3
sumber
Berikut adalah implementasi cepat dan kotor di javascript yang menggunakan pendekatan brute force. Sama sekali tidak dioptimalkan, ia bekerja dalam kisaran pecahan yang telah ditentukan: http://jsfiddle.net/PdL23/1/
Hal ini terinspirasi dari pendekatan yang digunakan JPS.
sumber
Seperti yang dikatakan banyak orang, Anda benar-benar tidak dapat mengubah floating point kembali menjadi pecahan (kecuali jika sangat persis seperti 0,25). Tentu saja Anda dapat membuat beberapa jenis pencarian untuk sejumlah besar pecahan dan menggunakan semacam logika fuzzy untuk menghasilkan hasil yang Anda cari. Sekali lagi ini tidak akan tepat dan Anda perlu menentukan batas bawah seberapa besar penyebut yang Anda inginkan.
.32 <x <.34 = 1/3 atau sesuatu seperti itu.
sumber
Berikut adalah implementasi untuk ruby http://github.com/valodzka/frac
sumber
Saya menemukan solusi Haskell yang sangat elegan yang menggunakan anamorphism. Itu tergantung pada paket skema-rekursi .
Jika Anda mencobanya di ghci, itu benar-benar berhasil!
sumber