Когда это стало кодом гольф? Я думал, что это было проблемой кода, чтобы придумать лучший алгоритм!
Код-гольф
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.)