Recursive function to convert between number bases fails at certain numbers

故事扮演 提交于 2019-12-24 10:44:02

问题


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

回答1:


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.




回答2:


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);
}



回答3:


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!




回答4:


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.



来源:https://stackoverflow.com/questions/24916666/recursive-function-to-convert-between-number-bases-fails-at-certain-numbers

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!