曾经面试让手动实现保留2位小数的函数,现在想来将其发出来(排版可能不好,因为csdn体验度本来就差)
实现思想:
利用二分法找整数,循环迭代找小数。
例如:111开方,保留两位小数。
(10+a)^2 = 111
a^2 + 2 * 10 * a = 11
a = 0.55 - a^2 / 20
因为0<a<1
-0.05<-a^2/20<0
0.5<a<0.55
所以小数第一位为5
然后找第二位
(10.5+a)^2 = 111
重复第一步操作,直到找到第二位小数。
注意:这里为了获得更加精准的结果通常要多运行一位。
例如获取2为小数,实际要计算三位精度,然后再取两位小数(四舍五入)
// 开方
function _sqrt($targetNumber, $d){
if($targetNumber < 0 ){
exit('error');
}else if($targetNumber == 0 ){
return 0;
}
$ac = 1;$ack = $ac;
for($i = 0; $i <= $d; $i++){
$ack = $ack / 10;
}
$sqrtNumber = findInteger($targetNumber);
while(1){
if($ac == $ack) break;
$decimal = ($targetNumber - $sqrtNumber * $sqrtNumber) / 2 / $sqrtNumber;
$sqrtNumber = $sqrtNumber + $decimal - $ac / 2 / $sqrtNumber;
$ac = $ac / 10;
}
return sprintf("%.".$d."f", $sqrtNumber);
}
//整数
function findInteger($targetNumber){
$sqrtNumber = $targetNumber;
while(1){
$sqrtNumber = floor($sqrtNumber / 2);
$square = $sqrtNumber * $sqrtNumber;
if($square - $targetNumber > $targetNumber){
continue;
}
$remain = $square - $targetNumber;
$sqrtNumber = $sqrtNumber - floor($remain / 2 / $sqrtNumber);
while(1){
if($sqrtNumber * $sqrtNumber < $targetNumber) break;
$sqrtNumber--;
}
break;
}
return $sqrtNumber;
}
$number = '216';
echo _sqrt($number,2);