P, 47 bajtów
m:{*/1_-':|(0<){y-x x bin y}[*+60(|+\)\1 0]\x}
Test
+(i;m'i:1 2 3 4 5 6 7 8 9 42 1000 12345)
odczytaj to jako pary (i, mapa (m, i)), gdzie m jest funkcją obliczeniową, a ja różnymi argumentami
pisze
1 1
2 2
3 3
4 3
5 5
6 5
7 10
8 8
9 8
42 272
1000 12831
12345 138481852236
Wyjaśnienie
n funtion\arg
stosuje funkcję (funkcja (funkcja (... funkcja (argumenty))) n razy (wewnętrznie używa rekurencji talowej) i zwraca sekwencję wyników. Obliczamy 60 pierwszych pozycji serii fibonnaci jako *+60(|+\)\1 0
. W takim przypadku funkcją jest ( | +): + \ zastosowane w sekwencji oblicza sumy cząstkowe (ex + \ 1 2 3 to 1 3 6) i | odwraca sekwencję, więc każda 'iteracja' obliczamy sumy cząstkowe dwóch poprzednich liczb Fibonacciego i zwracamy częściowe sumy odwrócone 60(|+\)\1 0
generują sekwencje 1 0, 1 1, 2 1, 3 2, 5 3, 8 5, 13 8, 21 13, ... *+
nakładane na ten wynik przerzucają (trasują go) i przyjmują pierwszą. Wynik jest sekwencją 1 1 2 3 5 8 13 21 34 55 ..
(cond)function\args
stosuje funkcję (function (.. function (args))) podczas warunku true i zwraca sekwencję częściowych wyników
function[arg]
nałożone na funkcję więcej niż jednego argumentu tworzy rzut (częściowe zastosowanie)
Możemy podać nazwę argumentom, ale implikowane nazwy to x, y, z
{y-x x bin y}[*+60(|+\)\1 0]
deklaruje lambda za pomocą argumentów x, y z rzutowaniem częściowym (arg x jest serią Fibonacciego, oblicza się jako * + 60 (| +) \ 1 0). x oznacza wartości Fibonacciego, a y liczbę do przetworzenia. Wyszukiwanie binarne (bin) służy do zlokalizowania indeksu większej liczby Fibonacciego <= y ( x bin y
) i odjęcia odpowiedniej wartości x.
Aby obliczyć iloczyn z częściowych wyników, odwracamy je i obliczamy różnicę dla każdej pary ( -':|
), upuszczamy pierwszą ( 1_
ponieważ wynosi 0) i mnożymy przez ( */
).
Jeśli interesuje nas skumulowana suma, kod jest taki sam, ale z +/
zamiast */
. Możemy również użyć dowolnego innego operatora diadic zamiast + lub *
O wydajności wykonania
Wiem, że w tym konkursie wydajność nie stanowi problemu. Ale w tym problemie możemy wahać się od kosztu liniowego do kosztu wykładniczego, więc jestem ciekawy.
Opracowałem drugą wersję (długość 48 bajtów bez komentarza) i powtarzałem przypadki testowe baterii 1000 razy w obu wersjach.
f:*+60(|+\)\1 0;m:{*/1_-':|(0<){x-f f bin x}\x} /new version
czas wykonania to: oryginalna wersja 0'212 seg, nowa wersja 0'037 seg
Oryginalna wersja oblicza serię fibbonaci raz na aplikację funkcji; Nowa wersja oblicza Fibonacciego tylko jeden.
W obu przypadkach obliczenia serii Fibonacciego wykorzystują rekurencję ogona
2
Można rozłożyć jako-1 + 3
. Prawidłowe stwierdzenie twierdzenia Zeckendorfa jest takie, że dodatnią liczbę Fibonacciego można jednoznacznie rozłożyć jako sumę niesekwencyjnych liczb Fibonacciego o dodatnim indeksie.