Ubah desimal berulang menjadi pecahan

23

Pertanyaan ini tidak perlu diterapkan pada penghentian desimal saja - desimal berulang juga dapat dikonversi menjadi pecahan melalui suatu algoritma.

Tugas Anda adalah membuat program yang mengambil desimal berulang sebagai input, dan menampilkan pembilang dan penyebut yang sesuai (dalam istilah terendah) yang menghasilkan ekspansi desimal itu. Pecahan yang lebih besar dari 1 harus dinyatakan sebagai pecahan yang tidak tepat 9/5. Anda dapat berasumsi bahwa input akan positif.

Desimal berulang akan diberikan dalam format ini:

5.3.87

dengan semua setelah titik kedua diulang, seperti ini:

5.3878787878787...

Program Anda akan menghasilkan dua bilangan bulat yang mewakili pembilang dan penyebut, dipisahkan oleh garis miring (atau bentuk yang setara dalam bahasa Anda jika Anda tidak menampilkan teks biasa):

889/165

Perhatikan bahwa penghentian desimal tidak akan memiliki apa pun setelah titik kedua, dan desimal tanpa bagian desimal yang tidak berulang tidak akan memiliki apa pun di antara kedua titik.

Uji kasus

Kasing uji ini mencakup semua kasing yang diperlukan:

0..3 = 1/3
0.0.3 = 1/30
0.00.3 = 1/300
0.6875. = 11/16
1.8. = 9/5
2.. = 2/1
5..09 = 56/11
0.1.6 = 1/6
2..142857 = 15/7
0.01041.6 = 1/96
0.2.283950617 = 37/162
0.000000.1 = 1/9000000
0..9 = 1/1
0.0.9 = 1/10
0.24.9 = 1/4

Jika diinginkan, Anda juga dapat mengasumsikan bahwa pecahan tanpa bagian bilangan bulat tidak memiliki apa pun di sebelah kiri titik pertama. Anda dapat mengujinya dengan kasus uji opsional ini:

.25. = 1/4
.1.6 = 1/6
..09 = 1/11
.. = 0/1
Joe Z.
sumber
1
Apakah perlu untuk menyederhanakan fraksi? Atau masuk akal untuk membiarkannya dalam bentuk yang tidak disederhanakan (misalnya:) 9/99?
Justin
3
(in lowest terms)yaitu fraksi harus disederhanakan.
Joe Z.
2
Apakah saya diizinkan output 13bukan 13/1?
mniip
4
Pastikan untuk menangani input 1.9999...dan output ini2/1
Thomas Eding
3
@ThomasEding 1.9999.adalah 19999/10000, untuk memenuhi 2/1kebutuhan Anda 1..9, bukan?
Qwertiy

Jawaban:

8

Dyalog APL ( 75 73 69 68 karakter)

Ini adalah upaya lain dan kelima (kemungkinan besar yang terakhir saya); Saya menghabiskan hari itu mencoba menulis beberapa kode lebih pendek dari 80 karakter dan sepenuhnya konsisten dengan aturan. Tantangan ini membuat hariku!

Saya akhirnya mendapat garis APL yang terdiri dari 75 karakter, bekerja dengan Dyalog APL (tetapi tidak pada halaman penerjemah online karena menggunakan fungsi eksekusi ), yang adalah sebagai berikut:

(N,D)÷D∨N←(⍎'0',1↓I/⍨2=+\P)+(⍎'0',I/⍨2>+\P)×D←D+0=D←⍎'0',⌽2↓⍕¯1+10⊥P←'.'=I← '1.2.3'

Tentu saja saya bisa membuatnya sedikit lebih pendek, tetapi kasus-kasus khusus di mana satu, dua atau tiga bidang hilang. Kode saya bahkan dapat menangani ..case input.

Saya tahu APL sulit dibaca, dan karena orang-orang senang memahami bagaimana sepotong kode benar-benar berfungsi, berikut adalah beberapa penjelasannya. Pada dasarnya, saya menghitung penyebut akhir dalam variabel D dan pembilang akhir dalam variabel N.

APL diuraikan dari kanan ke kiri.

  • Pertama, string disimpan dalam variabel I ( I←).
  • Kemudian dipetakan ke vektor boolean yang menunjukkan di mana titik berada, dan vektor ini disebut P ( P←'.'=). Misalnya '1.2.3' akan dipetakan ke 0 1 0 1 0.
  • Vektor ini adalah digit dalam basis 10 ( 10⊥); sekarang '1.2.3' adalah 1010.
  • Lalu 1 dikurangi dari nomor ini (baik dengan 1-⍨atau dengan ¯1+, di sini saya memilih yang kedua). Sekarang '1.2.3' adalah 1009.
  • Kemudian nomor ini dikonversi menjadi string ( ), dua digit awal dihapus ( 2↓), yang membuat 09 dari contoh awal kami '1.2.3'; string dibalik ( ).
  • Di sini, sebagai kasus khusus, saya menambahkan 0 karakter awal di depan string; itu membuat saya sedih untuk menggunakan empat karakter '0',tetapi saya melakukannya untuk menghindari kesalahan ketika bidang kedua dan pertiga keduanya kosong. String dikonversi kembali ke angka ( ) dan disimpan dalam D, yang merupakan penyebut kecuali ketika kedua bidang terakhir kosong, karena dalam kasus tersebut D sama dengan 0.
  • The D←D+0=potongan kode set D untuk 1 jika saat ini nol, dan sekarang D berisi denominator (sebelum pembagian GCD namun).
  • Penyebut ini dikalikan ( ×) dengan konten string awal I hingga titik kedua (⍎'0',I/⍨2>+\P)yang dimulai dari P lagi (0 1 0 1 0 dalam contoh saya), menambahkan angka berurutan dengan mengumpulkannya (yang membuat 0 1 1 2 2 dalam contoh saya), periksa nilai mana yang lebih kecil dari 2 (membuat vektor boolean 1 1 1 0 0), dan mengambil karakter yang sesuai di I; 0 lainnya ditambahkan di depan string untuk mencegah jebakan lain (jika dua bidang awal kosong) dan keseluruhan dikonversi ke angka.
  • Bagian terakhir dari string input ditambahkan ke produk sebelumnya dengan (⍎'0',1↓I/⍨2=+\P), yang mengambil P lagi, menambahkan dengan mengumpulkan lagi, memeriksa nilai mana yang sama dengan 2 (lihat penjelasan sebelumnya), mengambil karakter, menghapus yang pertama yang merupakan titik , menambahkan karakter awal 0 pencegahan dan mengkonversi ke nomor.
  • Produk ini diikuti dengan jumlah yang disimpan dalam N yang merupakan pembilang.
  • Akhirnya GCD dihitung dengan D∨N dan kedua angka dibagi dengan GCD ini.

sunting: Ini adalah perbaikan untuk 73 karakter:

(N,D)÷D∨N←(⍎'0',1↓P/I)+(⍎'0',I/⍨~P←2=+\P)×D←D+0=D←⍎'0',⌽2↓⍕¯1+10⊥P←'.'=I←

Gagasan hack ini adalah menghitung pertama kasus di mana penambahan kumulatif memiliki nilai sama dengan 2, menyimpannya untuk nanti dan membalikkan topeng bitwise ini untuk mendapatkan kasus pertama; dengan demikian menghitung kasus selanjutnya membutuhkan lebih sedikit karakter.

sunting: Ini adalah perbaikan lain untuk 69 karakter:

(N,D)÷D∨N←(⍎'0',1↓P/I)+(⍎'0',I/⍨~P←2=+\P)×D←⍎'1⌈0',⌽2↓⍕¯1+10⊥P←'.'=I←

Gagasan peretasan ini adalah untuk menyematkan kasus khusus yang paling rumit sebagai kode APL dalam string yang akan dievaluasi (pada tahap konversi string ke angka).

sunting: Ini adalah perbaikan lain untuk 68 karakter:

(N,D)÷D∨N←(⍎'0',1↓P/I)+(⍎'0',I/⍨~P←2=+\P)×D←⍎'1⌈0',⌽3↓⍕1-10⊥P←'.'=I←

Gagasan peretasan ini adalah untuk mengganti menambahkan -1 ke nilai untuk mengurangi 1 ke nilai itu dengan operasi mengurangkan nilai itu ke 1 lalu menghapus satu karakter lebih kemudian di awal (yang akan menjadi tanda minus).

sunting: Perubahan kosmetik:

(N,D)÷D∨N←(⍎'0',1↓P/I)+(⍎'0',I/⍨~P←2=+\P)×D←1⌈⍎'0',⌽3↓⍕1-10⊥P←'.'=I←

Tidak ada peningkatan dalam ukuran, tetapi lebih puas untuk mendapatkan fungsi maksimal dari kode yang akan dievaluasi.

Thomas Baruchel
sumber
Saya mencoba menjalankan ini dengan tryapl.org dan itu mengeluh INVALID TOKEN. Apa kamu tahu kenapa?
Peter Taylor
@ Peter Taylor: Ya, bahkan dikatakan dalam pesan saya; ini karena saya menggunakan operator "eksekusi" yang tidak aman untuk server Dyalog dan telah dinonaktifkan secara online (safe mode). Anda harus mencobanya di Dyalog APL versi terinstal.
Thomas Baruchel
Ah, malu. Saya tidak akan menghabiskan 60 € untuk dapat menguji pengiriman PCG sesekali. Saya telah menemukan tester APL online alternatif, tetapi tampaknya ada sesuatu yang spesifik Dyalog dalam kode Anda karena memberikan kesalahan peringkat atau kesalahan panjang.
Peter Taylor
@ Peter Taylor; tidak ;-) Tolong, gunakan situs web saya sendiri (masih eksperimental dan tidak resmi) dengan GNU APL; tapi saya harus menambahkan dua karakter untuk membuatnya kompatibel (tanda kurung sekitar satu I): lihat permalink
Thomas Baruchel
15

Perl 6 (93 101 100 80 68 66 byte)

$/=split ".",get;say ($0+($1+$2/(9 x$2.comb||1))/10**$1.comb).nude

Ukurannya ditingkatkan untuk menangani apa-apa, bukan hanya gagal. Mouq diusulkan untuk digunakan $/, jadi sekarang sedang digunakan, dan kodenya lebih pendek 20 byte. Ayiko mengusulkan mengganti /dengan , sehingga kode ini bahkan lebih pendek (dengan 12 bytes). Kemudian Mouq mengusulkan penggantian charsdengan comb(dalam konteks numerik, mereka identik, karena daftar karakter setelah konversi ke angka adalah jumlah karakter).

Output sampel:

$ perl6 script.p6
5.3.87
889 165
$ perl6 script.p6
2.0.0
2 1
$ perl6 script.p6
0..3
1 3
$ perl6 script.p6
0.0.3
1 30
$ perl6 script.p6
0.0.0
0 1
$ perl6 script.p6
0.1.6
1 6
$ perl6 script.p6
0.01041.6
1 96
$ perl6 script.p6
0.2.283950617
37 162
$ perl6 script.p6
123.456.789
41111111 333000
Konrad Borowski
sumber
Sayangnya, ternyata menggunakan nol sebagai pengganti antara dua titik adalah tindakan yang dilarang. 0..09kembali 1/11, tetapi 0.0.09kembali 1/110.
Joe Z.
@ Joz. Oh oke. Saya memperbarui kode saya untuk menangani kasus ini ketika tidak ada yang diketik.
Konrad Borowski
Saya tidak tahu Perl 6, tetapi apakah saya benar dalam menebak bahwa diberikan 'abc', program Anda menggunakan aritmatika rasional yang tepat untuk menghitung c / 99 ... 9, tetapi hanya menggunakan floating point untuk menghitung ab? Dalam hal ini jika b memiliki banyak digit maka akan memberikan jawaban yang salah.
Omar
@ OmarAntolín-Camarena: Tidak cukup. Dalam Perl 6, rasional adalah default, bukan angka floating point. Misalnya, 0.1 + 0.2 == 0.3dalam Perl 6.
Konrad Borowski
2
Bermain golf hingga 80 karakter: $/=split ".",get;say join "/",($0+($1+$2/(9 x chars $2 or 1))/10**$1.chars).nude:)
Mouq
6

J ( 85 90 89 karakter)

Fungsi asli saya, yang 5 karakter lebih pendek dari yang kedua, memiliki beberapa bug: itu tidak menghasilkan bilangan bulat sebagai "n / 1" dan itu memberikan jawaban yang salah pada angka dengan lebih dari selusin digit. Berikut adalah fungsi yang diperbaiki di J yang juga menggabungkan saran Eelvex untuk menyimpan karakter:

f=:3 :0
'a t'=.|:(".@('0','x',~]),10x^#);._1'.',y
(,'/'&,)&":/(,%+.)&1+/a%*/\1,0 1-~}.t
)

Ini menerima string dan mengembalikan string. Inilah sesi sampel:

   f '..'
0/1
   f '0.0.0'
0/1
   f '3..'
3/1
   f '..052631578947368421'
1/19
   f '0.2.283950617'
37/162
   f '.0.103092783505154639175257731958762886597938144329896907216494845360824742268041237113402061855670'
1/97
Omar
sumber
Anda harus memperbaiki fungsi Anda untuk output 0/1dan 3/1inf dua kasus uji pertama, Lihat komentar ini
mniip
Saya memperbaiki output untuk bilangan bulat dengan biaya 5 karakter, @mniip.
Omar
Gunakan ('0','x',~])dan simpan satu byte.
Eelvex
5

C, 171

Cukup lama. Bisa lebih jauh dikurangi. Tidak scanf, yang benar-benar tidak bisa mengatasinya jika tidak ada angka di antara titik-titik. Tidak ada strtol. Hanya angka yang berderak:

a,b,c,d,q;main(){while((q=getchar()-48)>-3)q<0?(d=b>0,b+=!b):d?(c=c*10+q,d*=10):(a=a*10+q,b*=10);for(a=a*--d+c,q=b*=d;q>1;a%q+b%q?--q:(a/=q,b/=q));printf("%d/%d\n",a,b);}

Uji:

rfc <<< "2..142857"
15/7
orion
sumber
5

DC (tidak sepenuhnya umum, disingkat menjadi 76 karakter)

Tidak sepenuhnya umum, tapi tolong, pertimbangkan saya melakukannya dengan salah satu hal tertua di dunia:

5.3.87 dsaX10r^d1-rla*sasbdscX10r^dlc*rlb*rlb*la+snsdlnld[dSarLa%d0<a]dsax+dldr/rlnr/f

Sunting: Saya mengedit solusi saya; itu tidak lebih umum, tetapi sedikit lebih pendek:

sadsbX10r^sclaX10r^dd1-dsdlblc**rla*+dsnrld*dsd[dSarLa%d0<a]dsax+dldr/rlnr/f

Gunakan sebagai:

5.3.87 sadsbX10r^sclaX10r^dd1-dsdlblc**rla*+dsnrld*dsd[dSarLa%d0<a]dsax+dldr/rlnr/f
  • Bidang pertama tidak diperlukan:

    .1.3 sadsbX10r^sclaX10r^dd1-dsdlblc**rla*+dsnrld*dsd[dSarLa%d0<a]dsax+dldr/rlnr/f
    

    tidak apa-apa.

  • Bidang kedua dan haus membutuhkan setidaknya satu digit

Thomas Baruchel
sumber
5

Javascript, 203

Terlalu lama, tapi tetap menyenangkan. Baris baru karena titik koma tidak dapat dibaca.

s=prompt(b=1).split(".")
P=Math.pow
a=s[0]
c=s[1]
d=P(10,l=c.length)
f=(P(10,s[2].length)-1)*P(10,l)||1
e=s[2]=+s[2]
a=d*a+b*c;b*=d
a=f*a+b*e;b*=f
function g(a,b){return b?g(b,a%b):a}g=g(a,b);a/g+"/"+b/g
tommeding
sumber
Saya mendapatkan 889/NaNketika saya menjalankan 5.3.87... Apakah saya melakukan sesuatu yang salah?
rafaelcastrocouto
Saya tidak tahu ... Jika saya hanya menempelkan kode ini di konsol Safari (Firefox atau Chrome juga harus melakukannya), tekan enter dan ketik "5.3.87", saya baru saja masuk "889/165"ke konsol. Bagaimana Anda menjalankannya? @rafaelcastrocouto
tomsmeding
Nevermind ... Saya kira saya melakukan sesuatu yang salah karena bekerja sekarang ...
rafaelcastrocouto
1
Anda dapat menyimpan 1 karakter dengan memindahkan b=1bagian dalam prompt().
user2428118
1
f=(P(10,s[2].length)-1)*P(10,l),f=f?f:1=>f=(P(10,s[2].length)-1)*P(10,l)||1
f.ardelian
3

J (metode berbeda)

Solusi lain berdasarkan metode yang sangat berbeda; kali ini sepenuhnya umum; hanya yang hilang adalah penyebut 1 ketika integer dikirimkan:

   ".((({.~(i.&1)),'+'"_,((":@(10&^)@#,'%~',])@}.@#~~:/\),'+%',((,~(##'9'"_),'%x:0'"_)@}.@#~2:=+/\@]))(=&'.')) '.1.3'
2r15
   ".((({.~(i.&1)),'+'"_,((":@(10&^)@#,'%~',])@}.@#~~:/\),'+%',((,~(##'9'"_),'%x:0'"_)@}.@#~2:=+/\@]))(=&'.')) '.1.'
1r10
   ".((({.~(i.&1)),'+'"_,((":@(10&^)@#,'%~',])@}.@#~~:/\),'+%',((,~(##'9'"_),'%x:0'"_)@}.@#~2:=+/\@]))(=&'.')) '1..'
1
   ".((({.~(i.&1)),'+'"_,((":@(10&^)@#,'%~',])@}.@#~~:/\),'+%',((,~(##'9'"_),'%x:0'"_)@}.@#~2:=+/\@]))(=&'.')) '1..3'
4r3
Thomas Baruchel
sumber
3

GolfScript (67 karakter)

`{'.'/1$=.10\,?@-).!+0@+~}+3,/1$4$*]-1%~;*+*+].~{.@\%.}do;{/}+/'/'@

NB Ini mendukung bagian integer kosong.

Jika string adalah dari bentuk 'n.p.q'maka nilainya adalah di n + p/E + q/(DE) = ((nD + p)E + q)/DEmana D = 10^(len p)dan E = 10^(len q) - 1, kecuali kapan len q = 0, dalam hal ini E = 1(untuk menghindari pembagian dengan 0).

Pembedahan:

           # Stack: 'n.p.q'
`{         # Combined with the }+ below this pulls the value into the block
           # Stack: idx 'n.p.q'
    '.'/   # Stack: idx ['n' 'p' 'q']
    1$=    # Stack: idx str   (where str is the indexed element of ['n' 'p' 'q'])
    .10\,? # Stack: idx str 10^(len str)
    @-)    # Stack: str 10^(len str)-idx+1
           #   If idx = 0 we don't care about the top value on the stack
           #   If idx = 1 we compute D = 10^(len 'p')
           #   If idx = 2 we compute E' = 10^(len 'q') - 1
    .!+    # Handle the special case E'=0; note that D is never 0
    0@+~   # Stack: 10^(len str)-idx+1 eval('0'+str) (GolfScript doesn't treat 011 as octal)
}+         # See above
3,/        # Run the block for idx = 0, 1, 2
           # Stack: _ n D p E q
1$4$*      # Stack: _ n D p E q D*E
]-1%~;     # Stack: D*E q E p D n
*+*+       # Stack: D*E q+E*(p+D*n)
].~        # Stack: [denom' num'] denom' num'
{.@\%.}do; # Stack: [denom' num'] gcd
{/}+/      # Stack: denom num
'/'@       # Stack: num '/' denom

Demo online yang mensimulasikan menjalankan program dengan masing-masing input tes, satu per satu.

Peter Taylor
sumber
Saya mencobanya, dan tampaknya tidak mengikuti semua aturan: "Perhatikan bahwa penghentian desimal tidak akan memiliki apa-apa setelah titik kedua, dan desimal tanpa bagian desimal yang berulang tidak akan memiliki apa pun di antara dua titik." Saya tidak dapat membuat kode Anda berfungsi dengan input menjadi0.1.
Thomas Baruchel
-1. Saya mencoba lagi di lain waktu setelah menyadari Anda mendapat +300 poin. Itu tidak adil, karena solusi lain telah melakukan yang terbaik untuk mengikuti semua aturan, yang jelas Anda belum lakukan.
Thomas Baruchel
@ ברוכאל, saya keberatan dengan pernyataan Anda bahwa saya belum mencoba mengikuti aturan. Posisi kasus uji opsional membingungkan saya untuk berpikir bahwa blok terakhir mencakup semua kasus yang diperlukan; ternyata saya salah, dan saya akan segera mengedit pertanyaan untuk menghindari orang lain melakukan kesalahan yang sama. Saya sekarang telah memperbarui kode saya untuk menangani kasus sudut yang sebelumnya tidak ditangani, dan memperbarui tautan saya ke tes untuk menunjukkan itu.
Peter Taylor
tidak apa-apa. Anda mungkin berhak mendapatkan 300 poin. Menjadi orang baru di CodeGolf, 300 poin ini adalah target yang menantang bagi saya, dan saya masih kecewa karena tidak mendapatkannya sementara saya masih berpikir bahwa pada batas waktu kode saya adalah yang terpendek agar sesuai dengan aturan. Ngomong-ngomong, saya memiliki seluruh hidup saya untuk poin kemenangan. Salam.
Thomas Baruchel
@ ברוכאל: Saya ingin memulai 500 poin (ya, saya murah hati seperti itu, bukan karena saya tidak bisa memberi lebih sedikit) hadiah, dan memberi Anda poin itu, tapi saya kira sudah ada karunia yang dimulai. Yah, terserahlah. Saya bertanya-tanya kapan karunia ini akan berakhir, dan siapa yang akan mendapatkan poin itu.
Konrad Borowski
2

Python

Tanpa perpustakaan - 156 karakter

_=lambda a,b:b and _(b,a%b)or a;a,b,c=raw_input().split('.');d,e=int(a+b+c)-bool(c)*int(a+b),
(10**len(c)-bool(c))*10**len(b);f=_(d,e);print'%i/%i'%(d/f,e/f)

Menggunakan fractions- 127 karakter

from fractions import*;a,b,c=raw_input().split('.');print Fraction(int(a+b+c)-bool(c)*int(a+b
),(10**len(c)-bool(c))*10**len(b))
Oberon
sumber
The fractionsVersi cetak hal-hal seperti "Fraksi (7, 5)" bukan "7/5", bukan?
Omar
Tidak; Ngomong-ngomong, aku tidak membuat yang teratas berfungsi. _=lambda a,b:b and _(b,a%b)or a;a,b,c=raw_input().split('.');d,e=int(a+b+c)-bool(c)*int(a+b), ValueError: need more than 1 value to unpack
tommeding
@ OmarAntolín-Camarena AFAIK, printgunakan strsaat tersedia, tidak repr. Ini adalah hasil akhir saya: puu.sh/7w64w.png
Oberon
@tommeding Keduanya dalam satu baris; jeda baris ditambahkan untuk membuatnya sesuai dengan jawaban. _=lambda a,b:b and _(b,a%b)or a;a,b,c=raw_input().split('.');d,e=int(a+b+c)-bool(c)*int(a+b),(10**len(c)-bool(c))*10**len(b);f=_(d,e);print'%i/%i'%(d/f,e/f)harus masuk semua dalam satu baris.
Oberon
Oh benar, @ Oberon, karena Anda mungkin bisa menebak saya tidak di komputer saya dan tidak bisa menjalankan kode.
Omar
2

Mathematica, 143

Seperti biasa, Mathematica menawarkan banyak fungsi tingkat tinggi untuk melakukan pekerjaan itu, tetapi memberi mereka nama verbal.

x=StringTake;c=ToExpression;p=s~StringPosition~".";{o,t}=First/@p;u=StringLength@s-t;d=t-o-1;Rationalize@(c@x[s,t-1]+c@x[s,-u]/((10^u)-1)/10^d)

Output sampel untuk ditambahkan nanti ketika saya punya waktu.

Jonathan Van Matre
sumber
Sepertinya saya ini menghasilkan bilangan bulat sebagai n, bukan n / 1. Apakah itu benar? (Solusi saya memiliki bug yang sama ... :()
Omar
Ah, sekarang saya melihat .... ditentukan dalam komentar. Apa persyaratan yang aneh ... jika setiap fraksi lain berkurang, mengapa tidak dibiarkan n/1berkurang n? Saya akan menambahkan ekstra ~ 50 byte untuk mengkonversi bilangan bulat nanti.
Jonathan Van Matre
Pendekatan Anda baik-baik saja. Milik saya memanfaatkan FromDigitsjadi saya memutuskan untuk mempostingnya juga.
DavidC
2

Ruby - 112

x,y,z=gets.chop.split".";y||='0';z||='0';puts((y.to_i+Rational(z.to_i,10**z.length-1))/10**y.length+x.to_i).to_s

Ini adalah eksperimen pertama saya dengan ruby, jadi silakan menyarankan perbaikan.

$ ruby20 % <<< '5.3.87'
889/165
$ ruby20 % <<< '0..3'
1/3
$ ruby20 % <<< '0.0.3'
1/30
$ ruby20 % <<< '0.00.3'
1/300
$ ruby20 % <<< '0.6875.0'
11/16
$ ruby20 % <<< '1.8.0'
9/5
$ ruby20 % <<< '2..'
2/1
$ ruby20 % <<< '..'
0/1
mniip
sumber
Menghapus dukungan ".. 'dan" .1.2 "berarti Anda tidak mengikuti spesifikasi, bukan? (Saya lebih suka menghapusnya juga.)
Omar
@ OmarAntolín-Camarena Pada titik tertentu, spec mengatakan If you wish,. Saya tidak berharap, jadi saya tidak mendukung pecahan tanpa kelompok angka 1 atau 3. Namun saya mendukung pecahan yang tidak memiliki kelompok digit kedua, yang cocok dengan spesifikasi.
mniip
@minip, Anda salah membaca spek: ia tidak mengatakan "jika Anda berharap dapat mendukung .. dan .1.2", katanya, "jika Anda mau, Anda dapat berasumsi bahwa 0 .. dan 0.1.2 selalu diberikan sebagai .. dan .1.2 "
Omar
@ OmarAntolín-Camarena Point diambil. Diedit.
mniip
2

C, 164

Ini mirip dengan solusi C orion, meskipun saya melakukannya dari awal. Namun saya akui mencuri sejumlah optimasinya. Ini tidak jauh lebih pendek, tetapi menangani 0,25. = 1/4 dan 0.000000.1 = 1/9000000.

long a,b,c,d,e;main(){while((c=getchar()-48)>-3)c+2?a=a*10+c,b*=10:b?e=a,d=b:(b=1);
b>d?a-=e,b-=d:0;for(d=2;d<=a;)a%d+b%d?d++:(a/=d,b/=d);printf("%ld/%ld\n",a,b);}
Florian F
sumber
2

Dua jawaban python tidak menggunakan pustaka. Pertama menangani input opsional tanpa digit sebelum yang pertama. dan 162 karakter

_=lambda a,b:b and _(b,a%b)or a;i,t,r=raw_input().split(".");b=r!="";d=(10**len(r)-b)*10**len(t);n=int((i+t+r)or 0)-b*int((i+t)or 0);f=_(d,n);print "%i/%i"%(n,d)

Kedua tidak menangani apa-apa sebelum digit pertama tetapi menangani semua input yang diperlukan dengan benar dan 150 karakter

_=lambda a,b:b and _(b,a%b)or a;i,t,r=raw_input().split(".");b=r!="";d=(10**len(r)-b)*10**len(t);n=int(i+t+r)-b*int(i+t);f=_(d,n);print "%i/%i"%(n,d)
tangga27
sumber
2

Haskell

import Data.Ratio
f n=case s '.' n of
    [x,y,z]->(r x)%1+(r y)%(10^(length y))+(r z)%((10^t-1)*(10^(length y)))
        where
            r ""=0
            r n=read n
            t = if length z==0 then 9 else length z
s _ []=[[]]
s n (x:xs) | x==n = []:(s n xs)
           | otherwise = let (l:ls)=s n xs in (x:l):ls
PyRulez
sumber
Hei, ini kode-golf, Anda bahkan tidak mencoba!
mniip
@ mniip Saya tidak pandai kode golf. Atleast saya menggunakan nama variabel karakter tunggal.
PyRulez
1
Anda tidak pernah menentukan bahasa atau jumlah total karakter / byte yang digunakan.
Justin Fay
2
Gunakan {;} untuk menghemat ruang pada indentasi, spanuntuk mengimplementasikan, menambahkan alias pendek untuk fungsi, menghapus ruang jika memungkinkan. import Data.Ratio v=span(/='.');w=tail;l=length;f n=(r x)%1+(r y)%p+(r z)%((10^t-1)*p)where{(x,b)=v n;(y,d)=v(w b);z=w d;p=10^(l y);r""=0;r n=read n;t=if null z then 9 else l z}- 178 karakter, turun dari 321. NB Trueadalah sinonim untuk otherwise, null zadalahlength z==0
bazzargh
2

JavaScript (ECMASCript 6) 180 175

G=(a,d)=>d?G(d,a%d):a;P=a=>+("1e"+a);L=a=>a.length;f=prompt().split(".");B=P(L(b=f[1]));D=P(L(b)+L(c=f[2]))-P(L(b))||1;alert((m=(f[0]+b||0)*D+B*(c||0))/(g=G(m,n=B*D))+"/"+n/g)

Meskipun ini bukan pemenang yang jelas untuk 300 karunia ... ini adalah yang terpendek yang bisa saya buat:

  • Perubahan dari versi sebelumnya: sedikit perubahan pada logika, dan perubahan pada Pfungsi Power dengan mengubahnya untuk +("1e"+a)bukannya Math.pow(10,a)menyimpan beberapa karakter ...
WallyWest
sumber
1

Mathematica 175

f@i_:=
If[IntegerQ[g=FromDigits[Map[IntegerDigits@ToExpression@#&,StringSplit[i,"."]/.""-> {}]
/.{a_,b_,c_}:> {{Sequence@@Join[a,b],c},Length@a}]],HoldForm[Evaluate@g]/HoldForm@1,g]

Sebagian besar rutinitas dilakukan untuk memijat input. Sekitar 50 karakter digunakan untuk menangani bilangan bulat.


Contohnya

f["7801.098.765"]

frac1

Lebih banyak contoh:

TableForm[
 Partition[{#, f[#]} & /@ {"19..87", "19.3.87", "5.3.87", "0.0.3", "0..3", "0.2.283950617", 
"123.456.789", "6666.7777.8888", "2.0.0","0.0.0"}, 5], TableSpacing -> {5, 5}]

frac2


Bagaimana hal itu biasanya dicapai dalam Mathematica

FromDigitsdapat memperoleh sebagian kecil dari desimal berulang berulang, asalkan input dari bentuk tertentu. Bilangan bulat ditampilkan sebagai bilangan bulat.

z={{{1, 9, {8, 7}}, 2}, {{1, 9, 3, {8, 7}}, 2}, {{5, 3, {8, 7}}, 1}, {{{3}}, -1}, {{{3}}, 0}, 
{{2, {2, 8, 3, 9, 5, 0, 6, 1, 7}}, 0}, {{1, 2, 3, 4, 5, 6, {7, 8, 9}}, 3}, 
{{6, 6, 6, 6, 7, 7, 7, 7, {8}}, 4}, {{2}, 1}, {{0}, 1}}

FromDigits/@z

z

DavidC
sumber
Output Anda dalam format yang salah, terlalu cantik.
Omar
Anehnya, ini adalah format default untuk mengekspresikan fraksi di Mathematica. Diperlukan beberapa karakter lagi untuk mengubah format ini ke format yang lebih sederhana.
DavidC
1

J (96 karakter)

Saya tidak menggunakan simbol garis miring sebagai pemisah (tetapi solusi dalam Mathematica juga tidak karena ia menggunakan representasi grafis yang lebih baik); dalam bahasa J fraksi ditampilkan dengan rsebagai /:

   (((-.@]#[)((".@[%#@[(10x&^)@-{.@])+({.@](10x&^)@-#@[)*<:@{:@](".%<:@(10x&^)@#)@}.[)I.@])(=&'.')) '1..3'
4r3
   (((-.@]#[)((".@[%#@[(10x&^)@-{.@])+({.@](10x&^)@-#@[)*<:@{:@](".%<:@(10x&^)@#)@}.[)I.@])(=&'.')) '123.456.789'
41111111r333000
Thomas Baruchel
sumber
1

APL (tidak sepenuhnya umum)

Tidak sepenuhnya umum (seperti solusi saya untuk dc); bekerja dengan Dyalog APL (tetapi tidak pada versi online Dyalog APL, tidak yakin mengapa):

(R,F)÷(F←D×N)∨R←(⍎C)+D×(⍎I/⍨2>+\P)×N←10*¯1++/≠\P⊣D←¯1+10*⍴C←1↓I/⍨2=+\P←'.'=I← '123.456.789'

Bidang pertama adalah opsional, tetapi setidaknya satu digit diperlukan untuk kedua bidang lainnya.

Thomas Baruchel
sumber
1

JavaScript (189)

i=prompt().split(".");a=i[0];b=i[1];c=i[2];B=b.length;p=Math.pow;n=a+b+c-(a+b);d=p(10,B+c.length)-p(10,B);f=1;while(f){f=0;for(i=2;i<=n;i++)if(n%i==0&&d%i==0){n/=i;d/=i;f=1}};alert(n+"/"+d)

Contoh:

Memasukkan:

5.3.87

Keluaran:

889/165
kitcar2000
sumber
1

C (420 karakter seperti yang tertulis; lebih sedikit setelah menghapus spasi yang tidak perlu)

Perhatikan bahwa ini mengasumsikan 64-bit long(mis. 64 bit Linux); itu akan gagal untuk kasus uji 0.2.283950617pada sistem menggunakan 32-bit long. Ini dapat diperbaiki dengan mengorbankan beberapa karakter dengan mengubah jenisnya long longdan mengubah printfformat string yang sesuai.

#include <stdio.h>

long d[3], n[3], i;

int main(int c, char** v)
{
  while (c = *v[1]++)
    switch(c)
    {
    case '.':
      n[++i] = 1;
      break;
    default:
      d[i] = 10 * d[i] + c - '0';
      n[i] *= 10;
    }

  n[2] -= n[2] != 1;

  while (i--)
    d[2] += d[i] * n[i+1], n[i]*=n[i+1];

  i = d[2];
  *n = n[1];

  while (i)
    *d = i, i = *n%i, *n = *d;
  printf("%ld/%ld\n", d[2]/ *n, n[1]/ *n);
}
celtschk
sumber
Bagus. Anda dapat mencukur 1 karakter dengan mengubah '0'ke 48.
Todd Lehman
Saya pikir Anda juga bisa menyimpan lebih banyak dengan menulis ulang switchpernyataan sebagai if(c==46) n[++i]=1; else d[i]=10*d[i]+c-48,n[i]*=10;.
Todd Lehman
-3

GTB , 81

`_:s;_,1,l?_)-S;_,"."
s;A;,1,S;_,".")-1
s;_,1+S;_,"."),l?_)-S;_,"."))→_
x?A;+_)►Frac

Contoh

?3.25.
            13/4
Timtech
sumber
4
Sampai kompiler tersedia secara bebas untuk bahasa ini, saya akan mencatat setiap jawaban yang menggunakannya.
Gareth
1
Tampaknya ada kompiler pada halaman yang ditautkan di atas?
skibrianski
@skibrianski Lihat posting ini di meta
mniip
2
@ Gareth, ada beberapa jawaban Mathematica bagi Anda untuk downvote juga. : P
Omar
2
@ OmarAntolín-Camarena Ada kompiler / juru bahasa untuk Mathematica. GTB tidak memilikinya. Ikuti GTBtautan di atas jika Anda tidak percaya kepada saya. Anda akan mendapatkan beberapa barang terkompresi untuk program berpemilik, kemudian Anda akan mencari program itu dan menemukan bahwa situs yang mengklaim menyediakan unduhan mengatakan itu tidak tersedia. Jadi bagaimana kita mengkompilasinya?
Gareth