Вычислить супер корень числа


10

В математике тетрация является следующим гипероператором после возведения в степень и определяется как повторное возведение в степень.

Добавление ( удалось п раз)

Умножение ( добавляется к себе, п раз)

Возведение ( умножается само по себе, п раз)

Тетрация ( возведенная в степень самостоятельно, n раз)

Обратные соотношения тетратации называются супер-корнем и супер-логарифмом. Ваша задача - написать программу, которая с учетом 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?
Tobia

1
Можете ли вы дать математическое представление супер-корня? Боюсь, я до сих пор не понимаю, как это определяется.

Ответы:


6

C - стремясь к ясности, не пытался сжать код

Учитывая вклад:

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

Тогда в usually обычно должно быть только одно решение, что значительно упрощает задачу.

Код является:

#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,44466786101 ...)


Вы действительно много знаете о математике, которую я могу рассказать :) (Этот ответ) ∈ (действительно впечатляющие вещи)
Альберт Реншоу

@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

Mathematica, 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 - количество запрашиваемых цифр точности. Эта сложность - мое интуитивное понимание, я не представил формального доказательства.

Этот алгоритм не требует больших целых чисел, он использует функцию log только для обычных чисел с плавающей запятой, поэтому он весьма эффективен для очень больших чисел, вплоть до предела реализации с плавающей запятой (либо двойной точности, либо произвольных больших чисел 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}

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

Это просто деление пополам. Ungolfed:

-> 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

к [52 символа]

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

Модифицированная версия моего собственного поста n- го корня

Пример:

{{{((%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

Haskell

Простой линейный поиск, возвращает первое, наименьшее найденное совпадение.

{-
    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(°+

Порт ответа @KeithRandall 's Python .

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

Объяснение:

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.