Q, 47 байт
m:{*/1_-':|(0<){y-x x bin y}[*+60(|+\)\1 0]\x}
Тест
+(i;m'i:1 2 3 4 5 6 7 8 9 42 1000 12345)
читайте його як пари (i, map (m, i)), де m - обчислювальна функція, i i різні аргументи
пише
1 1
2 2
3 3
4 3
5 5
6 5
7 10
8 8
9 8
42 272
1000 12831
12345 138481852236
Пояснення
n funtion\arg
застосовує функцію (функція (функція (... функція (арг.))), n разів (внутрішньо використовує тал рекурсії), і повертає послідовність результатів. Обчислюємо 60 перших елементів серії фібонаків як *+60(|+\)\1 0
. У цьому випадку функція ( | +): + \, застосований до послідовності, обчислює часткові суми (наприклад, + \ 1 2 3 є 1 3 6), і | обертається послідовність. Отже, при кожній "ітерації" ми обчислюємо часткові суми двох попередніх чисел поля і повертаємо часткове суми, зворотні, 60(|+\)\1 0
генерує послідовності 1 0, 1 1, 2 1, 3 2, 5 3, 8 5, 13 8, 21 13, ..., *+
застосовані над цим результатом, переверніть його (відкладіть) і приймайте перший. Результат - послідовність 1 1 2 3 5 8 13 21 34 55 ..
(cond)function\args
застосовує функцію (функцію (.. функція (args))), коли cond true, і повертає послідовність часткових результатів
function[arg]
застосований над функцією більш ніж одного аргументу створює проекцію (часткове застосування)
Ми можемо назвати аргументи, але неявні імена - x, y, z
{y-x x bin y}[*+60(|+\)\1 0]
оголошує лямбда з аргами x, y з частковою проекцією (arg x - це поле серії, обчислюється як * + 60 (| +) \ 1 0). x представляють значення значень рівня, і y число, яке слід обробити. Бінарний пошук (бін) використовується для пошуку індексу більшого числа значень <= y ( x bin y
) і підрегулювання відповідного значення x.
Щоб обчислити добуток за частковими результатами, ми повернемо їх і обчислимо різницю кожної пари ( -':|
), опустимо першу ( 1_
бо дорівнює 0) і помножимо на ( */
).
Якщо нас цікавить накопичена сума, код той самий, але +/
замість цього */
. Також ми можемо використовувати будь-який інший діадичний оператор замість + або *
Про ефективність виконання
Я знаю, що в цьому конкурсі ефективність не є проблемою. Але в цій проблемі ми можемо варіювати від лінійних витрат до експоненціальних витрат, тому мені цікаво про це.
Я розробив другу версію (довжина 48 байт без урахування коментарів) і повторив тестові випадки батареї 1000 разів на обох версіях.
f:*+60(|+\)\1 0;m:{*/1_-':|(0<){x-f f bin x}\x} /new version
час виконання: оригінальна версія 0'212 с., нова версія 0'037 с
Оригінальна версія обчислює серію fibbonaci один раз за програмою функції; нова версія обчислює лише один.
В обох випадках для розрахунку серій фільтрів використовується хвостова рекурсія
2
можна розкласти як-1 + 3
. Правильне твердження теореми Зекендорфа полягає в тому, що позитивне число Фібоначчі може бути однозначно розкладене як сума непослідовних чисел Фібоначчі з позитивним індексом.