Обчисліть суперкорінь числа


10

У математиці тетрація є наступним гіпероператором після експоненції і визначається як ітераційна експоненція.

Додавання ( вдалося п раз)

Множення ( додається до себе, п раз)

Зведення ( множиться саме по собі, п раз)

Тетраци ( експоненціруются сам по собі, п раз)

Зворотні відносини тетрації називаються суперкоренем, а супер-логарифмом. Ваше завдання - написати програму, яка, задавши A і B, виводить B- й порядковий суперкорінь A.

Наприклад:

  • якщо A = 65,536і B = 4він друкує2
  • якщо A = 7,625,597,484,987і B = 3він друкує3

A і B - цілі числа, а результат повинен бути числом з плаваючою комою з точністю 5 цифр після десяткової крапки. Результат належить до реального домену.

Будьте уважні, у суперкорінців може бути багато рішень.


1
Чи є мінімальні / максимальні межі вхідних чисел? Чи дійсна відповідь підтримує відповіді з плаваючою комою або лише ціле число?
Джош

3
Якщо кілька рішень, програма повинна знайти все або лише одне?
Йоханнес Х.

5
То які твої критерії виграшу?
Mhmd

2
Чи можете ви навести простий приклад суперкореня, який має більше одного рішення для заданих A і B ≥ 1?
Тобія

1
Чи можете ви дати математичне уявлення суперкореня? Боюся, я все ще не розумію, як це визначено.

Відповіді:


6

C - прагнучи до ясності, не намагався видавити код

З огляду на вхід:

A: A ∈ ℝ, A ≥ 1.0
B: B ∈ ℕ, B ≥ 1

Тоді зазвичай має бути лише одне рішення у ℝ, що значно спрощує проблему.

Код:

#include <stdlib.h>
#include <stdio.h>
#include <math.h>

#define TOLERANCE    1.0e-09

double tetrate(double, int);

int main(int argc, char **argv)
{
    double target, max, min, mid, working;
    int levels;

    if (argc == 3)
    {
        target = atof(argv[1]); // A
        levels = atoi(argv[2]); // B

        // Shortcut if B == 1
        if (levels == 1)
        {
            printf("%f\n", target);
            return 0;
        }

        // Get a first approximation
        max = 2.0;
        while (tetrate(max, levels) < target)
            max *= 2.0;

        min = max / 2.0;

        // printf("Answer is between %g and %g\n", min, max);

        // Use bisection to get a closer approximation
        do
        {
            mid = (min + max) / 2.0;
            working = tetrate(mid, levels);
            if (working > target)
                max = mid;
            else if (working < target)
                min = mid;
            else
                break;
        }
        while (max - min > TOLERANCE);

        // printf("%g: %f = %f tetrate %d\n", target, tetrate(mid, levels), mid, levels);
        printf("%f\n", mid);
    }

    return 0;
}

double tetrate(double d, int i)
{
    double result = d;

    // If the result is already infinite, don't tetrate any more
    while (--i && isfinite(result))
        result = pow(d, result);

    return result;
}

Для складання:

gcc -o tet_root tet_root.c -lm

Бігти:

./tet_root A B

Наприклад:

4 2

$ ./tet_root 65536 4
2.000000

3 3

$ ./tet_root 7625597484987 3
3.000000

3 π

$ ./tet_root 1.340164183e18 3
3.141593

n (2 ½ ) ➙ 2 як n ➙ ∞? (добре відомий ліміт)

$ ./tet_root 2 10
1.416190

$ ./tet_root 2 100
1.414214

$ ./tet_root 2 1000
1.414214

Так!

n (e 1 / e ) ➙ ∞ як n ➙ ∞? (верхні межі)

$ ./tet_root 9.999999999e199 100
1.445700

$ ./tet_root 9.999999999e199 1000
1.444678

$ ./tet_root 9.999999999e199 10000
1.444668

$ ./tet_root 9.999999999e199 100000
1.444668

Класно! (e 1 / e ≅ 1,444466786101 ...)


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

@AlbertRenshaw Це лише реалізація бісекції. Не дуже важко взагалі.
Просто красиве мистецтво

5

Пітон, 87 символів

E=lambda x,n:x**E(x,n-1)if n else 1
def S(A,B):
 x=1.
 while E(x,B)<A:x+=1e-5
 return x

Простий лінійний пошук відповіді.

Поза темою, але що * # $ (@! Працює з **оператором python ?

>>> 1e200*1e200
inf
>>> 1e200**2
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
OverflowError: (34, 'Numerical result out of range')

Варто повідомлення про помилку?
Джош

Чи стає на шляху асоціативність? Можливо , ви порівнюєте (1e200)**2з 1e(200**2)?
danmcardle

2
@Josh: Я повідомив про помилку: bugs.python.org/issue20543 В основному, працюють за призначенням - вони не так багато для IEEE float. Якби вони щось виправили, OverflowErrorу першому випадку було б генерувати .
Кіт Рендалл

3

Математика, 35 40

n /. Solve[Nest[#^(1/n) &, a, b] == n]~N~5

Створює список усіх рішень з 5-ти значною точністю.

n /. Last@Solve[Nest[#^(1/n) &, a, b] == n]~N~5

Ще 5 символів, щоб отримати лише реальне рішення, якого вимагають оновлені правила.


2

Юлія

julia> t(a,b)=(c=a;for j=1:b-1;c=a^c;end;c)
julia> s(c,b)=(i=1;while t(i,b)!=c;i+=1;end;i)
julia> s(65536,4)
2
julia> s(7625597484987,3)     
3

Ігнорована інструкція з плаваючою комою, оскільки питання визначає лише поведінку для цілих чисел.


2

Коли це стало кодовим гольфом? Я думав, що це виклик коду - придумати найкращий алгоритм!


APL, 33 символи

{r←⍵⋄⍺{1≥⍵⍟⍣⍺⊢r:⍵⋄⍺∇⍵+i}1+i←1e¯6}

Це простий лінійний пошук, починаючи з C = 1 + 10 -6 і збільшуючи його на 10 -6 до
    log C log C log C ⋯ A ≤ 1,
де функція log C застосовується рекурсивно B разів.

Приклади

      4 {r←⍵⋄⍺{1≥⍵⍟⍣⍺⊢r:⍵⋄⍺∇⍵+i}1+i←1e¯6} 65536
2.0000009999177335
      3 {r←⍵⋄⍺{1≥⍵⍟⍣⍺⊢r:⍵⋄⍺∇⍵+i}1+i←1e¯6} 7625597484987
3.0000000000575113

Цей код дуже повільний, але для невеликих баз, таких як 2 або 3, він завершується за кілька секунд. Дивіться нижче для кращої речі.


APL, логарифмічна складність

Фактично лінійна складність у кореневому порядку, логарифмічна за розміром результату та точністю:

    час = O (B × log (C) + B × log (D))

де B - кореневий порядок, C - база тетрації, про яку запитують, і D - число розпитаних точностей. Ця складність є моїм інтуїтивним розумінням, я не представив формального доказу.

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

Точність результату можна контролювати, встановивши ⎕CT(порівняльну толерантність) до бажаної допустимої помилки (у моїй системі вона за замовчуванням до 1e¯14, приблизно 14 десяткових цифр)

sroot←{              ⍝ Compute the ⍺-th order super-root of ⍵:
  n←⍺ ⋄ r←⍵          ⍝ n is the order, r is the result of the tetration.
  u←{                ⍝ Compute u, the upper bound, a base ≥ the expected result:
    1≥⍵⍟⍣n⊢r:⍵       ⍝   apply ⍵⍟ (log base ⍵) n times; if ≤1 then upper bound found
    ∇2×⍵             ⍝   otherwise double the base and recurse
  }2                 ⍝ start the search with ⍵=2 as a first guess.
  (u÷2){             ⍝ Perform a binary search (bisection) to refine the base:
    b←(⍺+⍵)÷2        ⍝   b is the middle point between ⍺ and ⍵
    t←b⍟⍣n⊢r         ⍝   t is the result of applying b⍟ n times, starting with r;
    t=1:b            ⍝   if t=1 (under ⎕CT), then b is the super-root wanted;
    t<1:⍺∇b          ⍝   if t<1, recurse between ⍺ and b
    b∇⍵              ⍝   otherwise (t>1) returse between b and ⍵
  }u                 ⍝ begin the search between u as found earlier and its half.
}

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

Приклади

      4 sroot 65536
1.9999999999999964
      4 sroot 65537
2.000000185530773
      3 sroot 7625597484987
3
      3 sroot 7625597400000
2.999999999843567
      3 sroot 7625597500000
3.000000000027626

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


1

Рубін, 79 байт

->a,b{x=y=1.0;z=a;eval"y=(x+z)/2;x,z=a<eval('y**'*~-b+?y)?[x,y]:[y,z];"*99;p y}

Це те саме, що в нижченаведеній програмі, але менш точне, оскільки воно виконує лише 99 циклів.

Рубін, 87 байт

->a,b{x=y=1.0;z=a;(y=(x+z)/2;x,z=a<eval("y**"*~-b+?y)?[x,y]:[y,z])while y!=(x+z)/2;p y}

Спробуйте в Інтернеті

Це просто бісекція. Безголівки:

-> a, b {
    # y^^b by evaluating the string "y ** y ** ..."
    tetration =-> y {eval "y ** " * (b-1) + ?y}

    lower = middle = 1.0
    upper = a

    while middle != (lower + upper) / 2 do
        middle = (lower + upper) / 2

        if tetration[middle] > a
            upper = middle
        else
            lower = middle
        end
    end

    print middle
}

0

k [52 символи]

{{{((%x)*(z*x-1)+y%z xexp x-1)}[x;y]/[2]}[y]/[y<;x]}

Модифікована версія мого поста п - й корінь

Приклад:

{{{((%x)*(z*x-1)+y%z xexp x-1)}[x;y]/[2]}[y]/[y<;x]}[7625597484987;3]
3f 

{{{((%x)*(z*x-1)+y%z xexp x-1)}[x;y]/[2]}[y]/[y<;x]}[65536;4]
2f

0

Хаскелл

Простий лінійний пошук, повертає перше, найменше знайдене збіг.

{-
    The value of a is the result of exponentiating b some number of times.
    This function computes that number.
-}
superRoot a b = head [x | x<-[2..a], tetrate x b == a]

{-
    compute b^b^...^b repeated n times
-}
tetrate b 1 = b
tetrate b n = b^(tetrate b (n-1))

Приклад

*Main> superRoot 65536 4
2
*Main> superRoot 7625597484987 3
3

0

Mathematica, 41 байт без оптимізації

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

Reduce[Nest[Power[#, 1/x] &, a, b] == x, x, Reals]

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

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


0

05AB1E , 16 байт

1[ÐU²FXm}¹@#5(°+

Порт відповіді Python @KeithRandall .

Спробуйте в Інтернеті.

Пояснення:

1                 # Push a 1
 [                # Start an infinite loop:
  Ð               #  Triplicate the top value on the stack
   U              #  Pop and store one in variable `X`
    ²F            #  Inner loop the second input amount of times:
      Xm          #   And take the top value to the power `X`
        }         #  After the inner loop:
         ¹@       #  If the resulting value is larger than or equal to the first input:
           #      #   Stop the infinite loop
                  #   (after which the top of the stack is output implicitly as result)
            5(°+  #  If not: increase the top value by 10^-5

ÐU²FXm}також може бути D²>и.»mдля того ж байтового числа:

  D               #   Duplicate the top value on the stack
   ²>             #   Push the second input + 1
     и            #   Repeat the top value that many times as list
                #   Reduce it by:
        m         #    Taking the power
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.