Here's a little test program that follows what the system pow()
from Source/Intel/xmm_power.c
, in Apple's Libm-2026
, does in this case:
#include <stdio.h>
int main() {
// basically lines 1130-1157 of xmm_power.c, modified a bit to remove
// irrelevant things
double x = .3;
int i = 3;
//calculate ix = f**i
long double ix = 1.0, lx = (long double) x;
//calculate x**i by doing lots of multiplication
int mask = 1;
//for each of the bits set in i, multiply ix by x**(2**bit_position)
while(i != 0)
{
if( i & mask )
{
ix *= lx;
i -= mask;
}
mask += mask;
lx *= lx; // In double this might overflow spuriously, but not in long double
}
printf("%.40f\n", (double) ix);
}
This prints out 0.0269999999999999962252417162744677625597
, which agrees with the results I get for .3 ^ 3
in Matlab and .3 ** 3
in Python (and we know the latter just calls this code). By contrast, .3 * .3 * .3
for me gets 0.0269999999999999996946886682280819513835
, which is the same thing that you get if you just ask to print out 0.027
to that many decimal places and so is presumably the closest double.
So there's the algorithm. We could track out exactly what value is set at each step, but it's not too surprising that it would round to a very slightly smaller number given a different algorithm for doing it.