Stern-Brocotシーケンスに従ってn番目の有理数を出力します


30

スターン- Brocot配列は Fibonnaci様配列次のように構成することが可能です。

  1. シーケンスを初期化する s(1) = s(2) = 1
  2. カウンターを設定 n = 1
  3. s(n) + s(n+1)シーケンスに追加する
  4. s(n+1)シーケンスに追加する
  5. インクリメントn、ステップ3に戻る

これは次と同等です:

s(n)= \ begin {cases} 1&\ textrm {if} n = 1 \ s(\ frac n 2)&\ textrm {if} n \ textrm {is even} \ s(\ frac {n-1 } 2)+ s(\ frac {n + 1} 2)&\ textrm {otherwise} \ end {cases}

他のプロパティの中でも、Stern-Brocotシーケンスを使用して、可能なすべての正の有理数を生成できます。すべての有理数は一度だけ生成され、常に最も単純な用語で表示されます。たとえば、1/3シーケンスの第四有理数、同等の数字である2/63/9などがまったく表示されません。

上記のように、n番目の有理数をとして定義できますr(n) = s(n) / s(n+1)。ここでs(n)は、n番目のStern-Brocot数です。

あなたの課題は、Stern-Brocotシーケンスを使用して生成されたn番目の有理数を出力するプログラムまたは関数を作成することです。

  • 上記のアルゴリズムは1から始まります。エントリのインデックスが0の場合は、回答に記載してください
  • 説明されているアルゴリズムは説明のみを目的としており、出力は任意の方法で導出できます(ハードコーディング以外)
  • 入力は、STDIN、関数パラメーター、またはその他の妥当な入力メカニズムを介して行うことができます
  • Ouptutは、STDOUT、コンソール、関数の戻り値、またはその他の妥当な出力ストリームになります。
  • 出力はの形式の文字列である必要がありますa/b。ここでaおよびbは、Stern-Brocotシーケンスの関連エントリです。出力前に端数を評価することはできません。たとえば、入力の12場合、出力はで2/5はなくである必要があり0.4ます。
  • 標準の抜け穴は許可されていません

これはなので、バイト単位の最短回答が勝ちます。

テストケース

ここでのテストケースは1から始まります。

n    r(n)
--  ------
1    1/1
2    1/2
3    2/1
4    1/3
5    3/2
6    2/3
7    3/1
8    1/4
9    4/3
10   3/5
11   5/2
12   2/5
13   5/3
14   3/4
15   4/1
16   1/5
17   5/4
18   4/7
19   7/3
20   3/8
50   7/12
100  7/19
1000 11/39

OEISエントリ:A002487
シーケンスについて説明している優秀なNumberphileビデオ:Infinite Fractions


出力でTruesの代わりに1sを使用できますか?
-Loovjo

1
@Loovjoいいえ、True/2有効な分数ではありません(私に関する限り)。余談ですTrueが、常にそうとは限りません。1一部の言語では、-1ビット演算子を適用する際の潜在的な間違いを避けるために代わりに使用します。[要出典]
ソク


2
@Sokの引用
mbomb007

1
@Sokですが、Pythonでは、Trueと同等で1、にTrue/2なります1/2
リーキー修道女

回答:


3

ゼリー、14バイト

3ẋḶŒpḄċ
’Ç”/⁸Ç

オンラインでお試しください!

ああ、@ Dennisが受け入れた答えを、同じ言語で打ち負かすことができるようです。これは、OEISの数式を使用して機能します。ハイパーバイナリ(つまり、数字として0、1、2のバイナリ)で表現する方法の数(数-1)。ほとんどのJellyプログラム(完全なプログラムまたは関数のいずれかとして機能する)とは異なり、このプログラムは完全なプログラムとしてのみ機能します(出力の一部をstdoutに送信し、残りを返すためです;完全なプログラムとして使用される場合、戻り値暗黙的にstdoutに送信されるため、すべての出力は同じ場所にありますが、これは関数の送信では機能しません)。

このバージョンのプログラムは非常に非効率的です。最初の行の直後にnを配置することで、最大2 allまでのすべての入力に対して機能するはるかに高速なプログラムを作成できます。プログラムのパフォーマンスはO(n ×3ⁿ)であるため、ここではnを小さく保つことが非常に重要です。書かれているプログラムは、nを入力に等しく設定します。これは明らかに十分に大きいですが、ほとんどすべての場合に明らかに大きすぎます(ただし、バイトを節約します)。

説明

私のJellyの説明でいつものように、中括弧内のテキスト(例{the input})は、元のプログラムのオペランドが欠落しているためにJellyによって自動的に埋められたものを示しています。

ヘルパー関数n番目の分母、つまりn +1番目の分子を計算):

3ẋḶŒpḄċ
3ẋ       3, repeated a number of times equal to {the argument}
  Ḷ      Map 3 to [0, 1, 2]
   Œp    Take the cartesian product of that list
     Ḅ   Convert binary (or in this case hyperbinary) to a number
      ċ  Count number of occurrences of {the argument} in the resulting list

最初の5バイトは基本的に、指定された長さまでのすべての可能なハイパーバイナリ数を生成するだけです。たとえば、入力3では、[[0,1,2]、[0,1,2]、[0,1,2] ]]デカルト積は[[0,0,0]、[0,0,1]、[0,0,2]、[0,1,0]、…、[2,2,1]、 [2,2,2]]。基本的には、最後のエントリに1を、最後から2番目にエントリを、最後から2番目にエントリを4倍するなどして、追加します。これは通常、バイナリを10進数に変換するために使用されますが、数字2をうまく処理できるため、ハイパーバイナリでも機能します。次に、シーケンス内の適切なエントリを取得するために、結果リストに入力が表示される回数をカウントします。(幸いなことに、分子と分母は同じシーケンスに従います)。

メインプログラム(分子と分母を要求し、出力をフォーマットします):

’Ç”/⁸Ç
’Ç      Helper function (Ç), run on {the input} minus 1 (‘)
  ”/    {Output that to stdout}; start again with the constant '/'
    ⁸Ç  {Output that to stdout}; then run the helper function (Ç) on the input (⁸)

どういうわけか、実際の問題を解決するのと同じくらい多くのバイトをI / Oの処理に使用するプログラムを書き続けています…


悲嘆に値する、あなたはそれが非効率であることをからかっていませんでした-TIO 12で完了するには20秒かかり、完全に13回タイムアウトします!すべてのテストケースを検証することはできませんが、受け入れられました。
ソク

11

CJam(20バイト)

1_{_@_2$%2*-+}ri*'/\

オンラインデモ。これは0から始まることに注意してください。それは1インデックスにするために、初期置き換える1_ことによってをT1

解剖

これは、Moshe Newmanによる特性評価を使用しています。

画分はa(n+1)/a(n+2)、前の画分から生成することが可能a(n)/a(n+1) = x1/(2*floor(x) + 1 - x)

場合はx = s/t、我々が得ます

  1 / (2 * floor(s/t) + 1 - s/t)
= t / (2 * t * floor(s/t) + t - s)
= t / (2 * (s - s%t) + t - s)
= t / (s + t - 2 * (s % t))

今、私たちがそれを仮定しst互いに素であれば

  gcd(t, s + t - 2 * (s % t))
= gcd(t, s - 2 * (s % t))
= gcd(t, -(s % t))
= 1

だから、a(n+2) = a(n) + a(n+1) - 2 * (a(n) % a(n+1))完璧に動作します。

1_           e# s=1, t=1
{            e# Loop...
  _@_2$%2*-+ e#   s, t = t, s + t - 2 * (s % t)
}
ri*          e# ...n times
'/\          e# Separate s and t with a /

ここで方法論が大好き、素晴らしい答えです!
ソク

OEISエントリをさらに下にスクロールすると、Mike Stayが既にその式を送信していることがわかります。
ニール

11

Haskell、78 77 65 58バイト

最適化されたアプローチを恥知らずに盗むことにより、次のことが可能になります。

(s#t)0=show s++'/':show t
(s#t)n=t#(s+t-2*mod s t)$n-1
1#1

インフィックス関数を使用して数バイトをゴルフしてくれた@nimiに感謝します!

(それでも)0から始まるインデックスを使用します。


古いアプローチ:

s=(!!)(1:1:f 0)
f n=s n+s(n+1):s(n+1):(f$n+1)
r n=show(s n)++'/':(show.s$n+1)

出力形式をくそ...インデックス演算子。編集:そして優先順位。

面白い事実:異種リストが重要な場合、最後の行は次のようになります

r n=show>>=[s!!n,'/',s!!(n+1)]

バインドするガードを使用して、s!!n1バイト短くする必要がありますf n|x<-s!!n=x:x+x+1:f$n+1
。– Laikoni

@Laikoni s!!n+1はそうではありません(s!!n)+1が、s!!(n+1)だからこそそれができません:/
ThreeFx

確かに、それは明らかだったはずです。そのちょうど...そこにたくさんs!!nあります!
ライコニ

1
++'/':(show.s$n+1)in rを使用してバイトを保存できます。
-nimi

1
中置機能に切り替え:(s#t)0=show...(s#t)n=t#(s+t-2*mod s t)$n-1r=1#1。省略することもできます。rつまり、最後の行はただ1#1です。
-nimi

6

ゼリー、16 バイト

L‘Hị⁸Sṭ
1Ç¡ṫ-j”/

オンラインでお試しください!または、すべてのテストケースを確認します

使い方

1Ç¡ṫ-j”/  Main link. Argument: n

1         Set the return value to 1.
 Ç¡       Apply the helper link n times.
   ṫ-     Tail -1; extract the last two items.
     j”/  Join, separating by a slash.


L‘Hị⁸Sṭ   Helper link. Argument: A (array)

L         Get the length of A.
 ‘        Add 1 to compute the next index.
  H       Halve.
   ị⁸     Retrieve the item(s) of A at those indices.
          If the index in non-integer, ị floors and ceils the index, then retrieves
          the items at both indices.
    S     Compute the sum of the retrieved item(s).
     ṭ    Tack; append the result to A.

5

05AB1E34 33 25 23バイト

XX‚¹GÂ2£DO¸s¦ìì¨}R2£'/ý

説明

XX‚                        # push [1,1]
   ¹G           }          # input-1 times do
     Â                     # bifurcate
      2£                   # take first 2 elements of reversed list
        DO¸                # duplicate and sum 1st copy, s(n)+s(n+1)
           s¦              # cut away the first element of 2nd copy, s(n)
             ìì            # prepend both to list
               ¨           # remove last item in list
                 R2£       # reverse and take the first 2 elements
                    '/ý    # format output
                           # implicitly print

オンラインで試す

Adnanのおかげで2バイト節約されました。


これも機能しますか?:XX‚¹GÂ2£DO¸s¦ìì¨}R2£'/ý
アドナン

@Adnan確かに。ýリストをフォーマットできることを忘れていました。いいね
エミグナ

4

MATL、20バイト

FT+"@:qtPXnosV47]xhh

これは、OEISページで与えられた二項係数の観点から特徴付けを使用します

このアルゴリズムは理論的にはすべての数値で機能しますが、実際にはMATLの数値精度によって制限されているため、大きなエントリでは機能しません。結果は20、少なくとも入力までは正確です。

オンラインでお試しください!

説明

FT+      % Implicitly take input n. Add [0 1] element-wise. Gives [n n+1]
"        % For each k in [n n+1]
  @:q    %   Push range [0 1 ... k-1]
  tP     %   Duplicate and flip: push [k-1 ... 1 0]
  Xn     %   Binomial coefficient, element-wise. Gives an array
  os     %   Number of odd entries in that array
  V      %   Convert from number to string
  47     %   Push 47, which is ASCII for '\'
]        % End for each
x        % Remove second 47
hh       % Concatenate horizontally twice. Automatically transforms 47 into '\'
         % Implicitly display

4

Python 2、85 81バイト

x,s=input(),[1,1]
for i in range(x):s+=s[i]+s[i+1],s[i+1]
print`s[x-1]`+"/"+`s[x]`

この投稿は1から始まります。

再帰関数を使用して、85バイト:

s=lambda x:int(x<1)or x%2 and s(x/2)or s(-~x/2)+s(~-x/2)
lambda x:`s(x)`+"/"+`s(x+1)`

次のような出力True/2が受け入れられる場合、81バイトに1つあります。

s=lambda x:x<1 or x%2 and s(x/2)or s(-~x/2)+s(~-x/2)
lambda x:`s(x)`+"/"+`s(x+1)`

3

JavaScript(ES6)、43バイト

f=(i,n=0,d=1)=>i?f(i-1,d,n+d-n%d*2):n+'/'+d

1インデックス付き。n=1インデックスが0に変更されます。リンクされたOEISページには、前の2つの用語に関して、各用語に対して有用な再帰関係があります。私は単に、前のフラクションに関して、各フラクションの繰り返しとして再解釈しました。残念ながら、インラインTeXがないため、別のサイトに貼り付けて、この形式を確認する必要があります。

abba+b2amodb

3

Python 2、66バイト

f=lambda n:1/n or f(n/2)+n%2*f(-~n/2)
lambda n:`f(n)`+'/'+`f(n+1)`

再帰式を使用します。


3

C(GCC)、79バイト

0ベースのインデックスを使用します。

s(n){return!n?:n%2?s(n/2):s(-~n/2)+s(~-n/2);}r(n){printf("%d/%d",s(n),s(n+1));}

イデオネ


1
x?:ygcc拡張です。
リチ

3

実際には、18バイト

11,`│;a%τ@-+`nk'/j

オンラインでお試しください!

このソリューションでは、ピーターの式を使用していますを、同様に0インデックスが付けられています。Leaky Nunに感謝します。

説明:

11,`│;a%τ@-+`nk'/j
11                  push 1, 1
  ,`│;a%τ@-+`n      do the following n times (where n is the input):
                      stack: [t s]
    │                 duplicate the entire stack ([t s t s])
     ;                dupe t ([t t s t s])
      a               invert the stack ([s t s t t])
       %              s % t ([s%t s t t])
        τ             multiply by 2 ([2*(s%t) s t t])
         @-           subtract from s ([s-2*(s%t) s t])
           +          add to t ([t+s-2*(s%t) t])
                      in effect, this is s,t = t,s+t-2*(s%t)
              k'/j  push as a list, join with "/"


@LeakyNun OPから明確化されるまで、その改善を保留します。
メゴ


2

R、93バイト

f=function(n)ifelse(n<3,1,ifelse(n%%2,f(n/2-1/2)+f(n/2+1/2),f(n/2)))
g=function(n)f(n)/f(n+1)

文字通り最も単純な実装。ゴルフに少し取り組んでいます。


2

m4、131バイト

define(s,`ifelse($1,1,1,eval($1%2),0,`s(eval($1/2))',`eval(s(eval(($1-1)/2))+s(eval(($1+1)/2)))')')define(r,`s($1)/s(eval($1+1))')

マクロ定義するrようにr(n)評価するには仕様に応じ。まったくゴルフをしていませんが、フォーミュラをコーディングしました。


2

ルビー、49バイト

これは0から始まり、Peter Taylorの式を使用します。ゴルフの提案を歓迎します。

->n{s=t=1;n.times{s,t=t,s+t-2*(s%t)};"#{s}/#{t}"}

1

> <>、34 + 2 = 36バイト

ピーターテイラーの優れた答えを見た後、テストの答えを書き直しました(これは非常に不器用な再帰を使用して、恥ずかしい82バイトでした)。

&01\$n"/"on;
&?!\:@}:{:@+@%2*-&1-:

入力がスタックに存在することを想定しているため、-vフラグは+2バイトです。オンラインでお試しください!


1

オクターブ、90バイト

function f(i)S=[1 1];for(j=1:i/2)S=[S S(j)+S(j+1) (j+1)];end;printf("%d/%d",S(i),S(i+1));end

1

C#、91 90バイト

n=>{Func<int,int>s=_=>_;s=m=>1==m?m:s(m/2)+(0==m%2?0:s(m/2+1));return$"{s(n)}/{s(n+1)}";};

にキャストしFunc<int, string>ます。これは再帰的な実装です。

ゴルフをしていない:

n => 
{
    Func<int,int> s = _ => _; // s needs to be set to use recursively. _=>_ is the same byte count as null and looks cooler.
    s = m =>
        1 == m ? m               // s(1) = 1
        : s(m/2) + (0 == m%2 ? 0 // s(m) = s(m/2) for even
        : s(m/2+1));             // s(m) = s(m/2) + s(m/2+1) for odd
    return $"{s(n)}/{s(n+1)}";
};

編集:-1バイト。C#の判明には、間にスペースを必要としないreturnし、$補間された文字列を。



1

J、29バイト

([,'/',])&":&([:+/2|]!&i.-)>:

使用法

nの大きな値にxは、拡張整数の使用を示す接尾辞が必要です。

   f =: ([,'/',])&":&([:+/2|]!&i.-)>:
   f 1
1/1
   f 10
3/5
   f 50
7/12
   f 100x
7/19
   f 1000x
11/39

100「大きな値」としてカウントされますか?
dcsohl

1
@dcsohlこの方法では、二項係数が計算され、n = 100の場合、計算される最大のものはC(72、28)= 75553695443676829680> 2 ^ 64であり、浮動小数点値を回避するために拡張整数が必要になります。
マイル


弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.