Interesting bug with the pow() function

I tried running the pow function to generate large numbers and I get some weird results. At first I thought it was an overflow issue so I cut it back a little, however there still seems to be an issue.

I thought maybe the complexity of pow function might play a part in this issue, so I wrote a simpler version (one that only deals with whole numbers) to see if I can get better results. After playing around with it for a bit, these are the results:

EXPONENT CALCULATOR
Please enter a base number (whole numbers only): 10
Please enter the exponent (whole numbers only): 22
Result
----------------------------------------------------------------------
exponent() 10000000000000000000000.0
pow() 10000000000000000000000.0
Would you like to go again? (Y/N):

EXPONENT CALCULATOR
Please enter a base number (whole numbers only): 10
Please enter the exponent (whole numbers only): 23

Result
-----------------------------------------------------------------------
exponent() 99999999999999991611392.0
pow() 100000000000000008388608.0
Would you like to go again? (Y/N):

EXPONENT CALCULATOR
Please enter a base number (whole numbers only): 10
Please enter the exponent (whole numbers only): 24
Result
-----------------------------------------------------------------------
exponent() 999999999999999983222784.0
pow() 999999999999999983222784.0
Would you like to go again? (Y/N):
This is the function I wrote to replace the pow() function

1
2
3
4
5
6
7
8
9
10
11
double exponent(double val1, double val2)
{
	int exponent = 1;
	double result = val1;
	while (exponent < val2)
	{
		result = result * val1;
		exponent += 1;
	};
	return result;
}
One thing I noticed with the second result (1024) was that the average of the two numbers is the correct answer.... Not sure why.
Small errors like that is to be expected when working with floating point numbers. double has only got about 16 figures of precision.
Pedantic:
(one that only deals with whole numbers)

Why do you take doubles in, particularly as the exponent? That does not convey the intent of your version.
That does not convey the intent of your version

Honestly, because I'm still a beginner haha. I'm in an intro college class for C++
It may be instructive to learn why you're seeing those exact numbers: the type double is a binary type that has 53 bits of precision: https://en.wikipedia.org/wiki/Double-precision_floating-point_format

When you're very close to 0.0, stepping from one double to the next (incrementing the 53rd bit) results in very small steps. When you're dealing with very large numbers, incrementing the 53rd bit produces huge steps, much larger than 1.0

The number 10^22 happens to be a valid double with value 10000000000000000000000 (hex 0x1.0f0cf064dd592p+73). If you increment the last bit by one (hex 0x1.0f0cf064dd593p+73), your value will be 10000000000000002097152.

There is no such thing as a double with value 10000000000000000000001 or the double with value 10000000000000000000002, ... or the double with value 10000000000000002097151. There is only 10000000000000000000000 and then, right after it, 10000000000000002097152. There is nothing inbetween those two numbers.

The number 10^23 does not exist in double notation. It lies between
99999999999999991611392 (hex 0x1.52d02c7e14af6p+76)
and
100000000000000008388608 (hex 0x1.52d02c7e14af7p+76)

It happens to be *exactly* between those two numbers, in which case the little-known "halfway to even" rounding rule kicks in, making the first one the correct value of pow(10,23) (the first one ends in hex 6, the second one ends in hex 7)

The number 10^24 also does not exist in double notation. It lies between
999999999999999983222784 (hex 0x1.a784379d99db4p+79)
and
1000000000000000117440512 (hex 0x1.a784379d99db5p+79)
Here it is a lot closer to the first one (by about a 100 mil), which is why that is the correct answer.

it takes a lot of difficult math to program a precise pow() (where "precise" means it always gives the one double value that is the closest to the mathematically-correct answer according to standard rounding rules). As you can see, your function failed to give the expected answer for 10^23, but worked for 10^22 and for 10^24. If you want to see (and be intimidated by) a production-level pow() implementation, take a look at https://bitbucket.org/MDukhan/crlibm/src/30bc7f5a18b8acacea71407709e039e701561bfa/pow.c
Last edited on
Or, don't use doubles ... the program is looking for integer powers, and many of us keep an ipow (integer to integer power, and possibly a variation with doubles to integer powers) handy for precise values for just this reason (and performance, pow can be sluggish).
Topic archived. No new replies allowed.