Оцініть n-ту гіпероперацію


12

Я розумію, що це трохи математика, але - ось що.

У математиці послідовність гіпероперації - це нескінченна послідовність арифметичних операцій (так звана гіпероперація), яка починається з одинарної операції наступника, потім продовжується з двійковими операціями додавання, множення та експоненціації, після чого послідовність протікає з подальшими бінарними операціями, що виходять за межі експоненцію, використовуючи право-асоціативність.

Ваша мета полягає в тому, щоб написати програму, яка приймає три цілі числа x, y і n як вхід і виводить результат n-ї гіперпереробки на x і y.

Напр

1 1 1 виходи 2

2 4 4 виводи 65536

3 3 4 виходи 7625597484987

  • Програма повинна бути написана найкоротшим бітом коду.
  • Ви можете приймати дані STDINабо з файлу, або з нього.
  • Функції бібліотеки не дозволені.
  • Обмеження введення: n буде ≥ 1.

http://en.wikipedia.org/wiki/Tetration має гарне пояснення, якщо ви не можете обмотати голову.


Що таке n=1? Якщо це x+yабо x+1, 1 1 1слід повернутися2
Джон Дворак

Я знав, що десь помилився :) виправлено, THX.
Soham Chowdhury

1
Я написав мені псевдо-код, потім зрозумів, що це насправді дійсний код Ruby (майже :-()
Джон Дворак

1
Ні, n> = 1.
Soham Chowdhury

Відповіді:


4

Рубі, повільно, 86 84 83 символи

def f x,y,n
n>1?(c=x;2.upto(y){c=f(x,c,n-1)};c):x+y
end
p f *gets.split.map(&:to_i)

Рубі, швидко, 96 94 93 символи

def f x,y,n
n>1?(n>2?(c=x;2.upto(y){c=f(x,c,n-1)};c):x*y):x+y
end
p f *gets.split.map(&:to_i)

Перша версія є шляхом занадто повільно з останнім тестом, тому я додав версію , яка використовує множення в якості базового випадку замість того. Перша версія вимагає віку для обчислення 3 3 4; другий - миттєвий (на рідній консолі IRB; веб-версія трохи повільніше).

Тут представлено кілька красунь Рубі:

Майже кожен вислів - це вираз у рубіні. Таким чином, ви можете вставити крапки з комою всередину потрійного оператора, якщо у вас є достатня кількість дужок. Coffeescript запозичив це. Він також запозичив синтаксис виклику Рубі "не потрібні пароні".

Неявне повернення: це класна особливість і випливає з попередньої. Дійсно, починати останній рядок функції з returnвважається кульгавим, навіть коли не грає в гольф.

Числа - це об’єкти в рубіні (навіть nullє об’єктом). У рубінах цілі числа мають метод times, який виконує переданий йому блок кілька разів. Це лише один із багатьох методів ітератора Рубі. Тут uptoметод дозволяє нам зберегти ще два символи над тим, що timesдозволяє нам.

унарний *оператор знаку оклику тут. Він перетворює масив у список аргументів. Як у Javascript Function#apply, але він коротший і кращий.

Унар &перетворює процедуру в блок. Хоча :to_iце символ, він перетворюється на процедуру досить добре. А саме, це перетворюється на процедуру, яка викликає to_iсвій аргумент і повертає результат. Детальніше про переповнення стека.

Можна було б отримати його ще швидше, використовуючи n=3в якості базового випадку, але я боюся, що він не потрібен. Це коштувало б лише 11 символів, хоча завдяки ще одній красі рубіну: оператору експоненції **. У Python є цей оператор, але це не перший (як @ aka.nice зазначив - спасибі -, Fortran вже мав цього оператора).

Інтернет-перекладач рубіну доступний тут: http://repl.it/Ikj/1


Приємно, але я все ще чекаю на вихід з 3 3 4:) Це дуже повільно.
Soham Chowdhury

@SohamChowdhury базовим випадком є ​​доповнення. З базовим випадком множення це було б дуже повільним (і довше). Я рекомендую замість цього тестувати з експоненцією ;-)
Джон Дворак

Це може заощадити час на використання мемуалізації, але це коштуватиме декількох байтів (зовсім небагато)
Джон Дворак

Додайте іншу версію потім :)
Soham Chowdhury

1
оператор ** вже існував у FORTRAN у 50-х, і ALGOL матиме на 1 символ менше стрілку вгору
aka.nice

6

APL, 62

{1=3⌷⍵:2⌷+\⍵⋄0=2⌷⍵:(⍵[3]⌊3)⌷⍵[1],0,1⋄∇⍵[1],(∇⍵-0 1 0),3⌷⍵-1}⎕

{...}⎕: Бере оцінений вхід (розділені пробілом цифри оцінюються до числового масиву) і застосовує до нього функцію.

1=3⌷⍵:: Якщо n дорівнює 1 ...
2⌷+\⍵: Повернути суму перших 2 елементів (x + y) ...
⋄0=2⌷⍵:: В іншому випадку, якщо y дорівнює 0 ...
(⍵[3]⌊3)⌷⍵[1],0,1: Створіть числовий масив [x, 0,1] і поверніть індекс min(n,3)...
⋄∇⍵[1],(∇⍵-0 1 0),3⌷⍵-1: Інше повернення ∇ (x, ∇ (x, y-1, n), n-1). (∇ - самопосилання)


У мене є "гіпер-рейзер" оператор, який бере функцію і повертає наступну гіперпереробку

{⍺⍺/⊃⍴/⌽⍵}

Наприклад, +{⍺⍺/⊃⍴/⌽⍵}була б функція множення та +{⍺⍺/⊃⍴/⌽⍵}5 3виводи 15.

Але не можу змусити її повторитись. Можливо, хтось ще може це зробити.


Ах, APL. Ударить Python за простоту в будь-який день. </sarcasm> Як це зробити?
Soham Chowdhury

2

Пітона, 83

(На основі відповіді flornquake )

def h(x,y,n):r=n>2;exec"r=h(x,r,n-1);"*y*(n>1);return(x+y,r)[n>1]
print h(*input())

Дуже повільно для великих результатів.

Для 2, 4, 4виходу є 65536.


"дуже повільно", тому моє рішення з 86 символів вважалося поганим.
Джон Дворак

1
@JanDvorak: Чому, на вашу думку, це вважалося поганим? Сохам Чоуддурі просто сказав, що це повільно, і що вам слід додати іншу версію, а не щоб ви замінили своє рішення. (Але, можливо, я це неправильно зрозумів.)
Поновіть Моніку

Ти правий; відновила коротку версію. Тепер я просто чарівник довший за тебе.
Джон Дворак

@WolframH точно. Завжди приємно мати версії.
Soham Chowdhury

2

Пітона, 96 92

def h(x,y,n):r=1;exec(n>2)*y*"r=h(x,r,n-1);";return(r,(x+y,x*y)[n>1])[n<3]
print h(*input())

Вхід: 3, 3, 4
Вихід:7625597484987

Скорочено, використовуючи пару ідей @ WolframH .


2

Гольфскрипт, повільний, 39 символів

 ~{\(.{3${[4$\2$4$.~}4$(*}{;;+}if])\;}.~

(пряма посилання)

Це стандартний рекурсивний алгоритм з базовим випадком n = 1 (додавання) (тобто повільний). Те саме, що я використовував у своєму розчині Ruby

Ось версія з моїми примітками (переважно зберігання стеків). Він не включає одну оптимізацію, яку я додав пізніше:

~{            #read the input and do (x y n f)
 \(.{         #(x y f n-1); if(n-1)
  3${         #(x y f n-1 c)
   4$\2$4$.~  #(x y f n-1 x c n-1 f); call
  }3$(*       #y-1 times
  {\;}4*
 }{           #else
  ;;+         #return (x+y)
 }if
}.~           #once

~є оператором eval. У разі рядків, вона розглядає рядок як програму GolfScript. На щастя, розділений пробілом список цілих чисел є дійсною програмою GolfScript, яка висуває ці цілі числа на стек. У порівнянні з цим, моя попередня версія вхідної програми ( " "/{~}/розділена на пробіл і eval кожна) є досить кульгавою. У разі функцій він викликає функцію. Коли йому передує .(клон), він викликає функцію із собою як перший аргумент.

Здається, Golfscript не дуже добре підходить для створення рекурсивних алгоритмів. Якщо ви хочете рекурсивний алгоритм, який не оптимізується для виклику хвоста, вам потрібно створити та знищити кадри стека, щоб зберегти свої змінні. У більшості мов це робиться автоматично. У golfscript вам доведеться фактично клонувати змінні (власне, записи стека) та знищувати записи стека, які вам більше не потрібні. Гольфскрипт не має поняття стекових фреймів. Чи сказав я, що GolfScript є мовою на основі стека?

Перша вимога зрозуміла. Ви повинні якось вказати аргументи. Приємно лише, якщо вони також зберігають свої початкові позиції. Друга вимога є прикрою, тим більше, що повернене значення знаходиться у верхній частині стека, а golfscript не має можливості видалити будь-який елемент стека. Ви можете повернути стек і відкинути новий верхній елемент, але це швидко накопичується. \;добре. \;\;\;\;\;ні. Можна зробити \;в циклі ( {\;}9*; вартість: 6 символів, щоб відкинути до 9 елементів, або 7 символів, щоб відкинути до 99 елементів), але ми можемо зробити краще:

Гольфскрипт має першокласні масиви. Він також має синтаксис прямого масиву масиву [1 2 3 4]. Що несподіваним є те , що [і ]насправді не є частиною синтаксису. Вони є лише двома операторами: [відмічає поточну позицію на стеку і ]збирає кожен елемент, поки він не знайде позначку початку масиву або не закінчиться стека, і відкидає позначку. Ви навіть можете розірвати ці двоє і подивитися, що відбувається. Ну, і досить цікава річ:

Я сказав, що в гольфскрипті немає поняття стекових фреймів? Я збрехав. Це кадр стека: [. Ви можете відмовитися від нього все відразу: ];. Але що робити, якщо ми хочемо зберегти повернену вартість? Ви можете закрити рамку стека при введенні функції (тоді у нас є злегка виправлена ​​версія масиву проходження проходження - не цікава концепція), або ми можемо закрити рамку стека і взяти останній елемент замість того, щоб повністю відкинути його: ]-1=або ми може uncons останній елемент замість цього, а потім відкинути фрейм: ])\;. Вони однакової довжини, але останні трохи прохолодніші, тому я його використовую.

Отже, замість 6 або 7 символів, щоб зробити прибирання, ми можемо зробити з 5. Я все ще вважаю, що це може бути більше в гольф, але ей, ми зберегли персонажа.


"викликає функцію з собою як перший аргумент" - цікава ідея для рекурсії
aditsu кинеться тому, що SE - EVIL

1

Smalltalk Squeak 4.x смакує багато байтів!

Я міг реалізувати одну з рекурсивних форм у Integer у 71 графі

f:y n:n n=1or:[^(2to:y)inject:self into:[:x :i|self f:x n:n-1]].^self+y

Тоді читання з файлу або FileStream stdin обійдеться мені за руку ... Скрип явно не розглядався як сценарій мови. Тому я витрачу багато байт, щоб створити власні утиліти загального призначення, не пов'язані з проблемою:

Запровадьте цей метод 21-ти чарівників у потоці (щоб пропустити мореплавці)

s self skipSeparators

Реалізуйте цей метод 20 char у поведінці (для читання екземпляра з потоку)

<s^self readFrom:s s

Потім 28 символів у рядку (щоб створити обробку файлу)

f^FileDirectory default/self

Потім 59 символів у FileDirectory (для створення readStream)

r^FileStream concreteStream readOnlyFileNamed:self fullName

Потім 33 символи в BlockClosure (щоб оцінити його n разів)

*n^(1to:n)collect:[:i|self value]

Потім 63 символи в масиві (оцініть аргумент із приймачем та аргументи, взяті з масиву)

`s^self first perform:s asSymbol withArguments:self allButFirst

потім вирішіть проблему, оцінивши цей фрагмент 31 символу де-небудь, щоб прочитати його з файлу з назвою x

|s|s:='x'f r.[0class<s]*3`#f:n:

Навіть не рахуючи комунальних послуг, це вже 71 + 31 = 102 символи ...

Тепер, оскільки я впевнено втрачаю кодGolf, у мене є смішніша реалізація в Integer:

doesNotUnderstand:m
    (m selector allSatisfy:[:c|c=$+])or:[^super doesNotUnderstand:m].
    self class compile:
        m selector,'y y=0or:[^(2to:y)inject:self into:[:x :i|self'
        ,m selector allButLast,'x]].^'
        ,(Character digitValue:()asBit)
        ,(m selector size-2min:1)hex last.
    thisContext sender restart

Цей метод визначає (компілює) двійкові повідомлення, зроблені з n +, якщо його немає (не розуміється одержувачем повідомлення m), і відновить виконання на початку контексту відправника. Я вставив додаткове повернення каретки та пробіли для читабельності.

Зауважте, що (m selector size-2min:1)hex lastце скорочена форма (m selector size>2)asBit printString.

Якби не демонстрація злих наддержав Smalltalk злих сил, остання заява могла б бути замінена коротшою та простішою

^m sendTo:self

Тепер реалізуйте утиліту 28 символів у символі (повторити її n разів у рядку)

*n^String new:n withAll:self

Потім оцініть цей вираз 43 символи:

|i s|i:=0class.s:='x'f r.[i<s]*2`($+*(i<s))

Ми можемо прискорити ще 10 символів, застосувавши в Integer:

++y^self*y

і в цьому випадку ми також маємо короткий код , тому що ми можемо замінити ^',(m selector size-2min:1)hex lastз^1'

За такої високої ціни код працює з другим цілим числом = 0 :)



0

Система комп'ютерної алгебри AXIOM, байти 69

p(x,y,n)==(n<=1=>y+x^n;n=2=>y*x;n=3=>x^y;y<=0=>1;p(x,p(x,y-1,n),n-1))

тест:

(2) -> p(1,1,1)
   (2)  2
                                                 Type: Expression Integer
                                   Time: 0.05 (IN) + 0.03 (OT) = 0.08 sec
(3) -> p(2,4,4)
   (3)  65536
                                                 Type: Expression Integer
                                                              Time: 0 sec
(4) -> p(3,3,4)
   (4)  7625597484987
                                                 Type: Expression Integer
                                                              Time: 0 sec

Це призведе до усунення деяких рекурсій ... Можливо, я поміняю місцями на x і y в якомусь поверненні ... Чи є інші значення тесту?


0

APL (NARS), символи 61, байти 122

{(x y n)←⍵⋄n≤1:y+x*n⋄n=2:x×y⋄n=3:x*y⋄y≤0:1⋄∇x,(∇x(y-1)n),n-1}

тест:

  h←{(x y n)←⍵⋄n≤1:y+x*n⋄n=2:x×y⋄n=3:x*y⋄y≤0:1⋄∇x,(∇x(y-1)n),n-1}
  h 1 1 1
2
  h 2 4 4
65536
  h 3 4 4
∞
  h 3 3 4
7625597484987
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.