在 PHP 中,浮点型数据(也称为浮点数 float、双精度数 double 或实数 real)可以使用以下语法定义:
<?php $a = 1.234; $b = 1.2e3; $c = 7E-10; $d = 1_234.567; // 从 PHP 7.4.0 开始支持 ?>
浮点数的形式表示(PHP 7.4.0 之前不支持下划线):
LNUM [0-9]+(_[0-9]+)* DNUM ([0-9]*(_[0-9]+)*[\.]{LNUM}) | ({LNUM}[\.][0-9]*(_[0-9]+)*) EXPONENT_DNUM (({LNUM} | {DNUM}) [eE][+-]? {LNUM})
浮点数的字长和平台相关,尽管通常最大值是 1.8e308 并具有 14 位十进制数字的精度(64 位 IEEE 格式)。
一、浮点数的精度
浮点数的精度是有限的。通常情况下,PHP 使用 IEEE 754 双精度格式,由于取整而引起的最大相对误差约为 1.11e-16,在进行非基本数学运算时,可能会产生更大的误差,并且需要考虑误差传递的问题。
此外,对于以十进制表示的有理数,如 0.1 或 0.7,无论尾部的数字有多少位,都无法精确地转换为内部使用的二进制格式。因此,在不丢失一些精度的情况下,将其转换为二进制格式可能会导致混乱的结果。例如,floor((0.1+0.7)*10) 通常会返回 7 而不是预期的 8,因为该结果的内部表示类似于 7.9999999999999991118…
因此,我们不能完全依赖浮点数结果的最后一位是精确的,也不能直接比较两个浮点数是否相等。如果确实需要更高的精度,应该使用任意精度数学函数或 gmp 函数。
二、转换为浮点数
1、从string转换
如果 string 是 numeric 或者前导数字, 则将它解析为相应的 float 值,否则将转换为零(0)。
2、从其他类型转换
对于其它类型的值,其情况类似于先将值转换成 int,然后再转换成 float。
注意:某些类型在转换成 int 时有未定义行为,转换为 float 时也会如此。
三、比较浮点数
由于内部表达方式的原因,直接比较两个浮点数是否相等是有问题的。然而,我们仍然可以采用一种间接的方法来比较浮点数的值。为了测试浮点数是否相等,我们可以使用一个稍微大一点的最小误差值,也称为机器极小值(epsilon)或最小可表示差异。这个值代表了计算中可以接受的最小差别。通过比较, $a 和 $b 在小数点后五位精度内是相等的。
<?php $a = 1.23456789; $b = 1.23456780; $epsilon = 0.00001; if(abs($a-$b) < $epsilon) { echo "true"; } ?>
四、NaN
某些数学运算会产生一个由常量 NAN 所代表的结果。此结果代表着一个在浮点数运算中未定义或不可表述的值。任何拿此值与其它任何值(除了 true)进行的松散或严格比较的结果都是 false。由于 NAN 代表着任何不同值,不应拿 NAN 去和其它值进行比较,包括其自身,应该用 is_nan() 来检查。