フィボナッチが逆転しました!


42

前書き

私たちは皆、フィボナッチ数列を知っていて大好きで、すでにここで無数の挑戦を見てきました。ただし、この答えが提供する非常に単純なケースはまだありません:逆フィボナッチ!だから、与えられたF_n仕事を見つけることですn

仕様

入力

入力は負でない整数になり、フィボナッチ数列の一部であることが保証されます。

出力

出力も負でない整数でなければなりません。

何をすべきか?

すでに紹介したとおり、フィボナッチ数が与えられたら、そのインデックスを出力します。ここでFiboancci番号はとして定義されてF(0)=0, F(1)=1, F(n)=F(n-1)+F(n-2)おり、指定されているため、をF(n)返す必要がありますn

潜在的なコーナーケース

0は有効な入出力です。
入力として「1」を指定した場合、「1」または「2」を出力できます。
入力は実際にはフィボナッチ数であると常に仮定することができます。
入力が32ビット符号付き整数として表現可能であると想定できます。

誰が勝ちますか?

これはコードゴルフなので、バイト単位の最短回答が勝ちです!
もちろん、標準ルールが適用されます。

テストケース

0 -> 0
2 -> 3
3 -> 4
5 -> 5
8 -> 6
13 -> 7
1836311903 -> 46

39
ちょっとした選択:これをフィボナッチとみなすべきではないen.m.wikipedia.org/wiki/Inverse_function
マイケル

19
iccanobiF ?!

6
@Michaelこれは逆フィボナッチではありません。なぜなら、それは単射ではないのでフィボナッチ関数に逆関数がないからです(「1」が2回現れるため)。元々は、「逆テーブルルックアップ」というアイデアから来ました。これは、人々がここで行うことを期待していたことです(たとえば、問題を解決するために行うと期待していました)。
SEJPM

9
ここでの関数は、負でない整数からフィボナッチ数のセットへの「フィボナッチ関数」の右逆関数と考えることができます。右逆の存在は単射を意味しません。
デニス

1
@SEJPM:「フィボナッチ数列を逆方向に綴るプログラムを書く」ようなタスクを期待していました。
ベルギ

回答:


58

実際には、1バイト

f

はい、2015年11月16日以降、このためのビルトインがあります。

オンラインで試す


楽しみのために、組み込みなしで、それは9バイトです:

╗1`F╜=`╓i

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

説明:

╗1`F╜=`╓i
╗          push input to register 0
 1`F╜=`╓   push list containing first value x (starting with x = 0) where:
   F         fib(x)
    ╜=       is equal to the input
        i  flatten the list

15
ಠ_ಠ:私は1人の思考と1私はこれを見たときだけと思ってい
アディソンCrumpの

37
このようなとんでもない具体的な目的のためにシンボルを「無駄にする」理由を私は本当に理解していない
致命

19
@Fatalize最初に追加したのは、フィボナッチ関数と逆フィボナッチ関数です。今でも、39個の完全に未使用のシングルバイトコマンドがあります(使用できるオーバーロードの数は誰が知っていますか)。256個のシンボルは、Actuallyに5つのタイプ(整数、実数、文字列、反復可能、関数)があるという事実と組み合わせて、最大1280個の単項関数と6400個のバイナリ関数があることを意味します。一見役に立たないコマンドには多くの余地があります。
メゴ

23
@Megoほとんどの組み込み機能についてMathematicaと競争しようとしていますか?
-gcampbell

13
実際、それはただのバイトです...笑、この言語名が大好きです。
ニカエル

42

Mathematica、25バイト

InverseFunction@Fibonacci

関数。あなたが私に尋ねると、かなり自明です。


31

Python、36 34 32バイト

lambda n:len(str(66*n**6))//1.24

以前のバージョン:

f=lambda n:len(str(66*n**6))//1.24
f=lambda n:(n*n*7).bit_length()//1.4

説明

核となる考え方は、式を逆にすることです

fibonacci(n) ~ ( (1 + sqrt(5)) / 2)**n / sqrt(5)

それは私たちに伝えます

log fibonacci(n) ~ n log((1 + sqrt(5)) / 2) - log(sqrt(5))

取得するため

f(n) ~ (log(n) + log(sqrt(5))) / log((1 + sqrt(5))/2)

ゴルフの最適化は次のとおりです。

  • len(str(n))インポートせずにログベース10を計算するために使用log.bit_length()ログベース2の計算に使用される古いバージョン)
  • 上げるn対数の近似値は、連続するフィボナッチ数を区別することができるように、電源に
  • 定数で乗算すると、値が正しい範囲に収まるように値がスケールアップされます

その後、除数は、私が管理できる限りの精度で切り捨てられ、すべての32ビットフィボナッチ数に対して正しい結果が得られるように乗数が選択されました。


f=カウントされないため、32バイトにする必要があります。
リーキー修道女

2
上記のコメントで既に述べたように、匿名関数/名前のないラムダはデフォルトで許可されています。また、Python 2への回答を制限し、長い引数が必要な場合は、機能するlambda n:~-len(`66*n**6`)//1.24はずです。
デニス


10

ゼリー、14 11バイト

5½×lØp+.Ḟ»0

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

これは私の最初のゼリーの答えです!これはMATL回答からのアルゴリズム使用します。3バイトを削り取ってくれたDennisに感謝します!

説明:

   lØp      # Log Base phi
5½          # Of the square root of 5
  ×         # Times the input
      +     # Plus
       .    # 0.5
        Ḟ   # Floored

これで正しい答えが得られます。今は、「0」の特殊なケースを処理するだけです。引数として「0」を使用すると、が取得されるため-infinity、戻ります

»      # The maximum of 
 0     # Zero
       # And the previous calculated value.

7
説明に対するコメントはリメリックの終わりであるため、+ 1。
ダニエル

10

ジュリア、27 26 18バイト

!n=log(3n+.7)÷.48

これは、Binetの式の逆を使用し、32ビット整数に十分な精度を持ちます。実際には、F(153)= 42,230,279,526,998,466,217,810,220,532,898> 2 105まで動作します。

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

使い方

Binetの式は次のことを述べています。

ビネットの式

Fをフィボナッチの集合に制限すると、マップn→F nには右逆 F→n Fがあります。

私たちはそれを持っています

ビネットの式の右逆

そして、やるべきことは、エッジケース0を扱うことだけです。

入力は32ビット整数に制限されているため、式では定数の代わりに短い10進数リテラルを使用できます。

  • logφ= 0.481211825059603447…≈0.48

    残念ながら、0.5は十分に正確ではありません。

  • √5= 2.2360679774997896964…≈3

    これは一見ひどい近似に思えるかもしれませんが、対数を取っているため、log 3-log√5= 0.29389333245105…であるため、丸め前の結果は小さな定数係数で相殺されます

  • 0.5≈0.7

    前の近似からの過剰のため、実際にこの用語を完全に省略しても、F> 0の正しい結果が得られます。ただし、F = 0の場合、対数は未定義になります。0.7は、式をF = 0に拡張する最短値であることが判明しました。


8

JavaScript、54 50 69 50 42バイト

b=>(j=>{for(i=c=0;b-i;c++)i=j+(j=i)})(1)|c

きっと楽しみのためだけに勝つつもりはありません:)

さて、ゼロをチェックすると19バイトを消費します。WTF?バカめ。


デモ!最後のテストケースを表示するには、コンソールを少しスクロールする必要があります。

a=b=>(j=>{for(i=c=0;b-i;c++)i=j+(j=i)})(1)|c;
console.log('0: '+a(0));
console.log('2: '+a(2));
console.log('3: '+a(3));
console.log('5: '+a(5));
console.log('8: '+a(8));
console.log('13: '+a(13));
console.log('1836311903: '+a(1836311903));

8バイト短縮する@edcに感謝します。


シンプルb=>{for(j=1,i=c=0;b-i;c++)i=j+(j=i);return c}45、ゴルフb=>(j=>{for(i=c=0;b-i;c++)i=j+(j=i)})(1)|c42。
edc6516

1
@edcうわー、それは賢い、ありがとう<3
nicael

8

Perl 6  33 30  27バイト

{first *==$_,:k,(0,1,*+*...*>$_)}
{first *==$_,:k,(0,1,*+*...*)}
{first $_,:k,(0,1,*+*...*)}

それを試してみてください

説明:

# lambda with implicit 「$_」 parameter
{
  first           # find the first element
    $_,           # where something is equal to the block's argument
    :k,           # return the key rather than the value

    # of the Fibonacci sequence
    ( 0, 1, * + * ... * )
    # ^--^ first two values
    #       ^---^ lambda used to generate the next in the series
    #             ^-^ generate until
    #                 ^ Whatever
}

テスト:

#! /usr/bin/env perl6
use v6.c;
use Test;

# using the safer version that stops generating
# values bigger than the input
my &fib-index = {first $_,:k,(0,1,*+*...*>$_)}

my @tests = (
  0 => 0,
  2 => 3,
  3 => 4,
  5 => 5,
  8 => 6,
  13 => 7,
  1836311903 => 46,
  1836311904 => Nil, # this is why the safe version is used here
  12200160415121876738 => 93,
  19740274219868223167 => 94,
  354224848179261915075 => 100,
);

plan +@tests + 1;

for @tests -> $_ ( :key($input), :value($expected) ) {
  cmp-ok fib-index($input), &[eqv], $expected, .gist
}

cmp-ok fib-index((0,1,*+*...*)[1000]), &[eqv], 1000, 'works up to 1000th element of Fibonacci sequence'
1..13
ok 1 - 0 => 0
ok 2 - 2 => 3
ok 3 - 3 => 4
ok 4 - 5 => 5
ok 5 - 8 => 6
ok 6 - 13 => 7
ok 7 - 1836311903 => 46
ok 8 - 1836311904 => Nil
ok 9 - 12200160415121876738 => 93
ok 10 - 19740274219868223167 => 94
ok 11 - 354224848179261915075 => 100
ok 12 - works up to 1000th element of Fibonacci sequence

1
数値は有効なスマートマッチャーであるため、first *==$_単にfirst $_に置き換えることができます。
smls

...代わりに演算子を使用して24バイトfirst
Jo King

7

ゼリー、8 バイト

1+С0
¢i

オンラインでお試しください!このアプローチは、最後のテストケースには非効率すぎることに注意してください。

使い方

¢i     Main link. Argument: n

¢      Call the helper link niladically (i.e., without arguments).
       This yields the sequence of the first n positive Fibonacci numbers, i.e.,
       [1, 1, 2, 3, 5, ...].
 i     Find the first index of n (1-based, 0 if not found).


1+С0  Helper link. No arguments.

1      Set the left argument to 1.
    0  Yield 0.
 +С   Add both arguments, replacing the left argument with the sum and the right
       argument with the previous value of the left argument.
       Yield the array of all intermediate values of the left argument.


5

Python、29バイト

g=lambda n:n>.7and-~g(n/1.61)

入力を黄金比近似1.61で0.7未満になるまで再帰的に分割し、分割数を出力します。

0の場合、コードはを出力しますFalseこれはPythonの0に相当します。これは2バイトでは回避できます

g=lambda n:n//.7and 1+g(n/1.61)

4

JavaScript(ES6)、39 33バイト

f=(n,j=0,k=1)=>n>j?f(n,k,j+k)+1:0

ES7でも、逆ビネの式は47バイトかかります。

x=>Math.log(x*5**.5)/Math.log(.5+1.25**.5)+.5|0
x=>Math.log(x*5**.5)/Math.log((1+5**.5)/2)+.5|0
x=>Math.log(x*(p=5**.5))/Math.log((1+p)/2)+.5|0

ただ配布しlog、すべての定数を事前計算します
...-チャーリー

私見では、名前でラムダを再帰的に呼び出す場合f(n,k,j+k)、割り当てf=を含めて+2バイトとしてカウントする必要があります。名前のないラムダのルールはここでは適用されません。
チャーリー

@charlie申し訳ありませんが、私はいつもそれを忘れていました。一定。
ニール

4

セージ、49バイト

lambda x,s=sqrt(5):x and int(log(x*s,(1+s)/2)+.5)

TuukkaXに、数バイトを節約sqrt(5)するsための保存についての提案をありがとう。

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

Binetの式の逆を使用するこのアプローチは、以前のアプローチに比べていくつかの改善点を提供します。高速(一定時間と2次時間)、実際に大きな入力で機能し、短いです!

Pythonユーザーは、Cの関数で計算され、浮動小数点の問題により精度が失われるためsqrt(5)、なぜ短いのではなく使用するのか疑問に思うかもしれません。多くの数学関数(およびを含む)はSageでオーバーロードされ、正確なシンボル値を返しますが、精度は失われません。5**.55**.5powsqrtlog


私はSageをまったく知りませんがsqrt(5)、変数を保持し、2回入力する代わりに2回使用することでバイトを節約できますsqrt(5)か?
Yytsi

4

MATL、14バイト

t?5X^*17L&YlYo

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

これはBinetの式の逆を使用するため、非常に高速です。

LET Fを表し、Nフィボナッチ数番目、およびφ 黄金比。それから

ここに画像の説明を入力してください

コードは、次の2つの変更を加えてこの式を使用します。

  • 1/2を追加してから切り捨てる代わりに、コードは単純に最も近い整数に向かって丸めます。
  • 入力F = 0は、特殊なケースとして扱う必要があります。

方法

t         % Take input F implicitly. Make a copy
?         % If (copy of) F is positive
  5X^     %   Push sqrt(5)
  *       %   Multiply by F
  17L     %   Push phi (predefined literal)
  &Yl     %   Two-input logarithm: first input is argument, second is base
  Yo      %   Round towards nearest integer
          % Else the input, which is 0, is left on the stack
          % End if implicitly
          % Display implicitly

1
別のアプローチ:O1G:"yy+]vGmfq
DJMcMayhem

1
11バイト:t?17L&YlXkQ
jimmy23013

@ jimmy23013すてきなアプローチ!それを別の答えとして明確に投稿する必要があります
ルイスメンドー

それは単に削除する方法であるため、別の答えの価値はないと思い5X^*ます (私は以前にこれをやったことがあります。)そして、私はそれを改善し続ける可能性があるほど十分にMATLを知りません。
jimmy23013


3

JavaScript、22バイト

n=>Math.log(n)/.48+2|0

私はそれを見たとき、これは仕事だと思うが、どうやらなかった-Infinity|0です0JavaScriptで。図を移動します。
デニス

@Dennis:JSでは、ビットごとの演算子は最後の32ビットとのみを取ります-Infinity = FFF00000 00000000。私が見つけたのは嬉しかったです、それはのような明示的なゼロテストを追加する必要がないために3バイトを節約しますn&&。それとは別に、の主な目的は(ジュリアのように)の|0代替です。Math.trunc()÷
チャーリー

3

C、62 58バイト

g(c,a,b){return c-a?g(c,b,a+b)+1:0;}f(c){return g(c,0,1);}

詳細

int g(int c, int a, int b)
{
    if (c == a)
    {
        return 0;
    }
    else
    {
        return g(c, b, a+b) + 1;
    }
}

int f(c)
{
    return g(c, 0, 1);
}

3

Java 7、70バイト

int c(int n){int a=0,b=1,c=0,t;while(a<n){c++;t=b;b+=a;a=t;}return c;}

https://ideone.com/I4rUC5


2
PPCGへようこそ、最初の回答です!
リーキー修道女

int c(int n){int a=0,b=1,c=0,t;for(;a<n;t=b,b+=a,a=t)c++;return c;}(テストなし)
リーキー修道女

int c(int n){int a=0,b=1,c=0;while(a<n){c++;b+=a;a=b-a;}return c;}(テストなし)
リーキー修道女

2
int c(int n){int a=0,b=1,c=0;for(;a<n;b+=a,a=b-a)c++;return c;}(テストなし)
リーキー修道女

2

TSQL、143バイト

入力は次の@nようになりますDECLARE @n INT = 1836311903;

DECLARE @O BIGINT=0;WITH F(R,P,N)AS(SELECT @O,@O,@O+1 UNION ALL SELECT R+1,N,P+N FROM F WHERE N<=@n)SELECT MAX(R)FROM F OPTION(MAXRECURSION 0);


2

Sesos、28バイト

Hexdump:

0000000: 16f8be 766ef7 ae6d80 f90bde b563f0 7ded18 3ceffa  ...vn..m.....c.}..<..
0000015: b1c1bb af9f3f ff                                  .....?.

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

(Sesosでは数値のコピーには指数時間が必要なため、指数時間が必要です。)

バイナリファイルの生成に使用されるアセンブリ:

set numin
set numout
get
jmp
sub 1
fwd 1
add 1
fwd 1
add 1
rwd 2
jnz    ;input input
fwd 4
add 1  ;input input 0 1
fwd 2
add 1  ;input input 0 1 0 1
rwd 4
jmp
jmp    ;input input-curr curr next iterations
sub 1
jnz    ;input 0 curr next iterations
fwd 3
add 1
jmp
sub 1
fwd 2
add 1
rwd 2
jnz    ;input 0 curr next 0 0 iterations+1
rwd 1
jmp
sub 1
fwd 1
add 1
fwd 1
add 1
rwd 2
jnz    ;input 0 curr 0 next next iterations+1
rwd 1
jmp
sub 1
fwd 1
sub 1
fwd 2
add 1
rwd 3
jnz    ;input 0 0 -curr next curr+next iterations+1
rwd 2
jmp
sub 1
fwd 2
add 1
fwd 1
add 1
rwd 3
jnz    ;0 0 input input-curr next curr+next iterations+1
fwd 3
jnz
fwd 3
put

2

Java 8 61バイト

@dainichiの回答と同じですが、Java 8ラムダを使用して短くしただけです。答えは有効な右辺値式です。

n->{int a=0,b=1,c=0,t;while(a<n){c++;t=b;b+=a;a=t;}return c;}

ゴルフをしていない:

interface F
{
    int c(int n);
}

public class Main
{

    public static void main(String[] args)
    {
        F f = n->{int a=0,b=1,c=0,t;while(a<n){c++;t=b;b+=a;a=t;}return c;};
    }
}


1

Java 7、89バイト

int c(int n){int i=-1;while(f(++i)<n);return i;}int f(int n){return n<2?n:f(n-1)+f(n-2);}

@Adnanの05AB1E回答の説明に触発されました。

未ゴルフ&テストケース:

ここで試してみてください。(最後のテストケースの制限時間を超えましたが、私のPCでは約30〜45秒で動作します。)

class Main{
  static int c(int n){
    int i = -1;
    while(f(++i) < n);
    return i;
  }

  static int f(int n){
    return n < 2
             ? n
             : f(n - 1) + f(n - 2);
  }

  public static void main(String[] a){
    System.out.println(c(0));
    System.out.println(c(2));
    System.out.println(c(3));
    System.out.println(c(5));
    System.out.println(c(8));
    System.out.println(c(1836311903));
  }
}

出力:

0
3
4
5
6
46


1

J、32 27 17バイト

i.~0,+/@(!|.)\@i.

最初のn個のフィボナッチ数を計算し、そのリストでnのインデックスを見つけます。

使用法

追加のコマンドは、複数の入出力をフォーマットするために使用されます。最後のテストケースは、計算にさらに多くの時間を必要とするため、省略されています。

   f =: i.~0,+/@(!|.)\@i.
   (,.f"0) 0 1 2 3 5 8 13
 0 0
 1 1
 2 3
 3 4
 5 5
 8 6
13 7

説明

i.~0,+/@(!|.)\@i.  Input: n
               i.  Get the range [0, 1, ..., n-1]
             \@    For each prefix of that range
          |.         Reverse the prefix
         !           Find the binomial coefficient between each value in the original
                     prefix and the reversed prefix
     +/@             Sum those binomial coefficients
                   This will create the Fibonacci numbers from 1 to n
   0,              Prepend a 0 to the list of Fibonacci numbers
i.~                Find the index of n in that list and return

1

Mathematica、30バイト

Round@Log[5^.5/2+.5,.8+5^.5#]&

純粋な機能; 入力が1の場合、2を返します。

他のMathematicaエントリに勝るものではありませんが、異常な方法を示しています。N番目のフィボナッチ数が[1 / sqrt(5)倍のNの黄金比のパワー]( "ビネットの式」)。

したがって、逆関数は、[sqrt(5)に問題のフィボナッチ数を掛けたもの]の底[黄金比]対数になります。これ.8+は、他の値を台無しにすることなく、0の対数を取らないようにするためのハックです。



1

Brachylog、14バイト

≜∧0;1⟨t≡+⟩ⁱ↖?h

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

出力変数を介して入力を受け取り、入力変数を介して出力します。

≜                 Label the input variable, trying 0, 1, -1, 2...,
  0               then starting with 0
 ∧                (which is not necessarily the input variable)
   ;1             paired with 1,
     ⟨t≡ ⟩        replace the first element of the pair with the last element
     ⟨ ≡+⟩        and the last element of the pair with the sum of the elements
          ⁱ↖?     a number of times equal to the input variable,
             h    such that the first element of the pair is the output variable.

なぜ必要なのか完全にはわかりません。


0

Javascript(外部ライブラリを使用)(84バイト)

n=>_.Until((i,a)=>{l=a.length;if(a[l-1]!=n){return i<=1?i:a[l-1]+a[l-2]}}).Count()-1

libへのリンク:https : //github.com/mvegh1/Enumerable

コードの説明:ライブラリには、述語の戻り値が未定義になるまでシーケンスを作成する静的メソッドがあります。述部には(「i」ndex、現在の内部「a」rray生成)の署名があります。各反復で、内部配列の最後の要素が入力nと等しいかどうかを確認します。そうでない場合は、fibシーケンスの次の値を返します。それ以外の場合、述部にはシーケンスの生成を終了する未定義の結果があります。次に、シーケンスの長さを返します(そして、OPで見られるように、0に基づいて適合させるために1を引きます

ここに画像の説明を入力してください


ここ からのコードを使用して53バイトn=>{a=c=t=0,b=1;while(a<n){c++;t=b;b+=a;a=t}return c} オンライン
pixma140
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.