Sprintf浮动一个带有右边填充零的18,16浮点数

时间:2012-12-18 10:13:32

标签: php printf

我正在尝试使用填充零向右浮动(18,16),但这不起作用,因为它总是以1而不是零结束。我的猜测是因为我说错了,但我不确定如何纠正。

样品: 12.12234必须变为12.1223400000000001.01必须变为1.01000000000000

为了达到这个目的,我正在使用sprintf('%18.016f', $fMyFloat);,但这总是以1而不是0结束。显然我在监督某些事情,我只是不知道是什么。非常感谢任何帮助。

1 个答案:

答案 0 :(得分:4)

此测试代码:

$data = array(
    12.12234,
    1.01
);
foreach($data as $fMyFloat){
    echo sprintf('%18.016f', $fMyFloat) . PHP_EOL;
}

...在我的64位计算机中打印出来:

12.1223399999999994
1.0100000000000000

您正面临众所周知的浮点精度问题。将整数从基数10转换为基数2非常简单(而且确切)但是基数10的浮点数不能总是在基数2中完全表示。这个问题不是特定于PHP,而是PHP手册中有warning

  

浮点数的精度有限。虽然这取决于   在系统中,PHP通常使用IEEE 754双精度格式,   由于订单的舍入,这将产生最大的相对误差   1.11e-16。非基本算术运算可能会更大   错误,当然,必须考虑错误传播   几个操作复杂化。

     

此外,有理数的数字可以完全表示为   基数10中的浮点数,如0.1或0.7,没有   精确表示为基数2中的浮点数,即   内部使用,无论尾数的大小。因此,他们   没有a就无法转换成它们的内部二进制对应物   精度损失小

获得此类精确度的唯一机会是将数字操作为字符串。 PHP捆绑了两个任意精度库,可以在您需要匹配字符串时帮助您:GNU Multiple PrecisionBC Math。这是bcmath的一点点破解:

$data = array(
    '12.12234',
    '1.01'
);
bcscale(16);
foreach($data as $fMyFloat){
    echo bcdiv($fMyFloat, 1) . PHP_EOL;
}

但是,在这种情况下,您可以使用简单的字符串函数:

$data = array(
    '12.12234',
    '1.01'
);
foreach($data as $fMyFloat){
    list($a, $b) = explode('.', $fMyFloat);
    echo $a . '.' . str_pad($b, 16, 0) . PHP_EOL;
}