Geben Sie die n-te rationale Zahl gemäß der Stern-Brocot-Sequenz aus


30

Die Stern-Brocot-Sequenz ist eine Fibonnaci-ähnliche Sequenz, die wie folgt konstruiert werden kann:

  1. Initialisieren Sie die Sequenz mit s(1) = s(2) = 1
  2. Zähler setzen n = 1
  3. Anhängen s(n) + s(n+1)An die Sequenz
  4. Anhängen s(n+1)An die Sequenz
  5. Inkrementieren n, kehren Sie zu Schritt 3 zurück

Dies ist äquivalent zu:

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}

Unter anderem kann die Stern-Brocot-Sequenz verwendet werden, um jede mögliche positive rationale Zahl zu erzeugen. Jede rationale Zahl wird genau einmal generiert und erscheint immer in ihrer einfachsten Form. ist zum Beispiel 1/3die 4. rationale Zahl in der Folge, aber die entsprechenden Zahlen 2/6,3/9 usw. wird nicht angezeigt.

Wir können die n-te rationale Zahl als definieren r(n) = s(n) / s(n+1), wos(n) oben beschrieben die n-te Stern-Brocot-Zahl ist.

Ihre Herausforderung besteht darin, ein Programm oder eine Funktion zu schreiben, die die mit der Stern-Brocot-Sequenz erzeugte n-te rationale Zahl ausgibt.

  • Die oben beschriebenen Algorithmen sind 1-indiziert; Wenn Ihr Eintrag 0-indiziert ist, geben Sie dies bitte in Ihrer Antwort an
  • Die beschriebenen Algorithmen dienen nur zur Veranschaulichung. Die Ausgabe kann nach Belieben abgeleitet werden (außer durch Hardcodierung).
  • Die Eingabe kann über STDIN, Funktionsparameter oder einen anderen sinnvollen Eingabemechanismus erfolgen
  • Ausgang kann STDOUT, Konsole, Funktionsrückgabewert oder jeder andere sinnvolle Ausgabestream sein
  • Ausgang muss als Zeichenkette in der Form sein a/b, in der aund bsind die entsprechenden Einträge in der Stern-Brocot Sequenz. Die Auswertung des Bruchs vor der Ausgabe ist nicht zulässig. Bei der Eingabe 12sollte die Ausgabe beispielsweise 2/5nicht sein 0.4.
  • Standardlücken sind nicht zulässig

Das ist , also gewinnt die kürzeste Antwort in Bytes.

Testfälle

Die Testfälle sind hier 1-indiziert.

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-Eintrag: A002487
Exzellentes Numberphile-Video zur Sequenz: Unendliche Brüche


Kann die Ausgabe Trues anstelle von 1s verwenden?
Loovjo

1
@ Loovjo Nein, True/2ist kein gültiger Bruch (soweit es mich betrifft). Übrigens Truenicht immer 1- einige Sprachen verwenden -1stattdessen, um mögliche Fehler beim Anwenden bitweiser Operatoren zu vermeiden. [Zitieren benötigt]
Sok


2
@Sok Zitat
mbomb007

1
@Sok ist aber in Python Truegleichbedeutend mit 1und True/2wäre 1/2.
Undichte Nonne

Antworten:


3

Jelly , 14 Bytes

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

Probieren Sie es online!

Ooh, looks like I can beat the accepted answer by @Dennis, and in the same language at that. This works using a formula from OEIS: the number of ways to express (the number minus 1) in hyperbinary (i.e. binary with 0, 1, 2 as digits). Unlike most Jelly programs (which work either as a full program or a function), this one works only as a full program (because it sends part of the output to stdout, and returns the rest; when used as a full program the return value is sent to stdout implicitly, so all the output is in the same place, but this wouldn't work for a function submission).

Diese Version des Programms ist sehr ineffizient. Sie können ein viel schnelleres Programm erstellen, das für alle Eingaben bis zu 2ⁿ funktioniert, indem Sie n direkt nach der ersten Zeile einfügen. Das Programm hat eine O ( n × 3ⁿ) -Leistung, daher ist es hier ziemlich wichtig , n klein zu halten . Das geschriebene Programm setzt n gleich der Eingabe, die eindeutig groß genug, aber in fast allen Fällen auch eindeutig zu groß ist (aber hey, es spart Bytes).

Erläuterung

Wie in meinen Jelly-Erklärungen üblich, zeigt Text in geschweiften Klammern (z. B. {the input}) etwas, das Jelly aufgrund fehlender Operanden im Originalprogramm automatisch ausfüllt.

Hilfsfunktion (berechnet den n- ten Nenner, dh den n + 1- ten Zähler):

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

Die ersten fünf Bytes erzeugen im Grunde genommen nur alle möglichen hyperbinären Zahlen bis zu einer bestimmten Länge, zB bei Eingabe 3 ist die Ausgabe von [[0,1,2], [0,1,2], [0,1,2] ]] so ist das kartesische Produkt [[0,0,0], [0,0,1], [0,0,2], [0,1,0],…, [2,2,1], [2,2,2]]. basically just multiplies the last entry by 1, the penultimate entry by 2, the antepenultimate entry by 4, etc., and then adds; although this is normally used to convert binary to decimal, it can handle the digit 2 just fine, and thus works for hyperbinary too. Then we count the number of times the input appears in the resulting list, in order to get an appropriate entry in the sequence. (Luckily, the numerator and denominator follow the same sequence).

Main program (asks for the numerator and denominator, and formats the output):

’Ç”/⁸Ç
’Ç      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 (⁸)

Somehow I keep writing programs that take almost as many bytes to handle I/O as they do to solve the actual problem…


Good grief, you weren't kidding about it being inefficient - on TIO 12 takes 20s to complete, and 13 times out completely! Accepted, even though I can't verify all the test cases.
Sok

11

CJam (20 bytes)

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

Online demo. Note that this is 0-indexed. To make it 1-indexed, replace the initial 1_ by T1.

Dissection

This uses the characterisation due to Moshe Newman that

the fraction a(n+1)/a(n+2) can be generated from the previous fraction a(n)/a(n+1) = x by 1/(2*floor(x) + 1 - x)

If x = s/t then we get

  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))

Now, if we assume that s and t are coprime then

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

So a(n+2) = a(n) + a(n+1) - 2 * (a(n) % a(n+1)) works perfectly.

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 /

Love the methodology here, awesome answer!
Sok

If you scroll further down the OEIS entry you'll find that Mike Stay already submitted that formula.
Neil

11

Haskell, 78 77 65 58 bytes

Shamelessly stealing the optimized approach gives us:

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

Thanks to @nimi for golfing a few bytes using an infix function!

(Still) uses 0-based indexing.


The old approach:

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)

Damn the output format... And indexing operators. EDIT: And precedence.

Fun fact: if heterogenous lists were a thing, the last line could be:

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

Using a guard to bind s!!n should be one byte shorter: f n|x<-s!!n=x:x+x+1:f$n+1
Laikoni

@Laikoni s!!n+1 is not (s!!n)+1 but s!!(n+1) which is why I can't do that :/
ThreeFx

Indeed, that should have been obvious. Its just ... so many s!!n in there!
Laikoni

1
You can use ++'/':(show.s$n+1) in r to save a byte.
nimi

1
Switch to an an infix function: (s#t)0=show..., (s#t)n=t#(s+t-2*mod s t)$n-1, r=1#1. You can even omit r, i.e. the last line is just 1#1.
nimi

6

Jelly, 16 bytes

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

Try it online! or verify all test cases.

How it works

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

05AB1E, 34 33 25 23 bytes

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

Explanation

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

Try it online

Saved 2 bytes thanks to Adnan.


Does this also work?: XX‚¹GÂ2£DO¸s¦ìì¨}R2£'/ý.
Adnan

@Adnan Indeed. I forgot that ý can format a list. Nice.
Emigna

4

MATL, 20 bytes

FT+"@:qtPXnosV47]xhh

This uses the characterization in terms of binomial coefficients given in the OEIS page.

The algorithm works in theory for all numbers, but in practice it is limited by MATL's numerical precision, and so it doesn't work for large entries. The result is accurate for inputs up to 20 at least.

Try it online!

Explanation

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 bytes

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]`

This submission is 1-indexed.

Using a recursive function, 85 bytes:

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)`

If an output like True/2 is acceptable, here's one at 81 bytes:

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 bytes

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

1-indexed; change to n=1 for 0-indexed. The linked OEIS page has a useful recurrence relation for each term in terms of the previous two terms; I merely reinterpreted it as a recurrence for each fraction in terms of the previous fraction. Unfortunately we don't have inline TeX so you'll just have to paste it onto another site to find out how this formats:

abba+b2(amodb)

3

Python 2, 66 bytes

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

Uses the recursive formula.


3

C (GCC), 79 bytes

Uses 0-based indexing.

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));}

Ideone


1
x?:y is a gcc extension.
rici

3

Actually, 18 bytes

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

Try it online!

This solution uses Peter's formula and is likewise 0-indexed. Thanks to Leaky Nun for a byte.

Explanation:

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 I'll hold off on that improvement until there's clarification from the OP.
Mego

2

MATL, 32 30 bytes

1i:"tt@TF-)sw@)v]tGq)V47bG)Vhh

This uses a direct approach: generates enough members of the sequence, picks the two desired ones and formats the output.

Try it online!


2

R, 93 bytes

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)

Literally the simplest implementation. Working on golfing it a bit.


2

m4, 131 bytes

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))')

Defines a macro r such that r(n) evaluates according to the spec. Not really golfed at all, I just coded the formula.


2

Ruby, 49 bytes

This is 0-indexed and uses Peter Taylor's formula. Golfing suggestions welcome.

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

1

><>, 34+2 = 36 bytes

After seeing Peter Taylor's excellent answer, I re-wrote my test answer (which was an embarrassing 82 bytes, using very clumsy recursion).

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

It expects the input to be present on the stack, so +2 bytes for the -v flag. Try it online!


1

Octave, 90 bytes

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 bytes

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)}";};

Casts to Func<int, string>. This is the recursive implementation.

Ungolfed:

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)}";
};

Edit: -1 byte. Turns out C# doesn't need a space between return and $ for interpolated strings.



1

J, 29 bytes

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

Usage

Large values of n require a suffix of x which denotes the use of extended integers.

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

100 counts as a "large value"?
dcsohl

1
@dcsohl In this method, the binomial coefficients are computed, and for n = 100, the largest one computed is C(72, 28) = 75553695443676829680 > 2^64 and will require extended integers to avoid floating point values.
miles

1

Mathematica, 108 106 101 bytes

(s={1,1};n=1;a=AppendTo;t=ToString;Do[a[s,s[[n]]+s[[++n]]];a[s,s[[n]]],#];t@s[[n-1]]<>"/"<>t@s[[n]])&

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.