【问题标题】:Arbitrary precision number to ascii in c [duplicate]c中ascii的任意精度数[重复]
【发布时间】:2017-10-15 18:54:38
【问题描述】:

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

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

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

我确信我可以阅读一些内容来轻松实现它。

例如下面十六进制d53ceb9d32c6ca06定义的数字应该用15365415089075571206表示。

【问题讨论】:

  • 你能举个例子吗?甚至可能是minimal reproducible example
  • 本质上,你必须实现长除法。
  • 这取决于您需要在文本和数字之间进行多少转换。如果您使用基数 100 而不是 256,则文本输出几乎是微不足道的,但需要权衡,因为使用 bignum 进行算术计算将需要使用效率较低的 % 而不是 & 来分隔部分总和,产品等。
  • @MatteoItalia 也许我错过了一些东西。您希望我将整个事物除以 10 所需的倍数,因为商(最后 8 位?)>10 并使用余数来构建字符串?
  • @Yunnosch 添加了示例。

标签: c math arbitrary-precision


【解决方案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;
}

【讨论】:

    猜你喜欢
    • 2011-05-30
    • 1970-01-01
    • 1970-01-01
    • 2012-08-25
    • 1970-01-01
    • 2021-05-27
    • 2011-10-21
    • 1970-01-01
    • 2014-04-25
    相关资源
    最近更新 更多