有没有一种方法可以将基数 2^64 数字转换为字符串形式的 base10 值,或者在不使用大数字库的情况下以 C 或 C++ 标准输出显示它?

Is there a way to convert a base 2^64 number to its base10 value in string form or display it in standard out in C or C++ without using big num libs?

假设我有一个使用 unsigned long(int64) 数组表示的非常大的数字,我希望看到它的 base10 形式存储在字符串中 and/or 将其显示为标准直接输出,如果不使用 gmp 或 boost 等库,我如何在 C 或 C++ 中执行此操作?我应该知道什么算法或方法?

下面是一个 base2^64 数字示例,其 base10 值在注释中

// base2^64
unsigned long big_num[3] = [77478, 656713, 872];

// base10 = 26364397224300470284329554475476558257587048

我不确定这是否是将另一个数字基数转换为基数 10 的正确方法,但这是我所做的:

为了得到 base10 值 26364397224300470284329554475476558257587048,我总结了 base2^64 数字的所有数字,乘以它的基数并乘以数字的索引。

base10 = ((77478 * ((2^64)^2)) + ((656713 * ((2^64)^1))) + ((872 * ((2 ^64)^0)))) = 26364397224300470284329554475476558257587048

唯一的问题是没有原始数据类型可以容纳这个超大数额...

我只是在想 boost cpp_intgmp 这样的库是否像这样表示它们的数字,如果是,它们如何将其转换为字符串形式的 base10 值或显示 base10 值标准输出?

或者他们是否只使用他们使用的数据类型的一半位,例如 unsigned long 并且可能使用类似 base 10000 的东西?

要得到这个数的小数表示,需要反复将这个数除以10,取余数得到小数位数。这意味着您需要为大数实现长除法,这也需要实现长加减乘法。

大数库给你的代码太多了,所以只用一个。

重复“mod10”数组以找到下一个最低有效的小数位,然后“除以 10”。根据需要重复。

避免unsigned long编码 64 位值,因为它可能只有 32 位。


如果代码可以使用最宽的类型对数字 而不是 进行编码并使用 uin32_t,那么重复数组的“mod 10”就是没那么难。

下面的说明性代码仍然需要反转字符串 - 留给 OP。也可能存在其他缺点 - 因此使用大数字库来处理这类事情的优势。

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

// Form reverse decimal string
void convert(char dec[], size_t n, uint32_t b32[]) {
  // TBD code to handle 0

  while (n > 0 && b32[0] == 0) {
    b32++;
    n--;
  }
  while (n > 0) {
    unsigned char rem = 0;
    // Divide by 10.
    for (size_t i = 0; i < n; i++) {
      uint64_t sum = rem * (1ULL << 32) + b32[i];
      b32[i] = (uint32_t) (sum / 10u);
      rem = (unsigned char) (sum % 10u);
    }
    *dec++ = (char) (rem + '0');
    if (b32[0] == 0) {
      b32++;
      n--;
    }
  }
  *dec = 0;
}

样本

int main() {
  // unsigned long big_num[3] = [77478, 656713, 872];
  uint32_t big_num[6] = {0, 77478, 0, 656713, 0, 872};
  size_t n = sizeof big_num / sizeof big_num[0];
  char s[sizeof big_num * 10 + 1];
  convert(s, n, big_num);
  printf("<%s>\n", s);
  // <84078575285567457445592348207400342279346362>
  //  26364397224300470284329554475476558257587048
}