Stern-Brocot ağacında bir kesirin konumunu bulun


11

Stern-Brocot ağaç her bir fraksiyon, yukarıda seviyeleri içinde komşu iki bileşenden numerators ve paydası ekleyerek elde edilir fraksiyonların bir ikili ağaçtır.

"Son nokta kesirleri" ile başlayarak 0/1ve 1/0oradan başlayarak ve oradan, bu kesirlerin pay ve paydalarını birbirine ekleyerek birbirini izleyen her kesir çifti arasına bir kesir yerleştirerek tekrarlanır:

0.  0/1                                                             1/0
1.  0/1                             1/1                             1/0
2.  0/1             1/2             1/1             2/1             1/0
3.  0/1     1/3     1/2     2/3     1/1     3/2     2/1     3/1     1/0
4.  0/1 1/4 1/3 2/5 1/2 3/5 2/3 3/4 1/1 4/3 3/2 5/3 2/1 5/2 3/1 4/1 1/0

Stern-Brocot ağacı (her tekrarında ninci yineleme) vardır, 2^n + 1biz bir kısmını atfedebilecekleri hangi sırayla elemanları, 0/2^niçin 2^n/2^n. Her yeni yineleme, birbirini izleyen her fraksiyon çifti arasına bir "fraksiyon" ekler.

Bu, Stern-Brocot ağacını pozitif rasyonel sayılar ve 0 ve 1 arasındaki ikili kesirler arasında bire bir eşleme yapar, böylece iki setin aynı kardinaliteye sahip olduğuna dair bir kanıt görevi görür.

Göreviniz, pozitif bir rasyonel sayının pay ve paydası göz önüne alındığında, o kesirin Stern-Brocot ağacındaki konumuna karşılık gelen ikili kesiri belirleyen bir program veya işlev yazmaktır.

Giriş ve çıkış örnekleri aşağıda verilmiştir:

2/3 -> 3/8   (4th number in iteration 3)
4/7 -> 9/32  (between 1/2 and 3/5 in the chart above)
1/1 -> 1/2   (middle number in the first iteration)

Desteklemeniz gerekmeyen, ancak referans olarak dahil edilen girdiler:

0/1 -> 0/1   (0/1 is considered the left number)
1/0 -> 1/1   (1/0 is considered the rightmost number)

Bu hedefe ulaşmak için herhangi bir dilde en kısa program kazanır.


Herhangi bir giriş / çıkış gereksinimi var mı? Örneğin sadece bir işlev referans çözümünüzde olduğu gibi yeterli mi yoksa bağımsız bir program mı olması gerekiyor? Kesir çıktı biçimi önemli mi?
Darren Stone

Bir işlev yeterlidir. Sorun açıklamasında bunu daha açık hale getireceğim.
Joe Z.

Bunu düşünmek benim için biraz geç; Muhtemelen yarın açıklığa kavuşturmaya çalışacağım.
Joe Z.

2
Tamam, aklınızdaki bijection, ağaçtaki her derinliğe soldan 2 ^ (derinlik + 1) ve 1, 3, 5, 7, ... payları atamaktır.
Peter Taylor

1
Bunu oluşturmak için bir alternatif yol 1 de genişliği birinci sıra çalıştırma ağacının düğümleri (yani birinci sayıya olan 1/1 => 1, 1/2 => 2, 2/1 => 3, 1/3 => 4, vs.). Bir düğüm için bu şekilde oluşturulan sayı ise n, 2^lg n(ikili günlük) ayarlanan en yüksek bittir nve istenen ikili kesirdir (2*(n - 2^lg n) + 1) / 2^(lg n + 1). (En yüksek set-bit'i içeren bir komut setinde bir montajcı çözümü deneyen herkes muhtemelen bu yaklaşımı kullanmak isteyecektir).
Peter Taylor

Yanıtlar:


1

GolfScript ( 49 48 46 karakter)

{0\@{}{@2*2$2$>!+@@{{\}3$)*}:j~1$-j}/\)\,?}:f;

veya

{0:x;\{}{.2$<!2x*+:x){\}*1$-{\}x)*}/x@)@,?}:g;

Her ikisi de yığındaki pay ve paydayı alan ve pay ve paydayı yığında bırakan işlevlerdir. Çevrimiçi demo .

Ana fikir, Beton Matematiği bölüm 4.5'teki sözde kodda ifade edilmiştir (sürümümde p122):

while m != n do
    if m < n then (output(L); n := n - m)
             else (output(R); m := m - n)

Ls ve Rs dizeleri L = 0 ve R = 1 ile ikili bir değer olarak yorumlanırsa, bu değerin iki katı artı bir paydır ve payda bir bit daha uzundur.

Golfscripters için bir ilgi noktası olarak, bu açılımlı yararlı bulduğum nadir olaylardan biridir. (Tamam, sadece döngü sayacı olarak kullanıyorum, ama bu hiç yoktan iyidir).


1

Mathematica 130 114 111 karakter

f=#~g~0&;0~g~q_=q;p_~g~q_:=g[#,(Sign[p-#]+q)/2]&@FromContinuedFraction[ContinuedFraction@p/.{x___,n_}:>{x,n-1}]

Misal:

f[2/3]

3/8

f[4/7]

9/32

f[1]

1/2


1

Yakut, 132 125

@JoeZ referans çözümünü rubied & golfed.

def t(n,d)u=k=0;v,j,f,g,b=[1,]*5;c=2
while(z=(f*d).<=>(g*n))!=0;z>0?(j,k=f,g):(u,v=f,g);b=b*2-z;f,g=u+j,v+k;c*=2;end
[b,c]end

Kullanım örnekleri:

>> t(2,3)
=> [3, 8]
>> t(4,7)
=> [9, 32]
>> t(1,1)
=> [1, 2]

1

Ruby (69 karakter) CoffeeScript (59 karakter)

Bu, pay ve paydayı bağımsız değişken olarak alan ve bijection'dan sonra pay ve paydayı içeren bir dizi döndüren bir işlevdir.

g=(a,b,x=0,y=1)->c=a>=b;a&&g(a-b*c,b-a*!c,2*x+c,2*y)||[x,y]

Çevrimiçi demo

Yukarıdaki GolfScript çözümümle aynı yaklaşımı kullanıyor, ancak bir diziye boks ve kutudan çıkma konusunda endişelenmeden 4 değişken kullanabileceğim için çok daha okunabilir. CoffeeScript'i seçtim çünkü değişkenleri öneksizleştirmez $(örneğin PHP üzerinde kaydedilmiş 20 karakter), varsayılan parametre değerlerine izin veren kısa işlev tanımı sözdizimine sahiptir (bu nedenle f(a,b,x,y)bir işlevi sarmaya gerek yoktur g(a,b) = f(a,b,0,1)) ve Booleans'i tamsayı olarak kullanmama izin verir faydalı değerlere sahip ifadeler. Bunu bilmeyenler için, CoffeeScript'in standart C tarzı üçlü operatörü ( C?P:Q) yoktur, ancak C&&P||Qburada yerini Palamıyorum çünkü asla sahte olmayacak.

Tartışmasız daha zarif, ama tartışmasız daha az kısa bir alternatif, tekrarlanan çıkarma işlemini bölme ve modulo ile değiştirmektir:

f=(a,b,x=0,y=1,p=0)->a&&f(b%a,a,(x+p<<b/a)-p,y<<b/a,1-p)||[x+p,y]

(65 karakter; çevrimiçi demo ). Bu şekilde yazmak Öklid algoritması ile olan ilişkisini ortaya koyar.


Etrafında a<bbir karakter kazandıran parantez gerekmez . Inlining ciki tane daha verir. Ayrıca f=->a,b,x=0,y=1{...}daha kısa tanım için sözdizimini de düşünebilirsiniz .
Howard

@Howard, hangi Ruby sürümünü kullandığınızı bilmiyorum, ancak IDEOne üzerinde bu parantezleri kaldırmayı veya bu işlev sözdizimini kullanmayı denediğimde bir sözdizimi hatası alıyorum.
Peter Taylor

c=a<b ?Sonra fazladan bir alan deneyin b. Aksi takdirde, soru işareti b.
Howard

0

Python - 531

Son yer referans çözümü olarak hizmet etmek için Python'da çözülmemiş bir çözüm:

def sbtree(n, d): 
    ufrac = [0, 1]
    lfrac = [1, 0]
    frac = [1, 1]
    bfrac = [1, 2]
    while(frac[0] * d != frac[1] * n): 
        if(frac[0] * d > frac[1] * n): 
            # push it towards lfrac
            lfrac[0] = frac[0]
            lfrac[1] = frac[1]
            bfrac[0] = bfrac[0] * 2 - 1 
        elif(frac[0] * d < frac[1] * n): 
            # push it towards ufrac
            ufrac[0] = frac[0]
            ufrac[1] = frac[1]
            bfrac[0] = bfrac[0] * 2 + 1 
        frac[0] = ufrac[0] + lfrac[0]
        frac[1] = ufrac[1] + lfrac[1]
        bfrac[1] *= 2
    return bfrac

Herhangi bir iki fraksiyonun medyantının her zaman bu iki fraksiyonun değerleri arasında olacağı gerçeğinden faydalanarak, kesirler arasında ikili bir arama yapar .


0

GolfScript, 54 karakter

'/'/n*~][2,.-1%]{[{.~3$~@+@@+[\]\}*].2$?0<}do.@?'/'@,(

Giriş, STDIN'de görevde belirtilen biçimde verilmelidir. Kodu çevrimiçi deneyebilirsiniz .

> 4/7
9/32

> 9/7
35/64

> 5/1
31/32

0

Mathematica 138

Alephalpha'nın prosedürü kadar akıcı değil, ama şimdiye kadar üretebildiğim en iyisiydi.

q_~r~k_:=Nest[#+Sign@k/(2Denominator@# )&,q,Abs@k]  
g@d_:=
Module[{l=ContinuedFraction@d,p=-1},
l[[-1]]-=1;
(p=-p;# p)&/@l]
h[q_]:=Fold[r,1/2,g@q]

Test yapmak

h[2/3]
h[4/7]
h[1]

3/8
9/32
1/2


0

JavaScript 186

f=(p1,q1,p2,q2)=>{if(p1*q2+1==p2*q1){return{p:p1+p2,q:q1+q2}}let p,q,pl=0,ql=1,ph=1,qh=0;for(;;){p=pl+ph;q=ql+qh;if(p*q1<=q*p1){pl=p;ql=q}else if(p2*q<=q2*p){ph=p;qh=q}else return{p,q}}}

daha az olabilir, ama okunabilir golf severim


0

Haskell , 125 bayt

n((a,b):(c,d):r)=(a,b):(a+c,b+d):n((c,d):r)
n a=a
z=zip[0..]
t x=[(j,2^i)|(i,r)<-z$iterate n[(0,1),(1,0)],(j,y)<-z r,x==y]!!0

Çevrimiçi deneyin!

Bir çift şeklinde giriş ve çıkış (n,d).

Kısa açıklama:

nher kesir çiftine bakarak ve yeni kesiti ilk ve özyineleme arasına ekleyerek bir önceki satırdan sonraki satırı oluşturur (ikinci kesri oraya koyar). Temel durum çok basittir çünkü temelde sadece kimlik işlevi. tFonksiyon süresiz iki sınır fraksiyonları ile başlangıç durumuna kapalı tabanlı bu işlevi dolaşır. tardından her satırı ( i) ve satırdaki ( ) her öğeyi dizine ekler ve jaradığımızla eşleşen ilk kesri arar. jBulduğunda pay ve payda olarak verir 2^i.

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.