1

I tried writing a function to convert a string of numbers to an integer. I get a wrong output when I run my code on VS code with g++ 9.2.0 but when I run it on repl.it, I get a right output. This is my code:

#include <iostream>
#include <cmath>
using namespace std;

int charToInt(char c)
{
    return c - '0';
}

int myStoi(string s)
{
    int r = 0, len = s.length();
    for (int i = 0; i < len; i++)
    {
        r += charToInt(s[i]) * pow(10, len - i - 1);
    }
    return r;
}

int main()
{
    string str = "123";
    cout << stoi(str) << endl;
    cout << myStoi(str) << endl;

    return 0;
}

This is the output on VS code:

PS C:\Users\ASUS\Code\Practice> g++ .\convertChartoInt.cpp
PS C:\Users\ASUS\Code\Practice> .\a.exe 
123
122

And this is the output on repl.it:

./main
123
123

I try to figure out why I get the number 122 on VS code, so I cout value of r in myStoi function:

for (int i = 0; i < len; i++)
    {
        r += charToInt(s[i]) * pow(10, len - i - 1);
        cout << r << " ";
    }

Here is the result:

PS C:\Users\ASUS\Code\Practice> .\a.exe 
99 119 122

I think the first number should be 100 in order to generate a right output but it returned 99, can anyone tell me what this bug is and how to fix it? Thanks!

be_strong
  • 23
  • 1
  • 1
  • 6
  • 1
    https://stackoverflow.com/questions/588004/is-floating-point-math-broken – Hans Passant Sep 05 '20 at 10:24
  • can't replicate https://godbolt.org/z/jvh47Y – Sopel Sep 05 '20 at 10:26
  • 3
    `pow` does floating-point arithmetic, so you might get something like, `2.999999…` instead of `3`, and when you cast it to `int` it is not rounded up, but will become `2`. That's not a bug but something you have to expect when you use floating-point arithmetic – t.niese Sep 05 '20 at 10:27
  • @Sopel not being able to replicate it, does not mean that is won't happen. – t.niese Sep 05 '20 at 10:28
  • @t.niese it is weird however, because even with -std=c++98 gcc does (erroneusly?) `std::pow(int, int)` and then a floating point multiply that should be exact. I can't even get gcc to emit code that could be broken. – Sopel Sep 05 '20 at 10:29
  • @Sopel yes, it indeed calls `std::pow(int, int)` but the arguments are then cast to `double` internally: [pow](https://en.cppreference.com/w/cpp/numeric/math/pow) `A set of overloads or a function template for all combinations of arguments of arithmetic type not covered by 1-3). If any argument has integral type, it is cast to double. If any argument is long double, then the return type Promoted is also long double, otherwise the return type is always double.[…]` so `pow` still will always do floating-point arithmetic. – t.niese Sep 05 '20 at 10:49
  • @t.niese that's c++11, before there was no such overload – Sopel Sep 05 '20 at 11:25
  • Just add the values in increasing order of `i` and multiply `r` by 10 each iteration. – François Andrieux Sep 05 '20 at 11:55
  • probably related: [Why does pow(5,2) become 24?](https://stackoverflow.com/q/22264236/995714), [Why pow(10,5) = 9,999 in C++](https://stackoverflow.com/q/9704195/995714), [Why does gcc compiler output pow(10,2) as 99 not 100? (duplicate)](https://stackoverflow.com/q/25474351/995714) – phuclv Sep 05 '20 at 14:29
  • @Sopel No matter which version of c++, `pow` does floating-point arithmetic. So either the parameters are cast to floating-point when passed to the function, or [through promoted in the function](https://code.woboq.org/gcc/libstdc++-v3/include/c_global/cmath.html#412). – t.niese Sep 06 '20 at 05:56

1 Answers1

5

The usual approach to this problem is to accumulate the result by multiplying by 10:

for (int i = 0; i < len; ++i) {
    r *= 10;
    r += s[i] - '0';
}
Pete Becker
  • 74,985
  • 8
  • 76
  • 165