математика — PHP Надежный расчет кубического корня

Это кажется легким делом, но у меня возникают проблемы, чтобы решить эту проблему:

Я хотел бы рассчитать уровень на основе данных очков опыта (опыта). Поэтому я использую формулу кубического корня и округляю до следующего целого числа. Следующий уровень достигается, когда точно достигает опыта level^3, Количество уровней не ограничено, поэтому я бы не использовал предварительно рассчитанную таблицу поиска.

Когда я использую стандартную PHP математику

floor( pow( 10648, 1/3))

Он возвращает 21 вместо 22. Это неверно, поскольку 21 ^ 3 дает 92161. Причина в том, что из-за ограниченной точности с плавающей точкой pow (10648, 1/3) возвращает не совсем 22, вместо этого он возвращает 21.9993112732.
Вы можете проверить это с помощью следующего фрагмента:

$lvl = pow( 10647, (float) 1 / 3);
print number_format( $lvl, 10);

Это мой обходной путь. Но я не уверен, что это пуленепробиваемый

public static function getLevel($exp) {
$lvl = floor(pow($exp, (float) 1 / 3));    // calculate the level
if (pow($lvl + 1, 3) == $exp) {            // make check
$lvl++;                                // correct
}
return $lvl;
}

Кроме того, это выглядит немного хрупким, когда дело доходит до проверки. Таким образом, остается вопрос:
Существует ли надежный, эффективный и пуленепробиваемый способ вычисления кубического корня (из положительных чисел).

Благодарю.

2

Решение

Я думаю, что это единственная модификация, в которой нуждается ваш код:

public static function getLevel($exp) {
$lvl = floor(pow($exp, (float) 1 / 3));
if (pow($lvl + 1, 3) <= $exp) {   // compare with <= instead of ==
$lvl++;
}
return $lvl;
}
2

Другие решения

Если вам нужны 100% надежные результаты, вы, вероятно, должны использовать Библиотека GMP для вычислений произвольной точности.

gmp_root Функция должна делать то, что вам нужно. Вам понадобится PHP версии 5.6 или новее с включенным расширением GMP.

$num = gmp_init(10648);
$third_root = gmp_root($num, 3);

var_dump(gmp_strval($third_root));  // string(2) "22"

Если библиотека GMP неудобна для вас, и вы уверены, что у вашего номера есть целочисленный корень, вы можете попробовать следующее:

function getLevel($base, $root = 3.0) {
$exact = pow($base, 1.0 / $root);
$ceil  = ceil($exact);
$floor = floor($exact);

if (pow($exact, $root) == $base) { return $exact; }
if (pow($ceil,  $root) == $base) { return $ceil;  }
if (pow($floor, $root) == $base) { return $floor; }

// Default: no integer root
return FALSE;
}

Он проверяет точное, floor, а также ceil значения результата, чтобы найти, который является правильным ответом. Если это не один из трех, то число не имеет целочисленного корня и по умолчанию FALSE,

Вот пример этого в действии:

var_dump(getLevel(10648, 3)); // 22^3 => float(22)
var_dump(getLevel(16807, 5)); //  7^5 => float(7)

var_dump(getLevel(1,  3)); // Should always return 1 => float(1)
var_dump(getLevel(1, 99)); // Should always return 1 => float(1)

var_dump(getLevel(7)); // Has no integer 3rd root => bool(false)

Конечно, вы можете сделать функцию return $floor; или же return $ceil; как случай по умолчанию, но это зависит от вас.

1

По вопросам рекламы [email protected]