可以使用以下语法之一定义浮点类型:
<?php $a = 1.234; $b = 1.2e3; $c = 7E-10; $d = 1_234.567; // 从 PHP 7.4.0 开始支持 ?>
浮点数的正式表示(下划线在PHP7.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通常使用IEEE754double格式,舍入引起的相对误差最大值为1.11e-16。非基本算术运算可能会带来更大的误差,在执行复合运算时可能会考虑误差的传播。
另外,像0.1和0.7这样可以用10进制正确表现的有理数,即使有几个假数部,内部使用的2进制也不能正确表现,所以转换为2进制的话精度会稍微下降。这可能会导致结果混乱。例如,floor((0.1+0.7)*10)通常返回7,而不是预期的8。这是因为结果的内部表示实际上就像7.99999999991118。
因此,不要将浮点结果信任到最后一位,也不要比较两个浮点是否相等。如果需要更高的精度,则必须使用任意精度的数学函数或gmp函数。
转换为浮点
从字符串转换
如果字符串是数字或第一个数字,则将其解析为相应的浮动值。否则,将转换为零(0)。
来自其他类型的转换
对于其他类型的值,情况类似于将值转换为整型,然后将其转换为浮点。
注意:
某些类型在转换为整型和浮点时具有未定义的行为。
比较浮点
如上面的警告所示,比较两个浮点是否相等对于内部表示是有问题的。尽管如此,也有比较浮点值的绕道。
要测试浮点是否相等,请使用略大于值的最小错误值。此值也称为计算机的最小值(伊普西隆)或整数的最小单位,是计算中接受的最小差值。
$a和$b相当于小数点后五位:
<?php $a = 1.23456789; $b = 1.23456780; $epsilon = 0.00001; if(abs($a-$b) < $epsilon) { echo "true"; } ?>
NaN
特定的数学运算生成由常数NAN表示的结果。此结果表示浮点运算中未定义或无法表达的值。此值与其他值(不包括真值)的松散或严格比较为假。
由于NAN表示不同的值,所以NAN不应与包括其自身的其他值进行比较,而是将is_必须在nan()中进行检查。
$x=8-6.4;//其等于1.6
$y=1.6;
var_dump($x=$y);//这不是真的吗
PHP认为1.6(来自差异)不等于1.6。要使其工作,请使用round()
var_dump(循环($x,2)=循环($y,2));//这是真的
发生这种情况可能是因为$x实际上不是1.6,而是1.599999..var_dump向您显示为1.6。
一般计算提示:如果你在跟踪资金,请帮助你自己和你的用户在内部用美分处理所有事情,并尽可能多地用整数计算。尽可能以美分为单位存储值。以美分为单位进行加减。在wii涉及浮动的每一个操作中,问问自己“如果我在这里得到一分钱的零头,在现实世界会发生什么”,如果答案是这个操作将生成整数分钱的交易,不要试图携带虚构的零头精度,这只会在以后把事情搞砸。
这只是对“浮点精度”插图的一个评论,其中写道:“这与……0.3333333有关。”
虽然作者可能知道他们在谈论什么,但这种精度损失与十进制表示法无关,它与有限寄存器中的浮点二进制表示有关,例如,当0.8以十进制结束时,它是二进制中重复的0.110011001100…被截断。0.1和0.7在二进制中也是非终止的,因此它们也被截断,并且这些截断的数字之和不等于0.8的截断二进制表示(这就是为什么(floor)(0.8*10)产生不同的、更直观的结果)。然而,由于2是10的因子,任何以二进制结尾的数字也以十进制结尾。
你写下8-6.4不等于1.6。真正的原因是绝对ε值取决于指数,而浮点的转换向下舍入到下一个可能的值。6.4具有比1.6更大的舍入误差,并且计算8-6.4的结果误差大于1.6本身的舍入错误。(float)1.6是最接近1.6的数字,而(float)(8-6.4)大于1.6-转换为浮点四舍五入。因此,1.6将类似于1.599999,而8-6.4将有点像1.600001
解决方案是对常量表达式使用十进制数学。
我想指出PHP浮点支持的一个“特性”,这一点在任何地方都不清楚,让我发疯。
该测试(其中var_dump表示$a=0.1和$b=0.2)
如果($a>=$b)回显“废话”;
在某些情况下会由于隐藏精度而失败(标准C问题,PHP文档没有提到,所以我假设他们已经摆脱了它)。我应该指出,我最初认为这是浮点存储为字符串的问题,所以我强制它们为浮点,但它们仍然没有得到正确的计算(可能有两个不同的问题)。
为了解决这个问题,我不得不做这个可怕的混搭(相当于:
如果(一轮($a,3)>=一轮($b,3))回响“废话”;
这是可行的。显然,尽管var_dump表示变量是相同的,并且它们应该是相同的(从0.01开始,重复添加0.001),但事实并非如此。有一些隐藏的精确性让我把头发扯下来。也许这应该添加到文档中?