16

Recently i write a block of code:

const int sections = 10;

for(int t= 0; t < 5; t++){
   int i = pow(sections, 5- t -1);  
   cout << i << endl;
}

And the result is wrong:

9999
1000
99
10
1

If i using just this code:

for(int t = 0; t < 5; t++){
    cout << pow(sections,5-t-1) << endl; 
}

The problem doesn't occur anymore:

10000
1000
100
10
1

Does anyone give me an explaination? thanks you very much!

Suraj Jain
  • 4,463
  • 28
  • 39
Kingfisher Phuoc
  • 8,052
  • 9
  • 46
  • 86

10 Answers10

11

Due to the representation of floating point values pow(10.0, 5) could be 9999.9999999 or something like this. When you assign that to an integer that got truncated.

EDIT: In case of cout << pow(10.0, 5); it looks like the output is rounded, but I don't have any supporting document right now confirming that.

EDIT 2: The comment made by BoBTFish and this question confirms that when pow(10.0, 5) is used directly in cout that is getting rounded.

Community
  • 1
  • 1
taskinoor
  • 45,586
  • 12
  • 116
  • 142
  • 4
    This doesn't explain why printing directly doesn't print 9999.9999999 – Luchian Grigore Mar 14 '12 at 14:50
  • @Luchian Grigore, is it possible that in that case it is getting rounded? I would like to hear that explanation too. – taskinoor Mar 14 '12 at 14:52
  • 3
    If the default precision is less the number of decimal places it would be rounded. – BoBTFish Mar 14 '12 at 15:01
  • @BoBTFish, can you explain a little more. Is that the behavior of `cout`? – taskinoor Mar 14 '12 at 15:03
  • Is there any solution to get `int i = pow(10,5) = 10,000`? – Kingfisher Phuoc Mar 14 '12 at 15:06
  • 1
    @Kingfisher, on my machine `int i = pow(10, 5)` results 10000, but pow(10.0, 5) does not. Looks like `sections` is double in your code. If you really need `sections` to be double then instead of assign it to `i` you need to round the power. – taskinoor Mar 14 '12 at 15:10
  • 5
    `std::cout` will round floats to a specified number of significant figures, which can be changed using the `std::setprecision` manipulator. So if you try to output `99.9999` (which remember is actually the closest approximation to that it can manage, not the exact number) with a precision of say 4, the rounding will "carry the 1" all the way up and print 100. – BoBTFish Mar 14 '12 at 15:13
  • @taskinoor Which compiler/library are you using that can't accurately compute `pow(10.0, 5);`? – Mark B Mar 15 '12 at 13:36
  • @Mark B, I'm using gcc 4.4.1 with MinGW32 on a windows 7 machine. – taskinoor Mar 15 '12 at 14:14
3

When used with fractional exponents, pow(x,y) is commonly evaluated as exp(log(x)*y); such a formula would mathematically correct if evaluated with infinite precision, but may in practice result in rounding errors. As others have noted, a value of 9999.999999999 when cast to an integer will yield 9999. Some languages and libraries use such a formulation all the time when using an exponentiation operator with a floating-point exponent; others try to identify when the exponent is an integer and use iterated multiplication when appropriate. Looking up documentation for the pow function, it appears that it's supposed to work when x is negative and y has no fractional part (when x is negative and `y is even, the result should be pow(-x,y); when y is odd, the result should be -pow(-x,y). It would seem logical that when y has no fractional part a library which is going to go through the trouble of dealing with a negative x value should use iterated multiplication, but I don't know of any spec dictating that it must.

In any case, if you are trying to raise an integer to a power, it is almost certainly best to use integer maths for the computation or, if the integer to be raised is a constant or will always be small, simply use a lookup table (raising numbers from 0 to 15 by any power that would fit in a 64-bit integer would require only a 4,096-item table).

supercat
  • 77,689
  • 9
  • 166
  • 211
2

From Here

Looking at the pow() function: double pow (double base, double exponent); we know the parameters and return value are all double type. But the variable num, i and res are all int type in code above, when tranforming int to double or double to int, it may cause precision loss. For example (maybe not rigorous), the floating point unit (FPU) calculate pow(10, 4)=9999.99999999, then int(9999.9999999)=9999 by type transform in C++.

How to solve it?

Solution1

Change the code:

    const int num = 10;

    for(int i = 0; i < 5; ++i){
       double res = pow(num, i);
       cout << res << endl;
    }

Solution2

Replace floating point unit (FPU) having higher calculation precision in double type. For example, we use SSE in Windows CPU. In Code::Block 13.12, we can do this steps to reach the goal: Setting -> Compiler setting -> GNU GCC Compile -> Other options, add

-mfpmath=sse -msse3

The picture is as follows:

add <code>-mfpmath=sse -msse3</code>
(source: qiniudn.com)

Glorfindel
  • 21,988
  • 13
  • 81
  • 109
Aleeee
  • 1,913
  • 6
  • 17
  • 27
1

Whats happens is the pow function returns a double so when you do this

int i = pow(sections, 5- t -1);  

the decimal .99999 cuts of and you get 9999.

while printing directly or comparing it with 10000 is not a problem because it is runded of in a sense.

1

If the code in your first example is the exact code you're running, then you have a buggy library. Regardless of whether you're picking up std::pow or C's pow which takes doubles, even if the double version is chosen, 10 is exactly representable as a double. As such the exponentiation is exactly representable as a double. No rounding or truncation or anything like that should occur.

With g++ 4.5 I couldn't reproduce your (strange) behavior even using -ffast-math and -O3.

Now what I suspect is happening is that sections is not being assigned the literal 10 directly but instead is being read or computed internally such that its value is something like 9.9999999999999, which when raised to the fourth power generates a number like 9999.9999999. This is then truncated to the integer 9999 which is displayed.

Depending on your needs you may want to round either the source number or the final number prior to assignment into an int. For example: int i = pow(sections, 5- t -1) + 0.5; // Add 0.5 and truncate to round to nearest.

Mark B
  • 95,107
  • 10
  • 109
  • 188
0

simple solution you can try is.. just add 0.1 in your code.

const int sections = 10;

for(int t= 0; t < 5; t++){
   int i = pow(sections, 5- t -1)+0.1;  
   cout << i << endl;
}
0

In addition to the other answers about doubles rounding to 9999.99999 internally, it's also important to note that by default, streams have a precision of 6, and which means they round in teh output at 6 digits. So when you print the double directly, it rounds correctly to 10000. But if you cast it to an int first, that truncates to 9999. https://en.cppreference.com/w/cpp/io/ios_base/precision

Mooing Duck
  • 64,318
  • 19
  • 100
  • 158
0

There must be some broken pow function in the global namespace. Then std::pow is "automatically" used instead in your second example because of ADL.

Either that or t is actually a floating-point quantity in your first example, and you're running into rounding errors.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
0

You're assigning the result to an int. That coerces it, truncating the number.

This should work fine:

for(int t= 0; t < 5; t++){
   double i = pow(sections, 5- t -1);  
   cout << i << endl;
}
Charlie Martin
  • 110,348
  • 25
  • 193
  • 263
-1

What happens is that your answer is actually 99.9999 and not exactly 100. This is because pow is double. So, you can fix this by using i = ceil(pow()).

Your code should be:

const int sections = 10;
for(int t= 0; t < 5; t++){
   int i = ceil(pow(sections, 5- t -1));  
   cout << i << endl;
}
Matheus Lacerda
  • 5,983
  • 11
  • 29
  • 45