0

关于 Objective-c 中 pow 函数的一般问题。

为什么base = 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]);
4

1 回答 1

5

这里有几个因素在起作用。最重要的1.0/3.0是,不完全是三分之一,因此您没有计算base. 相反,您指定的计算是:

base**0.333333333333333314829616256247390992939472198486328125

或者

exp(0.333333333333333314829616256247390992939472198486328125 * log(base))

base125时,该计算的准确实数结果为:

4.999999999999999553291243227753830961690873860134487744...

最接近该值的两个可表示双精度数是5.0和:

4.99999999999999911182158029987476766109466552734375

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

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

2.99999999999999981704430129767885583952101310176125736...

在这种情况下,这个数字比它更接近于3.0任何其他可表示的双精度数,因此再次pow返回了可能的最佳结果。

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

简而言之:你得到的结果是最好的结果,而在其他一些平台上你就不会那么幸运了。


备择方案:

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

  • 如果您先验地知道结果应该是整数,则可以通过roundorrint函数将其四舍五入为最接近的整数。

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

于 2014-02-02T00:29:22.553 回答