对number_format()结果取反会改变有效数字的数量


Negating number_format() result changes number of significant digits?

我有一个允许用户通过PayPal购买产品的网站,我允许使用折扣码。我是这样添加折扣的:

'cost'   => -number_format($discount, 2)

然而,有时PayPal会抛出一个错误,当我试图检查。

调试时,我发现有时cost的值会类似于-8.066666666667。我最初感到困惑,但发现在参数列表中移动反运算符(在第一个参数之前)解决了这个问题。

我想确保我明白发生了什么,这样我就不会再犯同样的错误。我想应该是这样的:

  • number_format($discount, 2)显然返回一个字符串(我认为它返回float)
  • 将负运算符放在number_format() '前面将导致返回的字符串结果自动转换为浮点数,这将产生舍入误差
  • 从字符串转换为浮点数后,返回相反的(反)结果
  • 返回结果没有四舍五入到小数点后两位

我对发生的事情的理解正确吗?

应该是…

'cost'   => '-' . number_format($discount, 2)

…或者只是…

'cost'   => number_format(-$discount, 2)

…如果你想获得一个字符串作为相应的值(你可能会这样做)。

使用当前的代码,您首先获得字符串(number_format调用的结果),然后使用一元减号操作符将其转换回数字。而这个数字和之前一样,也遇到了浮点数不准确的问题。

我相信你把number_format函数搞错了。该函数将float转换为string,使其易于阅读。根据手册,该函数还在任意三位数组之间添加逗号以使结果数字更易于阅读,并在需要时添加尾随点,后跟十进制数字。

这会使您的代码混乱,这实际上是对字符串取反。一般来说,对字符串取反是没有意义的:)

您想要的是一个将浮点数舍入为给定小数位数的函数。这是通过round函数实现的:

round(19.0398, 2); // returns 19.04

关于你的理解,大部分是正确的,但是你忽略了一个重要的微妙的情况。

就像我说的,number_format返回一个字符串,现在如果你对一个字符串取反,这个字符串会自动转换成一个数字。如何将字符串转换为数字?字符串的开头部分(由数字组成)将被转换为数字,但从第一个字符开始的所有非数字字符将被忽略。

因此,将字符串"12a33"转换为数字将得到数字12,而字符串"17,500"将转换为数字17。

你现在看到问题了吗?如果你的折扣变量包含一个较大的数字,比如10000,那么number_format(10000, 2)将产生字符串"10,000",而否定这个字符串将产生数字-10

我不知道$discount是否会那么大,但你应该考虑使用round而不是number_format

这将使它工作,

'cost' => number_format(-1*$discount, 2)