首先,保留几位有效数字和保留小数点几位小数是两个概念。如果不清楚的请出门百度。

我也是被坑过才知道的,一直以为保留小数点后n位 和 保留n位有效数字 是一回事儿。代码写完了发现和实际计算结果不同。突然想起来这两个概念不同。小数点后n位 就是大家常说的 round($val,n); 就可以了;但是n位有效数字是从第一个不为0的位开始往后保留三位。这个就麻烦了哈。用了大约一小时写出下面这个方法;

$res = 1234567894;
$valid_num = 3;//保留几位有效数字

print_r(get_valid_num($res, $valid_num));
function get_valid_num($value, $valid_num)
{
    if (!is_numeric($value)) {
        return '不是数字';
    }
    //拿到数据先看小数点在第几位
    $value_str = $value . "";
    $index = stripos($value_str, ".");
    if (false == $index) {  //如果是整数 返回总长度
        $index = strlen($value_str);
    }
    //小数点的向右移动 $valid_num 位 保证需要的有效数字全部在小数点左侧
    $right_move = $valid_num - $index;
    if ($value < 1) {
        for ($i = 2; $i <= strlen($value_str); $i++) {
            if ($value_str[$i] == 0) {
                $right_move++;
            } else {
                break;
            }
        }
    }
    $after_value = $value * (10 ** $right_move); //移动后的数值

    $after_value = round($after_value, $value < 1 ? 1 : 0);//四舍五入

    $return['value'] = $after_value * (10 ** -$right_move);//小数点移动之后再移动回来
    $return['str'] = $after_value . " * 10^".(-$right_move);//返回的字符串

    if($right_move == 0){ //10的0次幂=1  所以优化一下
        $return['str'] = $after_value;//返回的字符串
    }
    return $return;


}