我想我试过所有的例子从网上!这是我的PHP代码:
echo(number_format(22.95 * 4.1, 2));
字符串
结果是94.10 with PHP。我一直试图用JavaScript得到同样的结果,但无论我怎么尝试,它总是94.09。有什么办法吗?
我试过的一些代码:
var x = 22.95;
var y = 4.10;
var res = x * y;
var res1 = res.toFixed(3);
console.log(res);
console.log(res1);
console.log(Number(res1).toFixed(2));
console.log(Math.round(res * 100) / 100);
型
谢谢你,谢谢
2条答案
按热度按时间vxf3dgd41#
PHP number_format()比JS Number.prototype.toFixed()做的更多,因此,你不能把它当作替身。
除了在基数点前面设置十进制和大数分隔符的参数之外,还包括基数点。
更不用说您可能会以移植函数而告终(参见. What is the JS equivalent to the PHP function number_format?)。提示:给予他们你的号码作为一个新的测试用例。
对于94.10 vs. 94.09,这是在 * Is floating point math broken? * 中的问答,正如我们已经发现JavaScript中缺少舍入,问题陈述如下:
字符串
PHP也是如此:
型
有道理,最后一位的0.5是一个正好介于两个以2为基数的数之间的数。
现在的问题是,如果仍然可以将数字传送到格式上,以便以足够的精度显示,以便内部应用任何浮点计算Number.prototype.toFixed(),不要把浮点精度误差加起来,以至于剩下的精度太少,无法用两个数字来显示它的近似值?
阅读number_format()是 “使用舍入半向上规则”,在传递给toFixed(2)之前舍入¹可能已经足够你的用例了。
基数点后三位数的精度,加上 “必要时舍入”,应足以显示基数点后的两位数:
型
这个数字应该有足够的太小精度错误,以便Number.prototype.toFixed()的两个数字的字符串格式仍然正确地格式化字符串:
型
是的,成功了。幸运的是!因为n / 100在被传递给toFixed(2)之前再次添加了浮点精度错误,这会增加更多的错误!
也许:
型
正如Edward在2016年11月所写:
在使用小数位移位和舍入方法正确舍入后,可以使用number.toFixed(x)方法将其转换为具有所需数量的零的字符串。例如,使用跨浏览器方法将1.34舍入为1.3,然后添加1零,并使用1.3.toFixed(2)转换为字符串(以获得“1.30”)
如果这个肮脏的快捷方式还不够,最后的办法是只对字符串应用舍入规则,例如:
型
如果需要这样做,那么重构roundUpRule()。
¹ Cf. How to round to at most 2 decimal places, if necessary
讨论
十进制数字系统不仅不能表示所有的数字,而且当你准备用有限的小数来显示计算结果时,例如:第二,正如你的问题,你也需要经常地做四舍五入,如果不是经常。
number_format()作为一个用于显示目的的函数已经完成了这个舍入。
当你在计算机系统上进行计算时,你把数字写成小数,计算机已经需要把它们翻译成它自己的二进制数字系统了,再一次,就像其他的数字系统一样,它不能代表所有的数字。而所有这些都只是做浮点计算,这是有误差的,他们甚至可以加起来,失去精度超出你需要的显示精度。
在数学中,0.9 “表示小数点” 后的连续9的重复小数点,因此1.0和0.9 *“表示完全相同的数。
现在,对于十进制数字系统字符串表示的JavaScript,很容易创建类似的印象:
型
toFixed()甚至可以添加重复的零(再次比较w/ WP)。
但这只是一个近似值,静态方法只舍入 “必要时”(自然是为了自己的操作,而不是为了 * 你的 * 数字和 * 你的 * 显示目的)。
型
由于数字存储在位字段中,因此它们只能存储为2的幂;则舍入误差在最后位置的单位中。
因此,在误差增加之前消除误差范围是很重要的。然后,您可以应用字符串格式,错误较少。
与十进制数字系统中显示数字所需的类似,您需要进行舍入。Number.prototype.toFixed()不会为你取整(只为它自己取整):
型
所有这一切自然都已经在现有的Q&A中概述了(参见。* Is floating point math broken? *)正好有您的问题(仅使用不同的值):
型
因此,当你执行浮点运算时,设计错误并始终编码(写入)数字,以便你以你需要的精度向你使用的方法传达值。
甚至有一个关于如何在JavaScript²中使用从phpjs项目(现在是locutus的一部分)复制的代码来执行PHP number_format()的现有Q&A,但是您表达数字的方式破解了它。这表明了忘记number_format()是舍入的是多么容易,因此处理的浮点精度错误与Number.prototype.toFixed()相比已经不同了。
² What is the JS equivalent to the PHP function number_format?
p4tfgftt2#
您在JavaScript端遇到了floating point error。
22.95*4.1
不是94.095
(如您所料),而是(32位)浮点数学中的94.09499999999998
,因此向下舍入为.09
,而不是向上舍入为.10
。在JavaScript中没有很好的方法来解决这个问题,但是可以使用
ini_set('precision', 17)
强制PHP像JavaScript一样工作。参见问题Why can PHP calculate 0.1 + 0.2 when other languages fail?的答案:
PHP有一个
precision
配置值,用于设置浮点数中显示的有效位数。默认情况下为14,这就是0.1 + 0.2
显示为0.3
的原因。但是,如果您这样做:
字符串
您将得到
0.30000000000000004