Фибоначчи поменял местами!


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
Michael

19
Итак, iccanobiF ?!

6
@ Майкл, это не обратная функция Фибоначчи, потому что нет обратной функции Фибоначчи, потому что она не инъективна (потому что «1» появляется дважды). Обратное изначально исходило из идеи «обратного просмотра таблиц», и именно этого я и ожидал от людей (например, я ожидал, что они это сделают, чтобы решить проблему).
SEJPM

9
Функцию здесь можно рассматривать как правую обратную от «функции Фибоначчи» от неотрицательных целых чисел до набора чисел Фибоначчи. Наличие правого обратного не подразумевает инъективность.
Деннис

1
@SEJPM: Я вроде как ожидал задачу наподобие «написать программу, которая излагает последовательность Фибоначчи в обратном направлении».
Берги

Ответы:


58

На самом деле, 1 байт

f

Да, для этого есть встроенная функция с 16 ноября 2015 года .

Попробуйте онлайн


Для забавы, без встроенного, это 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
У меня есть одна мысль и одна мысль, только когда я вижу это: ಠ_ಠ
Аддисон Крамп

37
Я не очень понимаю, почему вы «тратите» символ на такие смехотворно конкретные цели
Fatalize

19
@Fatalize Функции Фибоначчи и обратные функции Фибоначчи были одними из первых, которые я добавил. Даже сейчас существует 39 полностью неиспользуемых однобайтовых команд (и кто знает, сколько перегрузок можно использовать). 256 символов в сочетании с тем фактом, что в действительности существует 5 типов (Integer, Real, String, Iterable, Function), означают, что существует до 1280 возможных унарных функций и 6400 возможных двоичных функций. Там много места для, казалось бы, бесполезных команд.
Mego

23
@Mego Вы просто пытаетесь конкурировать с Mathematica за большинство встроенных?
Gcampbell

13
На самом деле, это просто байт ... LOL, люблю это название языка.
Никель

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-битных чисел Фибоначчи.


это должно быть 32 байта, потому что f=не считается.
Утренняя монахиня

2
Как уже говорилось выше, анонимные функции / безымянные лямбды разрешены по умолчанию . Также, если вы ограничиваете свой ответ Python 2 и требуете длинных аргументов, lambda n:~-len(`66*n**6`)//1.24должно работать.
Деннис


10

Желе, 14 11 байт

5½×lØp+.Ḟ»0

Попробуйте онлайн!

Это мой первый желейный ответ! Это использует алгоритм из ответа MATL . Спасибо Деннису за то, что он сбрил 3 байта!

Объяснение:

   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

При этом используется обратная формула Бине , с достаточной точностью для 32-битных целых чисел; фактически он работает до F (153) = 42 230 309 526 998 466 217 810 220 532 898> 2 105 .

Попробуйте онлайн!

Как это работает

Формула Бине гласит следующее.

Формула Бине

Ограничение F на множестве Фибоначчи, отображение N → F п имеет право обратного F → N F .

У нас есть это

правая обратная формула Бине

и все, что осталось сделать, это иметь дело с краевым случаем 0 .

Поскольку ввод ограничен 32-разрядными целыми числами, мы можем использовать короткие десятичные литералы вместо констант в формуле.

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

Спасибо @edc за сокращение на 8 байтов.


просто 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.
edc65

1
@edc Ух ты, это умно, спасибо <3
Никель

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
Джо Кинг

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, который равен 0 в Python . Этого можно избежать на 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

Sage, 49 байтов

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

Благодаря TuukkaX за предложение о сохранении в sqrt(5)качестве sсбрить несколько байт.

Попробуйте онлайн .

Этот подход, использующий обратную формулу Бине, предлагает несколько улучшений по сравнению с предыдущим подходом: он быстрее (постоянное время по сравнению с квадратичным), он действительно работает для больших входов и короче!

Пользователи Python могут задаться вопросом, почему я использую sqrt(5)вместо более коротких 5**.5- это потому, что 5**.5вычисляется с помощью powфункции C и теряет точность из-за проблем с плавающей запятой. Многие математические функции (включая sqrtи log) перегружены в Sage, чтобы вернуть точное символическое значение, которое не теряет точности.


Я вообще не знаю Sage, но не могли бы вы сохранить байты, удерживая sqrt(5)переменную in и использовать ее дважды вместо ввода sqrt(5)дважды?
Yytsi

4

MATL , 14 байтов

t?5X^*17L&YlYo

Попробуйте онлайн!

Это использует обратную формулу Бине , и поэтому это очень быстро.

Пусть F обозначает n-е число Фибоначчи, а φ - золотое сечение . затем

введите описание изображения здесь

Код использует эту формулу с двумя модификациями:

  • Вместо добавления 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, чтобы продолжать улучшать его.
Джимми23013


3

JavaScript, 22 байта

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

Я не думал, что это сработает, когда я это увидел, но, видимо -Infinity|0, 0в JavaScript. Пойди разберись.
Деннис

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

Ungolfed:

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 's 05AB1E .

Ungolfed и тестовые случаи:

Попробуй это здесь. (Превышено ограничение по времени для последнего контрольного примера, но на моем компьютере оно работает примерно через 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#]&

Чистая функция; возвращает 2, если вход 1.

Не превосходит другую запись Mathematica, но демонстрирует необычный метод: это (очень крутой) факт, что N-е число Фибоначчи является ближайшим целым числом к ​​[1 / sqrt (5) раз N-й степени золотого сечения] (" Формула Бине ").

Следовательно, обратная функция будет логарифмом по основанию [золотое сечение] [sqrt (5) раз умноженного на число Фибоначчи]. .8+Хак , чтобы убедиться , что мы не берем логарифм 0, не щуря другие значения.



1

Брахилог , 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"). На каждой итерации мы проверяем, равен ли последний элемент внутреннего массива входу n. Если нет, верните следующее значение в последовательности fib. В противном случае предикат имеет неопределенный результат, который завершает генерацию последовательности. Затем мы возвращаем длину последовательности (и вычитаем 1, чтобы соответствовать нулю на основе 0, как видно из OP

введите описание изображения здесь


53 байта используя код отсюда n=>{a=c=t=0,b=1;while(a<n){c++;t=b;b+=a;a=t}return c} Попробуйте онлайн!
pixma140
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.