1

I was writing some function to convert base of an integer, I am using Ideone this code on ideone

While it works fine on Ideone , on C::B it gives the output 484. I am using -std=c++11 ,even without it (or using -std=c++0x ) , the output is still incorrect. so is this something wrong with code or compiler ?

I am using mingw on windows ( gcc 4.7.1 )

#include<iostream>
#include<cmath>
#define bigint long long unsigned int

bigint base(int numberOldBase, int newBase)
{
    bigint numberNewBase = 0;
    int digitCounter = 0, remainder[100];

    while (numberOldBase)
    {
        remainder[digitCounter] = numberOldBase % newBase;

        numberOldBase /= newBase;
        digitCounter++;
    }

    for (int currentDigit = 0; currentDigit < digitCounter; currentDigit++)
    {
        numberNewBase += ((remainder[currentDigit]) * pow(10, currentDigit));
    }

    return numberNewBase;
}

int main()
{
    std::cout << base(1025, 15);
    return 0;
}
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
zapper
  • 73
  • 5
  • 1
    `gcc 4.7.1 ` You need a newer version to get `-std=c++11` working correctly (min GCC 4.8). – πάντα ῥεῖ Jul 02 '14 at 07:38
  • 1
    @πάνταῥεῖ Thanks for that but it is still incorrect whether i use it or not. – zapper Jul 02 '14 at 07:43
  • Please be explicit about the errors or unexpected behavior you get in your question. We can't tell what's wrong, if you don't show the necessary information in your question. Everything else will lead to a guessing game. So you already tried with GCC 4.9? Respect! That was quick, really! – πάντα ῥεῖ Jul 02 '14 at 07:47
  • 1
    You should update your compiler anyway. If you don't want 4.8 for some reason, there is still MinGW with GCC 4.7.2 – Erbureth Jul 02 '14 at 07:57
  • it seems that your first modulo operation gives a wrong value somehow. can you confirm that you really tried the exact same code in both environments? – xmoex Jul 02 '14 at 07:57
  • 1
    @xmoex I'd rather guess the `pow` and floating-point operations to be the culprit – Erbureth Jul 02 '14 at 07:58
  • @Erbureth maybe it'd be a good idea to change the line `numberNewBase += ((remainder[currentDigit]) * pow(10, currentDigit));` to `numberNewBase += (int)((remainder[currentDigit]) * pow(10.0, currentDigit));` – xmoex Jul 02 '14 at 08:11
  • You are using `pow` which is a floating-point function. This makes not a lot of sense. You can calculate powers of 10 in the loop easily and not worry about inefficient conversions and rounding errors. – n. m. could be an AI Jul 02 '14 at 08:22
  • @Erbureth yeah, that did it, but why? , can make it an answer please? – zapper Jul 02 '14 at 08:26
  • @user3796613 Upgrading the compiler? I can only guess, maybe some bug in the math library implementation. – Erbureth Jul 02 '14 at 08:37
  • @Erbureth no, that explicit conversion to int with passing `10.0` as argument – zapper Jul 02 '14 at 08:40

1 Answers1

2

The reason for the inaccuracy is that floating point numbers are not exact, and if in some point you get 484.99999995, it gets truncated to 484 in conversion to int. In that case, you should limit yourself to integral arithmetic only, as it will be faster and gets rid of the float inaccruracy.

bigint curExp = 1;
for (int currentDigit = 0; currentDigit < digitCounter; currentDigit++)
{
    numberNewBase += remainder[currentDigit] * curExp;
    curExp *= 10;
}

More detailed analysis

 numberNewBase += ((remainder[currentDigit]) * pow(10, currentDigit));

gets interpreted as

 numberNewBase = (float)numberNewBase + (((float)remainder[currentDigit]) * pow(10, currentDigit));

which leads to situation where small and big floating point numbers are added (which leads to greater rounding errors. The

numberNewBase += (int)((remainder[currentDigit]) * pow(10.0, currentDigit));

approach helps to mitigate the problem by converting to int before addition

numberNewBase = numberNewBase + (int)(((float)remainder[currentDigit]) * pow(10, currentDigit));

However the float conversion can be fully avoided by using the top approach.

Erbureth
  • 3,378
  • 22
  • 39
  • for completeness: you omit that pow(...)'s first argument is also casted to a floating point value. Apart from that: +1. Update: Arg! Me: Read first, then brain, then comment, not the other way around :-) – xmoex Jul 02 '14 at 10:55