1

My code:

#include <stdio.h>
#include <math.h>

int main (void)
{
    int n = 0;
    int sum = 0;
    printf("Enter a number: ");
    scanf("%d", &n);
    for (int power = 1; power <= n; power++)
    {
        printf("%d %s ", (int)pow(10, power) - 1, power == n ? "=" : "+");
        sum += (int)pow(10, power) - 1;
    }
    printf ("%d", sum);
    return 0;    
}

Output in Vs Code with gcc:

Enter a number: 5
9 + 98 + 999 + 9998 + 99999 = 111103

Output in online compilers:

Enter a number: 5
9 + 99 + 999 + 9999 + 99999 = 111105

My question: Why? is this happening?

user14354509
  • 47
  • 1
  • 6
  • 2
    [The classic answer](https://stackoverflow.com/questions/588004/is-floating-point-math-broken) . Also you may get different answers with the same compiler and different optimization settings. –  Dec 07 '20 at 12:13
  • 1
    With these kinds of questions please be maximally specific when it comes to compiler versions. “online compiler” isn’t a good description, and nor is “VS code with gcc” enough. What version? What options? – Konrad Rudolph Dec 07 '20 at 12:22
  • Several issues: First, the code is always rounding down which can be an issue if pow result is slightly lower than the closed integer. Second, it does not check the input. It is vulnerable to overflow. Third: The sum accumulates the rounding errors. – Wör Du Schnaffzig Dec 07 '20 at 13:09
  • I now tested the code above with gcc 9.3, https://www.onlinegdb.com/online_c++_compiler and visual c version 19.16.27043. None of them showed the above behaviour. Did you use some outdated compiler version? Which runtime/sdk version did you use (if you used vc)? – Wör Du Schnaffzig Dec 07 '20 at 14:23

2 Answers2

3

Possibly an issue with pow and its implementation, perhaps due to different platform or compilers.

Instead of using pow which relies on floating point arithmetic and leads to compounding rounding errors (and possibly contains bugs), why not use simple multiplication? If you start the loop with 10, then you could multiply that by 10 each iteration to get the result you want.

Perhaps something like this:

unsigned sum = 0;
for (unsigned power = 0, value = 10; power < n; ++power, value *= 10)
{
    sum += value - 1;
}

[Printing left out]

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • @KonradRudolph: IEEE 754 does not fully constrain the results of `pow` and other routines. So this is not a conformance issue. Also, C implementations commonly do not conform to IEEE 754. – Eric Postpischil Dec 07 '20 at 12:18
  • 1
    @EricPostpischil Clearly I’m wrong since GCC and clang disagree on something so fundamental, but I fail to see how `pow` on integer powers of 10 can give different answers without this being a glaring bug. Just because IEEE-754 doesn’t “fully” constrain these functions doesn’t give implementations license to do whatever they want. The fact that this gives wrong results should be very unexpected. – Konrad Rudolph Dec 07 '20 at 12:20
  • @Someprogrammerdude: Nonetheless, it is incorrect to characterize it as a floating-point issue. Nothing about floating-point precludes returning correct results in this case. Microsoft’s `pow` returns incorrect results even though correct results are possible in this case and are returned by other implementations. When an integer routine returns an incorrect result, we do not characterize it as an integer error. – Eric Postpischil Dec 07 '20 at 12:21
  • @KonradRudolph: Please show us how you would implement `pow` to return correct results in all cases where an exact result is possible. – Eric Postpischil Dec 07 '20 at 12:23
  • 1
    @EricPostpischil I am *not* saying this is possible. I am saying that *even if* this is impossible, `pow` shouldn’t make errors willy-nilly. And in particular integer powers of 10 within the range of the underlying type should probably work (if for no other reason than that they crop up fairly frequently in actual usage, e.g. to label log-scaled graphs). In fact, clang does some really weird stuff here: https://godbolt.org/z/reKM57 – Konrad Rudolph Dec 07 '20 at 12:29
  • @KonradRudolph: As I wrote, show us how you would implement `pow` to return correct results in all cases where an exact result is possible. Once you try, even briefly, you will see that `pow` is not making errors “willy-nilly.” There are reasons for it, and you will understand better once you have the knowledge gained by trying. On the other hand, I criticize Microsoft’s implementation not because it makes errors “willy-nilly,” but because, even though implementing `pow` with the necessary quality is hard, Microsoft should have invested the required effort (earlier than it did). – Eric Postpischil Dec 07 '20 at 12:50
  • Looking at https://en.wikipedia.org/wiki/IEEE_754 it seems there are both binary as well as decimal representations covered by the standard. If someone asked me i had answered without thinking that c doubles are implemented using the former. Now i've written a test program which outputs the pow result to 20 digits and got no digits beside zero after the point. So now i'm pretty sure gcc implemented it's doubles on a base of 10 in contrast to my expectation. May it be that other compilers still use the binary representation which could probably result in the differences shown in the question? – Wör Du Schnaffzig Dec 07 '20 at 22:02
  • I mean that the result of assigning a double to an integer may be dependent on the direction of approach to the final calculation value. If one approaches from the top the integer would be the expected one. If one approaches from bottom, the integer would be one less than expected. Of course, this holds only if the double is represented in binary form, else powers of ten had an exact representation. – Wör Du Schnaffzig Dec 07 '20 at 22:07
  • @pqans “So now i'm pretty sure gcc implemented it's doubles on a base of 10” — No, that isn’t the case unless you run on a very obscure piece of hardware (and I don’t think GCC would support that). All modern commodity hardware implements base 2 doubles in the machine, and GCC uses the machine representation when translating C++ code. – Konrad Rudolph Dec 08 '20 at 10:10
  • Sorry, i was completely mistaken. The powers of ten considered here are exactly representable in the binary system. E.g. `1e+09 = 0.931323 * 2^30`. That's why the pow function should not exhibit rounding errors when calculating powers of ten and that's why the output of Vs Code with gcc is indeed inherently faulty. – Wör Du Schnaffzig Dec 09 '20 at 20:35
2

I just use the function "round" which returns the integer rounding closest to the value specified in parameter

#include <stdio.h>
#include <math.h>

int main (void)
{
    int n = 0;
    int sum=0;
    printf("Enter a number: ");
    scanf("%d", &n);
    for (int power = 1; power <= n; power++)
    {
        sum += (int)round (pow(10, power)) - 1;
    }
    printf ("%d", sum);
    return 0;
}
MED LDN
  • 684
  • 1
  • 5
  • 10
  • This doesnt really answer the question as to why it happens, but then neither does the (hastily) accepted answer. However this answer better targets where the issue arises when compared to the accepted answers approach of offering totally different code. – ROX Dec 07 '20 at 12:36