考虑到PHP8.1+,所有语法都是有效的:
var_dump(0.0); // outputs float(0)
var_dump(0.00); // also outputs float(0)
var_dump(0.0000000); // --||--
// ...
是否有技术(即使在C背景下)这些定义之间的差异?
它会以某种方式影响精度吗?如果不是,为什么允许这样的语法?
这和both有关系吗?方式?:var_dump(000042.42000000);
也是有效的语法…
PHP没有正式的规范。因此,没有正式的规范说0.0
和0.00
解析为相同的值。虽然对于0.0
和0.00
不太可能出现这种情况,但是对于其他浮点量,其解析可能产生不同的值,即使字面量在名义上表示相同的值,如下所述。
PHP手册似乎很少提到浮点量的解析。(我没有检查整个文档,只检查了"类型系统"部分的"浮点数"小节。)
PHP通常使用C实现。C标准允许不同源形式的浮点字面值产生不同的值,即使它们在名义上指定相同的数字。这是由于C 2018 6.4.4.2 5中的遗漏,它说相同形式的字面值产生相同的数字,"相同源形式的所有浮动常量77)应转换为具有相同值的相同内部格式",但省略了指定不同形式但相同标称值的"常量"转换为相同值。不规范的脚注77明确指出:"1.23
、1.230
、123e-2
、123e-02
和1.23L
都是不同的源格式,因此不需要转换为相同的内部格式和值。">
PHP源代码当然不是C源代码。然而,对于用C编写的PHP实现来说,使用标准C库工具解析PHP源代码是很自然的。特别是,我们可能会发现strtod
用于解析浮点量。那么我们就面临这样一个事实,即strtod
是根据上面引用的6.4.4.2中的规则来指定的。C 2018 7.22.1.3指定strtod
,第5段说:
…从第一个数字或小数点字符(以先出现者为准)开始的字符序列根据6.4.4.2的规则被解释为浮动常量,…
允许不同的形式可能产生不同的值,主要是为了考虑解析指数表示法的历史困难。4.2
和42000000000000000000000000000000000000000e-40
名义值相同。但是,解析后者比较困难,因为1040不能用硬件浮点数常用的格式表示。它要求有效位为81位,而普通硬件中最宽的有效位通常是53位或64位。所以像这样的字面量不能仅仅通过计算有效数的值并乘以或除以指数的值来解析。因此,能够用正确舍入解析浮点值的软件必须特别设计。在编写上面引用的C标准段落时,并没有期望解析浮点数能够达到产生正确舍入结果所需的严格程度。今天,由于学术研究,这样的软件是已知和可用的。然而,它并不一定存在于所有标准C库的实现中。
我希望0.0
和0.00
产生相同的值,正好是零,因为解析有效数将产生零,并且计算指数符号或非常长的有效数的结果的困难不会影响零。类似地,我希望即使是一般的解析软件也能对1.38
和138e-2
产生相同的值,因为所涉及的计算完全在所有所需值都可以用硬件浮点格式表示的范围内,前提是138e-2
计算为138/100而不是138•0.01。然而,如果这在业余软件中不成立,也就不足为奇了。
然而,对于较大的指数,我希望相同数字的不同形式是相等的,只有当软件故意使用已发布的算法来编写时。