当我开始编写我的第一个应用程序时,我使用了NSNumber来获取金钱价值而不必考虑两次 然后我想也许c类型足以处理我的价值观.然而,我被推荐在iPhone SDK论坛中使用NSDecimalNumber,因为它具有出色的舍入功能.
不是气质的数学家,我认为尾数/指数范式可能是过度的; 仍然,googlin',我意识到大多数关于可可货币/货币的谈判都被提到了NSDecimalNumber.
请注意,我正在处理的应用程序将进行国际化,因此以美分计算金额的选项并不可行,因为货币结构在很大程度上取决于所使用的区域设置.
我90%肯定我需要使用NSDecimalNumber,但因为我在网上找不到明确的答案(类似于:"如果你处理钱,请使用NSDecimalNumber!")我想我会问这里.也许答案对大多数人来说是显而易见的,但我想在开始对我的应用程序进行大规模重新分解之前确定.
说服我 :)
Marcus Zarra对此有一个非常明确的立场:"如果你正在处理货币,那么你应该使用NSDecimalNumber." 他的文章激励我研究NSDecimalNumber,我对它印象非常深刻.处理基数为10的数学时的IEEE浮点错误一直让我感到恼火(1*(0.5 - 0.4 - 0.1)= --0.00000000000000002776)并且NSDecimalNumber消除它们.
NSDecimalNumber不只是添加二进制浮点精度的另外几个数字,它实际上是基数10数学.这消除了上面示例中显示的错误.
现在,我正在编写一个符号数学应用程序,所以我对30+十进制数字精度和没有奇怪的浮点错误的渴望可能是一个例外,但我认为值得关注.这些操作比简单的var = 1 + 2样式数学更加尴尬,但它们仍然可以管理.如果您担心在数学运算期间分配各种实例,NSDecimal是NSDecimalNumber的C结构等价物,并且有C函数用于执行与它完全相同的数学运算.根据我的经验,这些对于除了最苛刻的应用程序之外的所有应用程序都是快速的(在MacBook Air上增加3,344,593个分区/秒,254,017个分区/秒,在iPhone上增加281,555个分区/秒,12,027个分区/秒).
作为额外的好处,NSDecimalNumber的descriptionWithLocale:方法提供了一个字符串,其中包含数字的本地化版本,包括正确的小数分隔符.对于其initWithString:locale:方法,情况相反.
是.你必须使用
NSDecimalNumber和
在iOS上处理货币时,不要加倍或浮动.
因为我们不想得到$ 9.9999999998而不是10 美元的东西
浮点数和双打数是近似值.它们总是带有舍入误差.计算机用于存储小数的格式会导致此轮询错误.如果您需要阅读更多详细信息
http://floating-point-gui.de/
根据苹果文档,
NSDecimalNumber是NSNumber的不可变子类,它提供了一个面向对象的包装器,用于执行base-10算术.实例可以表示可以表示为尾数x 10 ^指数的任何数字,其中尾数是长度为38位的十进制整数,指数是从-128到127.wrapper的整数,用于执行基数为10的算术.
所以NSDecimalNumber被推荐用于处理货币.
(改编自我对其他答案的评论.)
是的你应该.只要您不需要代表半分钱就可以使用完整数量的便士.如果发生这种情况,您可以将其更改为半美分,但如果您需要代表四分之一或八分之一美分呢?
唯一合适的解决方案是NSDecimalNumber(或类似的东西),它将问题推迟到10 ^ -128¢(即,
0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000001¢).
(另一种方法是任意精度算术,但这需要一个单独的库,例如GNU MP Bignum库.GMP属于LGPL.我从未使用过那个库,也不知道它是如何工作的,所以我不能说它对你有多好.)
[编辑:显然,至少有一个人 - 布拉德拉森 - 认为我在谈论这个答案的某个地方的二进制浮点数.我不是.]