c中ascii的任意精度数

时间:2017-10-15 18:54:39

标签: c math arbitrary-precision

我有一个uint8_t *数组,其中包含任意精确数bigendian编码。

我想得到它的十进制Ascii表示。所以我需要编写一个返回char *

的函数

由于硬件限制,我正在使用的环境不允许我导入任何任意精度库。

我确信有一些东西我可以阅读以轻松实现它。

例如,以下十六进制d53ceb9d32c6ca06定义的数字应由15365415089075571206表示。

1 个答案:

答案 0 :(得分:-1)

这是一个应该有用的方法。请注意,它破坏性地修改了传递给它的bigint,因此如果您关心那里的值,请在调用方法之前将其复制到临时暂存缓冲区。

此外,这不是您可以编写的最优化版本,但如果您在此处询问如何执行此操作,您可能不会关注微观优化。

#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>

bool is_zero(uint8_t *bigi_data, int bigi_size) {
    int i = 0;

    while((i < bigi_size) && (bigi_data[i] == 0)) {
        i++;
    }
    return (i >= bigi_size);
}

uint8_t bigdivmod(uint8_t *bigi_data, int bigi_size, uint8_t divisor) {
    int i = 0;
    uint16_t ans = 0;

    while((i < bigi_size) && (bigi_data[i] == 0)) {
        i++;
    }
    for (; i < bigi_size; i++) {
        ans = ans*256 + bigi_data[i];
        bigi_data[i] = ans / divisor;
        ans = ans % divisor;
    }
    return (uint8_t)ans;
}

static const char *digits = "0123456789abcdefghijklmnopqrstuvwxyz";

char *bigitoa(uint8_t *bigi_data, int bigi_size, char *out, int base) {
    /* Assumes that "out" has enough room. DESTRUCTIVE TO BIGI, so copy */
    /* if you care about the value */
    /* Only really works for non-negative values */
    int i = 0;
    uint8_t swp;
    int j;

    if ((base < 2) || (base > 36)) {
        return NULL;
    }

    if (is_zero(bigi_data, bigi_size)) {
        out[0] = '0';
        out[1] = '\0';
        return out;
    }

    while (!is_zero(bigi_data, bigi_size)) {
        out[i++] = digits[bigdivmod(bigi_data, bigi_size, base)];
    }
    out[i] = 0;
    for (j = 0; j < i/2; j++) {
        swp = out[i - 1 - j];
        out[i - 1 - j] = out[j];
        out[j] = swp;
    }

    return out;
}

int main(int argc, char *argv[]) {
    uint8_t test_data[] = { 0xd5, 0x3c, 0xeb, 0x9d, 0x32, 0xc6, 0xca, 0x06 };
    int test_data_len = sizeof(test_data);
    char *p;

    /* Times 3 because we can use three digits to represent 256. If changing */
    /* the base below from "10", change this factor. */
    p = malloc(3*test_data_len + 1);

    printf("Test data works out to %s\n",
           bigitoa(test_data, test_data_len, p, 10));

    return 0;
}