如何在PHP中安全地执行与金钱相关的计算?

时间:2021-12-15 12:37:38

I'm working on a few report output scripts that need to do some rudimentary calculations on some money values.

我正在研究一些报告输出脚本,需要对一些货币价值进行一些基本的计算。

I am aware of the limitations of floating point arithmetic for this purpose, however the input values are all in a decimal format, so if I use the arithmetic operators on them PHP will cast them to floats.

我知道浮点运算的局限性,但输入值都是十进制格式,所以如果我使用算术运算符,PHP会将它们转换为浮点数。

So what is the best way to handle the numbers? Should I use BCMath? Is there something akin to Decimal in .NET? Or is it safe to use the arithmetic operators if I cast back to int?

那么处理这些数字的最佳方法是什么?我应该使用BCMath吗?是否有类似于.NET中的Decimal的东西?或者,如果我转回int,使用算术运算符是否安全?

3 个解决方案

#1


Don't work in Dollars ($1.54), work in cents: (154c). Unless you need to be performing tasks where fractions of a cent are important, then you'll be working with integers and all is well. If you are interested in tenths of a cent, then just multiply everything by ten!

不要以美元(1.54美元)工作,以美分工作:(154c)。除非你需要执行几分之一重要的任务,否则你将使用整数,一切都很好。如果你对十分之一美分感兴趣,那么只需将所有东西乘以十!

#2


If you use BCMath all values will be stored in strings and passed to the functions as strings, just as the result will be a string. So, you needn't do any casting but ensure that the number given to the function is a value numeric value. Personally, if the math requires a high amount of precision on the decimal side then use BCMath.

如果使用BCMath,则所有值都将存储在字符串中并作为字符串传递给函数,就像结果将是一个字符串一样。因此,您不需要进行任何转换,但要确保为函数指定的数字是值数值。就个人而言,如果数学在小数方面需要很高的精度,那么使用BCMath。

#3


If you're working with reasonable amounts (to a "normal person"), using floating point is not likely to be a problem, especially if you're just adding and subtracting amounts, rather than doing, say, interest calculations.

如果你正在使用合理的金额(对于“普通人”),使用浮点不太可能是一个问题,特别是如果你只是增加和减去金额,而不是做利息计算。

If you're looking for a quick fix, switching to integer is not likely to help you; you still have to deal with overflow. (Someone edited here to mention that if PHP encounters a number beyond the bounds of the integer type, it will be interpreted as a float instead. But then you're back to your original problem of using floating point!) Arbitrary length integers (GMP, referenced from that page) can help.)

如果您正在寻找快速解决方案,切换到整数可能不会对您有所帮助;你仍然需要处理溢出。 (有人在这里编辑提到如果PHP遇到一个超出整数类型边界的数字,它将被解释为浮点数。但是你会回到你原来使用浮点的问题!)任意长度整数(GMP) ,从该页面引用)可以帮助。)

Basically, doing this in a half-assed way works in most cases, and is cheap; doing it correctly is a serious pain. My suggestion is to look at this as a business problem: if someone complains about missing a cent, give them a dollar, and don't bother starting on a real solution until you're going to save more dollars by doing that.

基本上,在大多数情况下以半as的方式执行此操作并且便宜;正确地做是一个严重的痛苦。我的建议是把这看作是一个商业问题:如果有人抱怨错过一分钱,给他们一美元,并且不要打扰真正的解决方案,直到你要通过这样做来节省更多的钱。

#1


Don't work in Dollars ($1.54), work in cents: (154c). Unless you need to be performing tasks where fractions of a cent are important, then you'll be working with integers and all is well. If you are interested in tenths of a cent, then just multiply everything by ten!

不要以美元(1.54美元)工作,以美分工作:(154c)。除非你需要执行几分之一重要的任务,否则你将使用整数,一切都很好。如果你对十分之一美分感兴趣,那么只需将所有东西乘以十!

#2


If you use BCMath all values will be stored in strings and passed to the functions as strings, just as the result will be a string. So, you needn't do any casting but ensure that the number given to the function is a value numeric value. Personally, if the math requires a high amount of precision on the decimal side then use BCMath.

如果使用BCMath,则所有值都将存储在字符串中并作为字符串传递给函数,就像结果将是一个字符串一样。因此,您不需要进行任何转换,但要确保为函数指定的数字是值数值。就个人而言,如果数学在小数方面需要很高的精度,那么使用BCMath。

#3


If you're working with reasonable amounts (to a "normal person"), using floating point is not likely to be a problem, especially if you're just adding and subtracting amounts, rather than doing, say, interest calculations.

如果你正在使用合理的金额(对于“普通人”),使用浮点不太可能是一个问题,特别是如果你只是增加和减去金额,而不是做利息计算。

If you're looking for a quick fix, switching to integer is not likely to help you; you still have to deal with overflow. (Someone edited here to mention that if PHP encounters a number beyond the bounds of the integer type, it will be interpreted as a float instead. But then you're back to your original problem of using floating point!) Arbitrary length integers (GMP, referenced from that page) can help.)

如果您正在寻找快速解决方案,切换到整数可能不会对您有所帮助;你仍然需要处理溢出。 (有人在这里编辑提到如果PHP遇到一个超出整数类型边界的数字,它将被解释为浮点数。但是你会回到你原来使用浮点的问题!)任意长度整数(GMP) ,从该页面引用)可以帮助。)

Basically, doing this in a half-assed way works in most cases, and is cheap; doing it correctly is a serious pain. My suggestion is to look at this as a business problem: if someone complains about missing a cent, give them a dollar, and don't bother starting on a real solution until you're going to save more dollars by doing that.

基本上,在大多数情况下以半as的方式执行此操作并且便宜;正确地做是一个严重的痛苦。我的建议是把这看作是一个商业问题:如果有人抱怨错过一分钱,给他们一美元,并且不要打扰真正的解决方案,直到你要通过这样做来节省更多的钱。