基本原理
与常见的二分法,牛顿迭代法的思路不一样。此方法直接求出2的平方根的二进制表示后,再转换为10进制输出,理论上可以实现无限的精度。基本思路是逐一判断1.0后跟的序列中的每一位应该是1还是0。
解题程序
<?php
//求出2的平方根,以二制数表示,并且不含小数点
$r = sqrt2(60);
binPrint($r);
//显示十进制数的结果
$d = binSqrt2dec($r);
echo $d;
//求出2的平方根,以二制数表示,$n为结果保留的位数
//基本思路是逐一判断1.0后跟的序列中的每一位应该是1还是0
function sqrt2($n){
$a=1;
$b=2;
$binResult=[];
$binResult[0]=1;
$currentBit = 1;
while($currentBit<$n){
$left = $a*2+1;
$left = $left*$left;
$right= $b*4;
//当变成两个大的浮点数进行比较时,将不能求得精确的结果,后续改进时需要做大整数的乘法和比较
if($left<$right){
$a=$a*2+1;
$binResult[$currentBit]=1;
}else{
$a=$a*2;
$binResult[$currentBit]=0;
}
$b=$right;
$currentBit++;
}
return $binResult;
}
//补齐长度为4的倍数
function align4($v){
$vLen=count($v);
$diff = $vLen % 4;
if( $diff == 0){
return $v;
}
$diff = 4-$diff;
for($j=$vLen;$j<$vLen+$diff;$j++){
$v[$j]=0;
}
return $v;
}
//输出二进制数组内容,按低位到高位输出,每4位一个空格
function binPrint($v){
//补0对齐
$v = align4($v);
$vLen=count($v);
$cnt = 0;
for($i=0;$i<$vLen;$i++){
echo $v[$i];
$cnt++;
if($cnt ==4){
echo " ";
$cnt =0;
}
}
echo "\n";
}
//将二制数的平方根转成10进制数
function binSqrt2dec($v){
$vLen=count($v);
$r = 1;
$base = 1;
//整数位是1,不用转换,只转换小数部分
for($i=1;$i<$vLen;$i++){
$base*=2;
$t=$v[$i]/$base;
$r+=$t;
}
return $r;
}