1

I'm trying to a create an algorithm that can convert base 10 numbers into base n numbers, where n is at most 10. However, for some weird reason the following algorithm in C fails at certain critical points for each base. For example, for base 2 and base 3 conversions, all numbers up to and including 1023 and 52,487 work, respectively, but numbers beyond that produce some weird negative result. I can't figure out why this is happening; can anyone help me?

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int returnint;

int baseconvert(int number,int base) {
    if(number == 0 || base == 10) {
        return returnint;
    }
    returnint = (number % base) + (10 * baseconvert(number / base, base));
    return returnint;
}

int main() {
    fprintf(stdout,"%d\n",baseconvert(1023,2));
    fprintf(stdout,"%d\n",baseconvert(52487,3));
}

EDIT:

Here is the printed result of the above print statements, if that's helpful:

1410065408
-2094967296
user3059347
  • 529
  • 1
  • 9
  • 15
  • `baseconvert(1023,2)` does work in gcc and `baseconvert(52487,3)` is most likely an overflow. – dari Jul 23 '14 at 17:10
  • Not the answer just a note: you're missing a `return` in your `main()` function. – Jack Jul 23 '14 at 17:14
  • @dari Yes `baseconvert(1023,2)` and `baseconvert(52487,3)` work; those are posted as examples of the highest values that work. I tried using a larger integer, as I commented below on Mark Wilkin's post, but that didn't work. – user3059347 Jul 23 '14 at 17:22
  • 1
    The main problem here is that you're taking integers as if they are dedicated for a specific base. Integers are for representing counts of things that extend to the negative range as well. The value you are to hold in an `int` variable is the count, for example, the amount of apples in a bag. Regardless of how you represent it in different bases, there are fixed amount of apples in that bag, and that fixed amount is to be held within the `int`. Base should only matter while outputting the value. For example: `int n = 20; printf( "%d %x %o", n, n, n );` will output `n` as `20`, `14` and `24`. – Utkan Gezer Jul 23 '14 at 17:34
  • the code has a bug. if the base is 10, then the code returns 'returnint' however, the var returnint has not been set so the function will return garbage. – user3629249 Jul 24 '14 at 06:32
  • the code does not seem to work as the base 2 of 1023 is 1111111111, not 1410065408 – user3629249 Jul 24 '14 at 06:33

4 Answers4

1

Your algorithm is very limited in the range of numbers vs. bases. The smaller the base is the more digits are needed to represent it. And since you store the result in decimal form, you'll waste your available data range very quickly. There is no fundamental data type that can hold the results for all the possible inputs. E.g., maximal 31-bit decimal number (normal integer, dropping the sign bit) will result in 31-digit output!

You have several options to cope with this:

  • Allocate a stack large enough and push the digits into it. Upon completion, print the stack contents.
  • Print the digits immediately without saving, this will eliminate the need to allocate anything. E.g.:

#include <stdio.h>

void baseconvert(int number,int base) 
{
    if(number > 0) 
    {
        int digit = (number % base);
        baseconvert(number / base, base);
        printf("%d",digit);
    }
    else
    {
        printf("\n");
    }
}

int main() 
{
    baseconvert(1023,2);
    baseconvert(52487,3);
}
SomeWittyUsername
  • 18,025
  • 3
  • 42
  • 85
0

It appears that the integer value is overflowing. For example, the decimal value 1023 in base two is 1111111111. If it is a 4 byte integer, then it will overflow when trying to "add" one more digit (the max signed integer in this case being 2147483647).

Since it appears your goal is to display a number in a different base, it might make more sense to store the digits in a character array.

Mark Wilkins
  • 40,729
  • 5
  • 57
  • 110
  • Hmm, even if I increase the size of returnint to unsigned long int (and put it inside the body of the function baseconvert as lgor suggested), the value still overflows even though the integer can now be 32 bits in size. Perhaps if I change over to appending digits to a string... I'll be right back with the result of that. – user3059347 Jul 23 '14 at 17:18
  • Depending on the platform, a long may still only be 4 bytes rather than 8, so that may not help. And I see that I suggested the character array at the same time you did. :) – Mark Wilkins Jul 23 '14 at 17:20
0

On all processors that I know of, integers are already stored in binary form; this implies base 2. This value can be displayed in whatever base you desire, with some work on your part. printf() and friends allow you to easily print in base 10 (%d) and base 16 (%x). It is not difficult to imagine a method that would convert a binary (base 2) integer value into a character representation in base n.

I seriously doubt that you really intend to change the actual value of the integer, as you are doing. Like @ThoAppelsin said above, the number of apples in the bag stays the same, regardless of which base you choose for display.

By simply creating a method that represents (with digits) the integer in any base, you will also solve your overflow problem!

Steger
  • 887
  • 7
  • 16
0

Your result is overflowing the integer range. Try using strings instead. This is the pseudocode which relies on strings to represent numbers and it can convert numbers from any base to any other base between 2 and 36 inclusive (using digits and upper case letters):

function ConvertNumber(number, b, d)
begin
    newNumber = ""
    while number <> "0"
        begin
            number = Divide(number, b, d, out remainder)
            newDigit = ValueToDigit(remainder)
            newNumber = Concatenate(newDigit, newNumber)
        end
    if newNumber ="" then
        newNumber = "0"
end

function Divide(number, base, divisor, out remainder)
begin
    remainder = 0
    result = ""
    for i = 0 to Length(number) - 1
        begin
            digitValue = DigitToValue(number[i])
            remainder = base * remainder + digitValue
            newDigitValue = remainder / divisor -- integer division
            remainder = remainder mod divisor
            if newDigitValue > 0 OR result <> "" then
                newDigit = ValueToDigit(newDigitValue)
                result = Concatenate(result, newDigit)
        end
    if result = "" then
        result = "0"
    return result
end

You can find the whole math and implementation in this article: Converting Number Bases.

Zoran Horvat
  • 10,924
  • 3
  • 31
  • 43