目标C浮点数的乘法给出了意想不到的结果

时间:2013-06-27 07:47:24

标签: objective-c c floating-point

我只是在做两个花车的乘法。为什么这些陈述产生不同的结果?我应该使用花车吗?

500,000.00 * 0.001660 = 830

Oddity Float Multiplications

2 个答案:

答案 0 :(得分:4)

  

为什么这些陈述产生不同的结果?

因为floating-point arithmetic is not exact并且显然你没有足够精确地打印乘数(即具有足够的小数位数)。它不是.00166,而是似乎 0.00166四舍五入的东西。

  

我是否应该使用花车?

没有。为了金钱,使用整数并将它们视为定点有理数。 (它们仍然不准确,但明显更好,更不容易出错。)

答案 1 :(得分:3)

您没有展示如何初始化periodicInterest,并且您可能认为您将其设置为0.00166,但实际上输出中的错误足够大,您无法明确初始化它为periodicInterest = 0.00166。它必须更接近0.001659750.001660.00165975之间的差异肯定足够大,不会只是单个浮点舍入错误。

假设您使用的是货币数量,则应使用NSDecimalNumberNSDecimal

使用NSDecimalNumber的一个非显而易见的好处是它可以与NSNumberFormatter一起使用,因此您可以让Apple负责为各种外国语言环境设置货币格式。

更新

回应评论:

  • periodicInterest显然不是货币数量”和“十进制在除以12时比二进制更不会出错” - 对于不精确的数量,我可以想到两个问题:

    • 一个问题是使用足够的精度来提供准确的结果。 NSDecimalNumber是一个浮点数,精度为38位,指数范围为-128 ... 127。这是IEEE'double'可以存储的十进制数字的两倍多。指数范围小于double的指数范围,但这在金融计算中不太重要。因此,NSDecimalNumber s肯定会导致比floatdouble s更小的错误,即使它们都不能完全存储1/12。

    • 另一个问题是匹配其他系统计算的结果,例如您的银行或您的经纪人或纽约证券交易所。在这种情况下,您需要弄清楚其他系统如何存储数字并使用它们进行计算。如果另一个系统使用十进制格式(可能在金融部门),那么NSDecimalNumber可能会有用。

  • “使用原始类型进行浮点运算,特别是数千个实时运算效率不高。”原始类型的算法比NSDecimalNumber上的算术快得多。我没有测量它,但100倍不会让我感到惊讶。

    您必须在要求之间取得平衡。如果十进制精度至关重要(通常在财务编程中),则必须牺牲性能以保证准确性。如果小数精度不是那么重要,您可以仔细考虑使用基本类型,但是您应该知道您牺牲的准确性。即使这样,float的大小也很小(通常只有7位有效十进制数字),你应该使用double(至少15位,通常是16位有效十进制数字)。

    如果您需要以真正的小数精度每秒执行数百万次算术运算,您可以使用double执行此操作,如果您是IEEE 754专家能够执行此操作分析您的代码以确定引入错误的位置以及如何消除它们。很少有人拥有这种专业水平。 (我没有声称。)您还必须了解编译器如何将Objective-C代码转换为机器指令。

    无论如何,也许你只是在编写一个随意的应用来计算净现值或未来价值的粗略估计。在这种情况下,使用double可能就足够了,但使用NSDecimalNumber可能也足够快。如果不了解您正在编写的应用程序的更多信息,我无法向您提供更具体的建议。