Я адаптировал алгоритм, представленный в 1.5.2
(корень kth ) в Современная компьютерная арифметика (Брент и Циммерман) . Для случая (k == 3)
и с учетом «относительно» точной завышенной оценки первоначального предположения - этот алгоритм, по-видимому, превосходит приведенный выше код «Восхищения Хакера».
Не только это, но MCA в виде текста обеспечивает теоретическое обоснование, а также подтверждение правильности и критериев завершения.
При условии, что мы можем предоставить «относительно» хорошую начальную переоценку , я не смог найти случай, который превышает (7) итераций. (Это эффективно связано с 64-битными значениями, имеющими 2 ^ 6 бит?) В любом случае, это улучшение (21) итераций в коде HacDel!
Первоначальная оценка, которую я использовал, основана на «округлении» количества значащих битов в значении ( x ). Учитывая ( b ) значащих бит в ( x ), мы можем сказать: 2^(b - 1) <= x < 2^b
. Я утверждаю без доказательств (хотя это должно быть относительно легко продемонстрировать), что: 2^ceil(b / 3) > x^(1/3)
Вот мой код в том виде, в котором он сейчас ...
static inline uint32_t u64_cbrt (uint64_t x)
{
#if (0) /* an exact IEEE-754 evaluation: */
if (x <= (UINT64_C(1) << (53)))
return (uint32_t) cbrt((double) x);
#endif
int bits_x = (64) - __builtin_clzll(x);
if (bits_x == 0)
return (0); /* cbrt(0) */
int exp_r = (bits_x + 2) / 3;
/* initial estimate: 2 ^ ceil(b / 3) */
uint64_t est_r = UINT64_C(1) << exp_r, r;
do /* quadratic convergence (?) */
{
r = est_r;
est_r = (2 * r + x / (r * r)) / 3;
}
while (est_r < r);
return ((uint32_t) r); /* floor(cbrt(x)) */
}
Вызов crbt
, вероятно, не так уж и полезен - в отличие от вызова sqrt
, который может быть реализован с максимальной эффективностью на современном оборудовании. Тем не менее, я видел выигрыш для наборов значений в 2^53
(точно представлен в двойных единицах IEEE-754), что меня удивило.
Единственным недостатком является деление на: (r * r)
- это может быть медленно, так как задержка целочисленного деления продолжает отставать от других достижений в ALU. Деление на константу: (3)
обрабатывается взаимными методами на любом современном оптимизирующем компиляторе.