Objective C功能混合精度结果

时间:2014-02-02 00:13:10

标签: objective-c floating-point precision pow libm

关于目标c中的pow函数的一般问题。

为什么以下代码会吐出来 当基数= 125时,ans = 4.9999999

NSDecimalNumber * base = [[NSDecimalNumber alloc ]initWithString:@"125"];
NSDecimalNumber * root = [[NSDecimalNumber alloc] initWithString:@"3"];
double ans=pow(125, 1.0/[root doubleValue]);

当base = 27时正好为3

NSDecimalNumber * base = [[NSDecimalNumber alloc ]initWithString:@"27"];
NSDecimalNumber * root = [[NSDecimalNumber alloc] initWithString:@"3"];
double ans=pow(125, 1.0/[root doubleValue]);

1 个答案:

答案 0 :(得分:5)

这里有一些因素在起作用。最重要的是,1.0/3.0并不是三分之一,因此您计算base的多维数据集根。相反,您指定的计算是:

base**0.333333333333333314829616256247390992939472198486328125

exp(0.333333333333333314829616256247390992939472198486328125 * log(base))

base125时,此计算的确切实数结果为:

4.999999999999999553291243227753830961690873860134487744...

此值的两个最接近的可表示的双倍是5.0和:

4.99999999999999911182158029987476766109466552734375

后一个值几乎不接近数学上精确的结果,因此pow函数返回了最佳(或“正确舍入”)答案。

当您使用等于27的base执行相同的计算时,数学上精确的实数结果为:

2.99999999999999981704430129767885583952101310176125736...

在这种情况下,这个数字比任何其他可表示的双数更接近3.0,所以pow再次返回了最佳结果。

因此,在这些情况下,pow函数会为您提供的计算提供最准确的结果。现在,也就是说,不能保证pow对所有可能的输入都这样做(事实上,通常它没有)。对于所有输入,您将无法获得如此准确的结果,并且对于某些平台上的许多输入,您将获得显着不太准确的结果。通常,您不应该依赖于pow函数的最后一位舍入,也不应该依赖于未明确定义的任何函数的最后一位舍入来生成正确的舍入结果。

简而言之:您获得的结果是最好的结果,而在其他平台上,您将不会那么幸运。


备选方案:

  • 你可能会考虑使用cbrt函数,它也不能保证正确的舍入,但至少是计算立方根而不是0.3333333333333333148296 ......的权力。

  • 如果你知道先验结果应该是一个整数,你可以通过roundrint函数将其四舍五入到最接近的整数。 / p>

  • 如果您确实需要精确的最后一位舍入,请考虑使用CRLibm库。这将带来一些性能成本,但如果你绝对必须有正确的舍入,那么它是唯一的好选择(但请注意,它将为这些特定的例子产生完全相同的结果)。