在c中的基数10中打印大基数256数组

时间:2009-05-11 19:15:44

标签: c base-conversion

我在c中有一系列未签名的字符我试图在10号基础上打印,但我被卡住了。我认为这将在代码中得到更好的解释,因此,给出:

unsigned char n[3];
char[0] = 1;
char[1] = 2;
char[2] = 3;

我想打印197121。

这对于小型256基数阵列来说是微不足道的。一个可以简单地1 * 256 ^ 0 + 2 * 256 ^ 1 + 3 * 256 ^ 2.

但是,如果我的数组大100字节,那么很快就会出现问题。 C中没有100字节大的整数类型,这就是我将数字存储在unsigned char数组中的原因。

我怎么能在10号基地有效地打印这个号码?

我有点失落。

6 个答案:

答案 0 :(得分:8)

使用标准C库没有简单的方法。您要么自己编写函数(不推荐),要么使用GMP之类的外部库。

例如,使用GMP,你可以这样做:

unsigned char n[100];  // number to print

mpz_t num;
mpz_import(num, 100, -1, 1, 0, 0, n);  // convert byte array into GMP format
mpz_out_str(stdout, 10, num);  // print num to stdout in base 10
mpz_clear(num);  // free memory for num

答案 1 :(得分:8)

答案 2 :(得分:3)

我不知道你是否还需要一个解决方案,但我写了一篇关于这个问题的article。它显示了一个非常简单的算法,可用于将任意长数字与基数X转换为相应数量的基数Y.该算法是用Python编写的,但它实际上只有几行,并且不使用任何Python魔法。我也需要这样一个C实现算法,但由于两个原因决定使用Python来描述它。首先,任何理解用伪编程语言编写的算法的人都可以阅读Python,其次,我不允许发布C版本,因为我是为公司做的。看看你会发现这个问题在一般情况下是多么容易解决。 C中的实现应该是直截了当的......

答案 3 :(得分:2)

这是一个可以做你想要的功能:

#include <math.h>
#include <stddef.h> // for size_t

double getval(unsigned char *arr, size_t len)
{
    double ret = 0;
    size_t cur;
    for(cur = 0; cur < len; cur++)
        ret += arr[cur] * pow(256, cur);
    return ret;
}

这看起来非常易读。只需传递要转换的unsigned char *数组和大小。请注意,它不会是完美的 - 对于任意精度,我建议查看GNU MP BigNum库,正如已经建议的那样。

作为奖励,我不喜欢您以小端顺序存储您的数字,所以如果您想以big-endian顺序存储base-256数字,这里有一个版本:

#include <stddef.h> // for size_t

double getval_big_endian(unsigned char *arr, size_t len)
{
    double ret = 0;
    size_t cur;
    for(cur = 0; cur < len; cur++)
      {
        ret *= 256;
        ret += arr[cur];
      }
    return ret;
}

需要考虑的事情。

答案 4 :(得分:0)

提出此建议可能为时已晚或太无关紧要,但是您可以将每个字节存储为两个基本10位数(或一个基数100)而不是一个基数256吗?如果你还没有实现除法,那么这意味着你所拥有的只有加法,减法和乘法;那些不应该太难转换。一旦你完成了它,打印它将是微不足道的。

答案 5 :(得分:0)

由于我对提供的其他答案不满意,因此我决定自己写一个替代解决方案:

#include <stdlib.h>
#define BASE_256 256

char *largenum2str(unsigned char *num, unsigned int len_num)
{
    int temp;
    char *str, *b_256 = NULL, *cur_num = NULL, *prod = NULL, *prod_term = NULL;
    unsigned int i, j, carry = 0, len_str = 1, len_b_256, len_cur_num, len_prod, len_prod_term;

    //Get 256 as an array of base-10 chars we'll use later as our second operand of the product
    for ((len_b_256 = 0, temp = BASE_256); temp > 0; len_b_256++)
    {
        b_256 = realloc(b_256, sizeof(char) * (len_b_256 + 1));
        b_256[len_b_256] = temp % 10;
        temp = temp / 10;
    }

    //Our first operand (prod) is the last element of our num array, which we'll convert to a base-10 array
    for ((len_prod = 0, temp = num[len_num - 1]); temp > 0; len_prod++)
    {
        prod = realloc(prod, sizeof(*prod) * (len_prod + 1));
        prod[len_prod] = temp % 10;
        temp = temp / 10;
    }

    while (len_num > 1) //We'll stay in this loop as long as we still have elements in num to read
    {
        len_num--; //Decrease the length of num to keep track of the current element

        //Convert this element to a base-10 unsigned char array
        for ((len_cur_num = 0, temp = num[len_num - 1]); temp > 0; len_cur_num++)
        {
            cur_num = (char *)realloc(cur_num, sizeof(char) * (len_cur_num + 1));
            cur_num[len_cur_num] = temp % 10;
            temp = temp / 10;
        }

        //Multiply prod by 256 and save that as prod_term
        len_prod_term = 0;
        prod_term = NULL;

        for (i = 0; i < len_b_256; i++)
        {                                                                        //Repeat this loop 3 times, one for each element in {6,5,2} (256 as a reversed base-10 unsigned char array)
            carry = 0;                                                           //Set the carry to 0
            prod_term = realloc(prod_term, sizeof(*prod_term) * (len_prod + i)); //Allocate memory to save prod_term
            for (j = i; j < (len_prod_term); j++)                                //If we have digits from the last partial product of the multiplication, add it here
            {
                prod_term[j] = prod_term[j] + prod[j - i] * b_256[i] + carry;
                if (prod_term[j] > 9)
                {
                    carry = prod_term[j] / 10;
                    prod_term[j] = prod_term[j] % 10;
                }
                else
                {
                    carry = 0;
                }
            }

            while (j < (len_prod + i)) //No remaining elements of the former prod_term, so take only into account the results of multiplying mult * b_256
            {
                prod_term[j] = prod[j - i] * b_256[i] + carry;

                if (prod_term[j] > 9)
                {
                    carry = prod_term[j] / 10;
                    prod_term[j] = prod_term[j] % 10;
                }
                else
                {
                    carry = 0;
                }
                j++;
            }

            if (carry) //A carry may be present in the last term. If so, allocate memory to save it and increase the length of prod_term
            {
                len_prod_term = j + 1;
                prod_term = realloc(prod_term, sizeof(*prod_term) * (len_prod_term));
                prod_term[j] = carry;
            }
            else
            {
                len_prod_term = j;
            }
        }

        free(prod); //We don't need prod anymore, prod will now be prod_term
        prod = prod_term;
        len_prod = len_prod_term;

        //Add prod (formerly prod_term) to our current number of the num array, expressed in a b-10 array
        carry = 0;
        for (i = 0; i < len_cur_num; i++)
        {
            prod[i] = prod[i] + cur_num[i] + carry;
            if (prod[i] > 9)
            {
                carry = prod[i] / 10;
                prod[i] -= 10;
            }
            else
            {
                carry = 0;
            }
        }

        while (carry && (i < len_prod))
        {
            prod[i] = prod[i] + carry;
            if (prod[i] > 9)
            {
                carry = prod[i] / 10;
                prod[i] -= 10;
            }
            else
            {
                carry = 0;
            }
            i++;
        }

        if (carry)
        {
            len_prod++;
            prod = realloc(prod, sizeof(*prod) * len_prod);
            prod[len_prod - 1] = carry;
            carry = 0;
        }
    }

    str = malloc(sizeof(char) * (len_prod + 1)); //Allocate memory for the return string

    for (i = 0; i < len_prod; i++) //Convert the numeric result to its representation as characters
    {
        str[len_prod - 1 - i] = prod[i] + '0';
    }

    str[i] = '\0'; //Terminate our string

    free(b_256); //Free memory
    free(prod);
    free(cur_num);

    return str;
}

这一切背后的想法源自简单的数学。对于任何以256为底的数字,其以10为底的表示可以计算为: num[i]*256^i + num[i-1]*256^(i-1) + (···) + num[2]*256^2 + num[1]*256^1 + num[0]*256^0

扩展为: (((((num[i])*256 + num[i-1])*256 + (···))*256 + num[2])*256 + num[1])*256 + num[0]

所以我们要做的就是一步一步地将数字数组的每个元素乘以256,然后将下一个元素加到该元素上,依此类推...这样我们就可以得到以10为底的数字