Question

General question on the pow function in objective-c.

Why does the following code spit out ans=4.9999999 when the base = 125

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

and exactly 3 when base = 27

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

La solution

There are a few factors at work here. Most importantly, 1.0/3.0 is not exactly one-third, so you are not computing the cube root of base. Instead, the computation that you have specified is:

base**0.333333333333333314829616256247390992939472198486328125

or

exp(0.333333333333333314829616256247390992939472198486328125 * log(base))

When base is 125, the exact real-number result of this computation is:

4.999999999999999553291243227753830961690873860134487744...

The two closest representable doubles to this value are 5.0 and:

4.99999999999999911182158029987476766109466552734375

The latter value is just barely closer to the mathematically exact result, so the pow function has returned the best possible (or "correctly rounded") answer.

When you do the same computation with base equal to 27, the mathematically exact real-number result is:

2.99999999999999981704430129767885583952101310176125736...

In this case, this number is somewhat closer to 3.0 than it is to any other representable double, so again pow has returned the best possible result.

So in these cases, the pow function is giving you the most accurate possible results to the computations you have prompted it with. Now, that said, there is no guarantee that pow does so for all possible inputs (and indeed, in general it doesn't). You won't get such accurate results for all inputs, and you will get significantly less accurate results for many inputs on some platforms. In general, you should not depend on last-bit rounding of the pow function, or of any function that is not explicitly defined to produce correctly-rounded results.

In short: the results you got are the best possible results, and on some other platforms you won't be so lucky.


Alternatives:

  • You might consider using the cbrt function, which also does not guarantee correct rounding, but at least is computing the cube root and not the 0.3333333333333333148296...th power.

  • If you know a priori that the result should be an integer, you might round it to the closest integer via the round or rint function.

  • If you really require exact last bit rounding, consider using the CRLibm library. This will come with some performance cost, but if you absolutely must have correct rounding, it is the only good option (but note that it will produce exactly the same results for these particular examples).

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top