En yakın kesir


24

Görev:

Programınıza biçiminde uygun , pozitif basit bir kesir verilir <numerator>/<denominator>.

Bu girdi için iki kesir bulması gerekir.

  1. Girdiden daha az olan bir kesir.
  2. Girişten daha büyük bir kesir.

Her iki fraksiyon girdiden daha düşük bir paydaya sahip olmalıdır. Tüm olası kesirler arasında, girişe göre en düşük fark bulunmalıdır.

Çıktı:

Programınızın çıktısı şöyle olmalıdır:

  • Girdiden daha küçük bir kesir, biçiminde <numerator>/<denominator>.
  • Boşluk karakteri izler (ASCII kodu 32).
  • Ardından, girdiden daha büyük olan bir kesimi, formatta izleyin <numerator>/<denominator>.

Aşağıdaki gibi:

«fraction that is < input» «fraction that is > input»

Kurallar:

  • Çıktılan tüm kesirler en düşük durumda olmalıdır .
  • Çıktılan tüm kesirler uygun kesirler olmalıdır.
  • Kuralların izin verdiği uygun kesirler yoksa, 0kesir <giriş 1yerine ve kesir> giriş yerine çıktı vermelisiniz .
  • Kesiri komut satırı argümanı (örn. yourprogram.exe 2/5) Olarak mı yoksa kullanıcı girişi için mi istemek istediğinizi seçebilirsiniz .
  • Programınızın geçersiz girdi almadığını varsayabilirsiniz.
  • En kısa kod (bayt cinsinden, herhangi bir dilde) kazanır.
  • Standart olmayan herhangi bir komut satırı argümanı (normalde bir komut dosyasını çalıştırmak için gerekli olmayan argümanlar) toplam karakter sayımına sayılır.

  • Programınızın yapmaması gerekenler:

    • Herhangi bir dış kaynağa bağlı.
    • Belirli bir dosya adına sahip olmanıza bağlı.
    • İstenilen çıktıdan başka bir şey çıktılayın.
    • Koşması çok uzun sürüyor. Programınız, 179565/987657ortalama bir ev kullanıcısının bilgisayarında 6 basamaklı numaralayıcı ve payda (örn. ) Bulunan kesirler için bir dakikadan fazla çalışıyorsa geçersizdir.
    • 0Payda olarak çıktı kesirleri . Sıfır ile bölemezsiniz.
    • 0Pay olarak fraksiyonları çıkar . Programınız 0kesir yerine çıktı almalıdır .
    • Girilen kesri azaltın. Girdi olarak verilen kısım indirgenebilir ise, girilen kısmı kullanın.
  • Programınız, bu zorluk yüklenmeden önce halka açık bir derleyici / tercüman bulunmadığı bir programlama dilinde yazılmamalıdır.

Örnekler:

Giriş: 2/5
Çıkış: 1/3 1/2

Giriş: 1/2
Çıkış: 0 1

Giriş: 5/9
Çıkış: 1/2 4/7

Giriş: 1/3
Çıkış: 0 1/2

Giriş: 2/4
Çıkış: 1/3 2/3

Giriş: 179565/987657
Çıkış: 170496/937775 128779/708320


1
İlk örneğiniz belirtimle uyuşmuyor: Her iki kesir de girişten daha küçük bir paydaya sahip olmalıdır.
Howard,

1
İlk örnek, çıktı olmalıdır 1/3 1/2.
Heiko Oberdiek

@HeikoOberdiek Haklısın. Sabit.
user2428118

1
"Ortalama ev kullanıcısı bilgisayarı" tanımlayın. 1.6GHz Intel Atom makinesinde 90 saniye kabul edilebilir mi?
John Dvorak

2
Son örneğiniz yanlış. Giriş kesri, çıkış kesirlerinin birincisine eşittir.
DavidC

Yanıtlar:


3

Adaçayı - 119 117

x,X=map(int,raw_input().split('/'))
a=0
A=c=C=1
while C<X:exec("ab,,AB"[c*X>C*x::2]+"=c,C");c=a+b;C=A+B
print a/A,b/B

Adaçayı, yalnızca çıktıyla ilgilenen son satırda gereklidir. Diğer her şey Python'da da çalışır.

Değiştir raw_input()ile sys.argv[1]giriş yerine bir istem bir komut satırı argümanı okunan etmiş. Bu karakter sayısını değiştirmez. ( sysÖnce içe aktarmadan Python'da çalışmaz .)

Bu, esasen özyinelemeyle , mevcut elemanların aracılarını kullanarak ilgili Farey sırasını oluşturur, ancak kendisini girdiye en yakın olan elemanlarla sınırlandırır. Başka bir bakış açısından, ilgili Farey dizileri üzerinde iç içe aralıklı bir arama gerçekleştirir.

Makinemdeki tüm örnekleri bir saniyeden daha kısa sürede doğru şekilde işler.

İşte bir ungolfed versiyonu:

x,X = map(Integer,sys.argv[1].split('/'))
x = x/X
a = 0
c = b = 1
while c.denominator() < X:
    if c > x:
        b = c
    else:
        a = c
    c = ( a.numerator() + b.numerator() ) / ( a.denominator() + b.denominator() )
print a,b

Zaten bu ödül için herhangi bir yeni sunum alamayacağımdan korktum. Harika iş.
user2428118

Güzel numara exec!
xnor

Ödül süresi içinde verilen tek cevap olarak, size ödülü vereceğim. Tebrikler.
user2428118

Sadece örneklerden birinde bir hatayı düzelttim . Gönderinizi düzeltmek isteyebilirsiniz (gönderdiğinizden bu yana yarım yıl geçmiş olsa bile).
user2428118

12

Python 2,7 - 138

x,y=n,d=map(int,raw_input().split('/'))
while y:x,y=y,x%y
def f(p,a=d):
 while(a*n+p)%d:a-=1
 print`(a*n+p)/d`+('/'+`a`)*(a>1),
f(-x);f(x)

Açıkça kaba kuvvet çözümüyle başladım, ancak OP'nin altı basamaklı sayıları ve paydaları olan örnekleri bir dakikadan daha kısa sürede çözmek istediğinden, trilyon olasılıkları denemekten daha iyi bir çözüme ihtiyacım olduğunu fark ettim. Farey dizisi için Wikipedia sayfasında kullanışlı bir formül buldum: a / b, c / d, Farey dizilerinden birinde komşularsa a/b<c/d, o zaman ile b*c-a*b=1. Programımdaki f içindeki while döngüsü, bu gerçeği, loop yaparken hesapladığı gcd kullanarak, azaltılmamış numaralara genişletir.

Bunu çok zor bir şekilde golf oynadım, ancak önerilerinizi duymak isterim.

Düzenlemeler:

166-> 162: Kaldırıldı ave bdış programdan. Gereksizlerdi.
162-> 155: str()-> `
155-> 154: Eklendi k.
154-> 152: xFonksiyonun içinden çıkarıldı, yerine bir argüman olarak geçti.
152-> 150: Bağımsız adeğişken olarak geçirmek yerine varsayılan bir değer verdi.
150-> 146: başlatma değiştirildi xve y.
146-> 145: Kaldırıldı k.
145-> 144: Değiştirildi ... ve ... veya ... ila (..., ...) [...], böylece yer tasarrufu sağlandı.
144-> 138: Değiştirildi (..., ...) [...] ila ... + ... * (...). @ Mbomb007 'e teşekkür ederiz.

Test durumları:

2/5
1/3 1/2

1/2
0 1

2/4
1/3 2/3

179565/987657
170496/937775 128779/708320

12345678/87654321
12174209/86436891 11145405/79132382

Sondan ikinci test bilgisayarımda bir saniye sürdü, sonuncusu ise yaklaşık 5-10 saniye sürdü.


Bu k=1saf kötülük.
Evpok

1
@Evpok: Çalışmak için k = y = n elde etmeye çalışıyordum, fakat görünüşe göre eğer bir fonksiyon içindeki bir değişkeni değiştirirseniz, python bunun yerel olmasını istiyor. Yerel bir değişkeni 4 karakterde almanın tek yolu buydu. Ayrıca, kesir pozitif ve düzgün olduğundan, payda 1 olamaz.
isaacg

Komut satırı argümanları Python ile kolaydır, bu nedenle burada belirtildiği şekilde girdi için kullanılmış olmaları gerekir.
Alex Thornton

1
" Kesiri komut satırı argümanı olarak almak isteyip istemediğinizi seçebilirsiniz (örn. Yourprogram.exe 2/5) veya kullanıcı girişi istemi ."
isaacg

6 karakterden print`(a*n+p)/d`+('/'+`a`)*(a>1),
tasarruf edin

5

Mathematica, 163 bayt

{a,b}=FromDigits/@InputString[]~StringSplit~"/";r=Range[b-1];""<>Riffle[#~ToString~InputForm&/@(#@DeleteCases[#2[a/b*r]/r,a/b]&@@@{{Max,Floor},{Min,Ceiling}})," "]

Bu, kullanıcı girişi ve dizeleri olarak giriş / çıkış gereksinimi ile ciddi şekilde sınırlandırılmıştır. İplerle uğraşmak Mathematica'da gerçekten zordur (en azından golf oynamak istediğinizde). Bunu Mathematica'da doğal bir şekilde yaparak, (sadece tamsayıları ve gerekçeleri kullanarak) büyük olasılıkla bunu% 50'ye düşürürdüm.

Makinemde birkaç saniyede 6 basamaklı sayılar yapabilir.

Biraz daha okunabilir (gerçekte asılsız değil):

{a, b} = FromDigits /@ InputString[]~StringSplit~"/";
r = Range[b - 1];
"" <> Riffle[#~ToString~
     InputForm & /@ (#[DeleteCases[#2[a/b*r]/r, a/b]] & @@@ {{Max, 
       Floor}, {Min, Ceiling}}), " "]

Bunun eğlencesi için, bu "doğal yolu" yapmak, yani pay ve payda almak ve iki rasyonel almak gibi bir işlev olarak, bu yalnızca 84 karakterdir (bu yüzden% 50'lik tahminim oldukça yakındı):

f[a_,b_]:=#@DeleteCases[#2[a/b*(r=Range[b-1])]/r,a/b]&@@@{{Max,Floor},{Min,Ceiling}}

3

Julia - 127 125 bayt

Döngüsel ihtiyaçtan kaçınmak için buna matematiksel bir perspektiften yaklaşmıştım, bu nedenle bu kod büyük girişler için oldukça hızlı çalışıyor (not: eğer a / b girişi ise, a * b Int64'e uymalıdır (32 bit sistemlerde Int32) aksi takdirde saçma cevaplar üretilir - a ve b'nin ikisi de Int32'de (32 bit sistemlerdeki Int16'da) açıksa, hiçbir sorun oluşmaz).

GÜNCELLEME: Artık div için ters eğik çizgiyi aşırı yüklemeye gerek yok, ÷ kullanarak, 2 baytlık bir net tasarruf sağlıyor.

a,b=int(split(readline(),"/"));k=gcd(a,b);f=b-invmod(a÷k,b÷k);d=2b-f-b÷k;print(a*d÷b,d<2?" ":"/$d ",a*f÷b+1,"/$f"^(f>1))

Ungolfed:

a,b=int(split(readline(),"/")) # Read in STDIN in form a/b, convert to int
k=gcd(a,b)           # Get the greatest common denominator
f=b-invmod(a÷k,b÷k)  # Calculate the denominator of the next biggest fraction
d=2b-f-b÷k           # Calculate the denominator of the next smallest fraction
print(a*d÷b,d<2?" ":"/$d ",a*f÷b+1,"/$f"^(f>1)) # Calculate numerators and print

Temel fikir: ad-bc = gcd (a, b) (sonraki en küçük) ve be-af = gcd (a, b) (sonraki en büyük) değerlerini karşılayan b'den en büyük d ve f'yi bulun, sonra c ve e'yi hesaplayın. Orada. Elde edilen çıktı, d veya f 1 olmadığı sürece c / de / f'dir, bu durumda / d veya / f ihmal edilir.

İlginç bir şekilde, bu, girişin bir tamsayı olmadığı sürece (yani, gcd (a, b) = a) olduğu sürece, kodun pozitif hatalı kesirler için de çalıştığı anlamına gelir.

Sistemimde, giriş 194857602/34512958303yapmak, çıkış için algılanabilir bir zaman gerektirmiyor171085289/30302433084 23772313/4210525219


İle test etmek 55552/999999bana verir -396/920632 486/936509.
user2428118

@ user2428118 - 32 bit sistemde misiniz (veya 32 bit Julia kullanıyorsanız)? "İnt" kullandım, yani 32 bit sistemde Int64 yerine Int32 kullanacak. int32(55552*999999)verir -282630400. Benim için, bu test ile anlıyorum 51143/920632 52025/936509- paydaların aynı olduğunu ve 52025-51143 = 486 - (- 396) olduğunu unutmayın. Bu konuyu belirtmek için bir not ekleyeceğim.
Glen O

Kodun tüm Int64 boyutlu girişler için çalışacağından emin olmak istiyorsanız, "int" yerine "int128" kullanabilirsiniz. Bu değişiklikle birlikte giriş 1234567891234567/2145768375829475878sonuçlanır 869253326028691/1510825213275018197 365314565205876/634943162554457681. Bu değişiklik sadece 3 ekstra karakter ekler.
Glen O

Evet, 32 bit bilgisayar kullanıyorum. Vakti geldiğinde bir ara 64-bit makinede deneyeceğim.
user2428118

64 bitlik bir bilgisayarda test yapmak doğru sonucu verir, bu yüzden bu cevabı kabul ediyorum.
user2428118

2

JavaScript, 131

Yağ ok gösterimi ve evalçağrıları ile:

m=>{for(e=eval,n=e(m),i=p=0,q=1;++i</\d+$/.exec(m);)if(n*i>(f=n*i|0))g=f+1,p=f/i>e(p)?f+'/'+i:p,q=g/i<e(q)?g+'/'+i:q;return p+' '+q}

179565/987657Stres testi yaklaşık çalıştırılır 35 saniye , Firefox üzerinde çok daha fazla Chrome'da (~ 6 dakika)

Hızlı yöntem ve evalyağsız ok notasyonu

for(n=eval(m=prompt(a=i=p=0,b=c=d=q=1));++i<m.match(/\d+$/);)if(n*i>(f=n*i|0))g=f+1,p=f*c>i*a?(a=f)+'/'+(c=i):p,q=g*d<i*b?(b=g)+'/'+(d=i):q;alert(p+' '+q)

179565/987657Stres testi yaklaşık 5 saniye içinde yürütülür.

Golf değil:

m=prompt(); //get input
a=0; c=1; //first fraction
b=1; d=1; //second fraction
n=eval(m); //evaluate input
for (i=1; i<m.match(/\d+$/); i++) { //loop from 1 to input denominator
  f=Math.floor(n*i);
  if (n*i > f) { //if fraction not equal to simplification of input
    g=f+1; // f/i and g/i are fractions closer to input
    if (f/i>a/c) a=f, c=i;
    if (g/i<b/d) b=g; d=i; 
  }
}
alert(a+'/'+c+' '+b+'/'+d); //output values handling 0 and 1 correctly

Çok ... çok ... eval. EEK
John Dvorak

3
İle test 2/6verir 1/3 2/5, ancak 1/3değil daha az ama hiç eşit 2/6 .
user2428118

@ user2428118 düzeltildi
Michael M.

Bu cevap neden bu kadar erken kabul edildi?
Evpok

1
@ user2428118: Biliyorsunuz, birkaç gün boyunca çözümleri kabul etmeden önce izin verebilirsiniz. Ayrıca, bu çözüm artık en kısası değil.
isaacg

2

perl, 142 bayt (155, CPAN olmadan)

use bare A..Z;$/="/";N=<>;D=<>;F=N/D;K=G=1;for$H(1..D){J<F&&J>E?(E,I):J>F&&J<G?(G,K):()=(J=$_/H,"$_/$H")for(Z=int F*H)..Z+1}print I||0," $K\n"

Veya CPAN modüllerine izin verilmezse / 3-4 kat daha hızlı kod gerekir:

$/="/";$N=<>;$D=<>;$F=$N/$D;$g=$G=1;for$d(1..$D){$f<$F&&$f>$E?($E,$e):$f>$F&&$f<$G?($G,$g):()=($f=$_/$d,"$_/$d")for($z=int$F*$d)..$z+1}print$e||0," $g\n"

Eski sürüm makinemde 9.55 saniye sürüyor, sonraki sürüm 2.44 saniye sürüyor.

Daha az okunamıyor:

($N, $D) = split(m[/], <>);
$F = $N / $D;
$G = 1;
foreach $d (1 .. $D) {
    $z = int $F * $d;
    foreach $_ ($z .. $z + 1) {
        $f = $_ / $d;
        ($f < $F && $f > $E ? ($E, $e) :
        ($f > $F && $f < $G ? ($G, $g) : ())) = ($f, "$_/$d");
    }
}
print $e || 0, ' ', $g || 1, "\n";
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.