2014-10-30 138 views
2

的可靠计算这似乎是没有道理的,但我无法得到这个解决:PHP立方根

我想计算基于给定的经验值(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; 
} 

此外,它涉及到检查时看起来有点脆弱。所以问题仍然存在: 有没有一种可靠,高效和防弹的计算立方根(正数)的方法。

谢谢。

+1

为什么不使用'round()'而不是'floor()'? – Barmar 2014-10-30 07:52:16

+0

'round()'在某些情况下也失败。以7为例。它应该返回级别1,但是'round(pow(7,(float)1/3))'返回2(错误) – stot 2014-10-30 07:57:51

+1

真正的问题是'1/3'不能完全用浮点数表示。 – Barmar 2014-10-30 08:02:15

回答

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; 
} 
+0

谢谢,现在它应该是防弹的 – stot 2014-11-03 17:08:12

1

如果你需要100个%可靠的结果,你应该使用GMP library任意精度计算。

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

它检查的准确,floorceil结果的值找出哪个是正确的答案。如果它不是三者中的一个,那么该数字没有整数根,并且默认为FALSE

下面是一个example of it in action

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;作为默认的情况下,但是这取决于你。