2

我正在用 PHP 编写赔率转换器,并遇到将小数赔率转换为小数赔率的代码

function dec2frac($dec) { 
    $decBase = --$dec; 
    $div = 1; 
    do { 
        $div++; 
        $dec = $decBase * $div; 
    } while (intval($dec) != $dec); 
    if ($dec % $div == 0) { 
        $dec = $dec / $div; 
        $div = $div / $div; 
    } 
    return $dec.'/'.$div; 
} 

当我测试代码时,它有时会在计算中成功,有时会尝试加载页面一段时间但没有成功,所以我认为它以某种方式卡在了循环中。我将时间限制设置为 1 秒,并在循环中出现回声,这证实了我的怀疑。我将这两个回声添加到循环中,这样我就可以看到出了什么问题。

echo "$dec $div<br/>";
echo var_dump(intval($dec) == $dec)." $dec is int<br/>";

失败时的示例打印输出,使用十进制 = 1.6

1.2 2
bool(false) 1.2 is int
1.8 3
bool(false) 1.8 is int
2.4 4
bool(false) 2.4 is int
3 5
bool(false) 3 is int //应该在这里中断并返回 3/5
3.6 6
bool( false) 3.6 是 int
4.2 7
bool(false) 4.2 是 int

成功时的示例打印输出,使用小数 = 1.8

1.6 2
bool(false) 1.6 是 int
2.4 3
bool(false) 2.4 是 int
3.2 4
bool(false) 3.2 是 int
4 5
bool(true) 4 是 int

为什么有时它不能识别整数?如何修复它以便在找到整数时退出循环?

4

1 回答 1

2

它看起来像一个浮动精度舍入误差。intval($dec) 和 $dec似乎相等,但实际上并非如此。差异可以忽略不计,但严格的平等失败了。

在我的 64 位系统上,该函数以 1E-15 的精度工作,以 1E-16 的精度循环。

一般来说,要避免严格比较两个浮点数。如果两个浮点数的差小于阈值,则将它们视为“相等” 。有计算这个阈值的方法(谷歌“确定机器精度”),因为它在任何地方都不一样。

因为在我的 PHP.INI 我有默认值

; The number of significant digits displayed in floating point numbers.
; http://php.net/precision
precision = 14

那么即使一个是 3 而另一个是 3.0000000000044,这两个数字也会显示相等,并且菱角不会被注意到。

精度 = 18,$dec显示不是您所期望的:

1.20000000000000018
1.80000000000000027
2.40000000000000036
3.00000000000000044

尝试:

function dec2frac($dec) {
    $decBase = --$dec;
    $div = 1;
    do {
        $div++;
        $dec = $decBase * $div;
    } while (abs(intval($dec) - $dec) > 1e-15);
    if (($dec % $div) == 0) {
        $dec = $dec / $div;
        $div = $div / $div;
    }
    return $dec.'/'.$div;
}
于 2012-09-30T21:53:35.257 回答