这看起来很容易,但我很难解决这个问题:
我想根据给定的经验点(exp)来计算一个等级。因此,我使用了立方根公式,并向下四舍五入到下一个整数。当exp恰好达到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;
}
此外,当涉及到支票时,它看起来有点脆弱。因此,问题仍然存在:有没有一种可靠、高效、防弹的方法来计算(正数的)立方根。
谢谢。
我认为这是您的代码所需要的唯一修改:
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;
}
如果您需要100%可靠的结果,您可能应该使用GMP库进行任意精度计算。
gmp_root
函数应该满足您的需要。您需要启用GMP扩展的PHP 5.6或更新版本。
$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;
作为默认情况,但这取决于您自己。