【问题标题】:Large integer radix/base conversion from 10^x to 2^x从 10^x 到 2^x 的大整数基数/基数转换
【发布时间】:2011-09-09 16:07:06
【问题描述】:

前言

我正在通过编写和改进自己的 BigInt 库来学习计算机数学。到目前为止,我的第一个版本将基数为 10 的数字的每个数字存储在向量的连续元素中。它可以以任意精度进行乘法和加法。我想通过转换为基数 2^x 来使用标准 C++ 数据类型中的所有可用空间来加速它。

信息

我正在从标准输入读取 1000 个或更多数字,以 10 为基数,我希望将它们转换为以 2^x 为基数,因此我可以轻松地将它们存储在标准 C++ 数据类型之一的数组或向量中,可能是无符号整数。我对如何进行基本转换只有一个想法,即用余数重复除法。下面是一些描述该方法的 C++ 代码:

vector<int> digits;
while(num!=0) {
   int mod = num%base;
   num = num/base;
   digits.push_back(mod);
}

难题

我不知道的一些事情是除以余数是否是对大整数进行基数转换的正确方法。我试过看看 GMP 库 是如何做到的。 gmp/mpn/generic/set_str.c 是发生“魔法”的相关 c 源文件,但我不确定那里发生了什么。 Matt McCutchen 的 BigInt 似乎使用了带余数的重复除法。如果我确实使用这种方法,我基本上需要编写我的 BigInt 类的两个版本,一个用于在 Base10 中工作,另一个用于 Base2^x。

结论

  • 就将大数从字符串转换为 32 位字数组的正确步骤提供建议。
  • 帮助我了解 GMP 如何将字符串转换为 32 位字的数组,而无需涉足许多抽象层。

使用 4 位字长的示例

我们要存储的数字(显然是小号):123456789

无符号字符的范围为 0-255,如果我们想拆分我们的数字并将其存储在向量中,我们可以通过以下三种方式之一进行:

  • 以 10 为底,我们的向量看起来像:[1,2,3,4,5,6,7,8,9]
    • 这是我的向量在我的第一个实现中的样子。
  • 以 100 为底,我们的向量看起来像:[1,23,45,67,89]
    • 易于从基数 10 转换为基数 100,具有 ciel(base10/2 中的数字)元素。
  • 以 256 为基数,我们的向量如下所示:[7,91,205,21]

显然,第三种解决方案对于内部表示来说是最佳的,也是我想要达到的。

【问题讨论】:

  • 您是否将字符串到 bigint 的转换与 bigint 到字符串的转换混淆了?
  • @MarkRansom - 不,我正在尝试读取字符串并将其存储为 bigint。
  • 一个 bigint 类可能更适合存储更大的块,而不是更小的块。与其从 10 降到 2,不如升到 2^31-1 之类的更好。
  • C 接口和实现amazon.com/… 这本书有一个完整的工作 bigint 库,详细解释。这不是一本的书(还可以,只是不例外),但听起来它在这里很适合你。

标签: algorithm math gmp bigint


【解决方案1】:

FryGuy 的帖子中没有提到的一件事是,在该方法中,必须在您将 转换为 的基数中进行算术运算,而用作乘数的基数是相同的作为您原始号码的基础;您不再需要的基础或要转换的基础来自

整数的基数转换有两个公式。 (1) 使用base B,我们将(目标基础)转换为重复除数,加上在base b中完成的算术,其中b是基础转换from . (2) 另一方面,使用基数 b 作为我们正在转换的数字的乘数,这些数字恰好在同一个基数 b 中,并且在基数 B 中进行算术运算。

(1) 公式以B为参数,以b为基数进行算术运算

(2) 公式以b为参数,以B为基数进行算术运算

这是 knuth, vol 2, 4.4 基数转换

【讨论】:

  • 一些进一步的信息:算术模一些基础 b 可以用同一本书中提到的众所周知的算法来执行
【解决方案2】:

一旦您拥有适用于 bigint 库的乘法和加法函数,将字符串转换为 bigint 本身就很简单。从零转换结果开始。对于您处理的每个数字(从左到右),将前一个结果乘以 10 并添加新数字的值(使用您的 bigint 乘法和加法函数)。

【讨论】:

  • 虽然应该注意,将 BigInt 转换为整数几乎是您必须为 BigInt 库实现的最复杂的函数;)
  • 这个答案错过了问题的重点。如果我读取 1234 的每个数字并将其存储在 vector 中,它看起来像 [1,2,3,4]。我希望能够使用这些单个 char 元素的全部范围。 1234 可以表示为两个字符元素 [4,210]。 4*(256^1) + 210*(256^0) = 1234
  • @Dezzimal:对于您读取的每个数字,将 x 乘以 10,然后将该数字添加到 x(x 是您的基数 256 变量)。对于“1000”,x 的进展如下:[0]、[1]、[10]、[100]、[3,232]。
  • 我也设法错过了这个答案的简单性,@Tom 启发了我。
  • 高中数学,伙计们 =) 记住小学的 1s、10s 和 100s 列 =) 不过答案非常好且清晰。
【解决方案3】:

一般来说,要将一个基数转换为另一个基数(从最高有效位到最低位),算法如下:

output = 0
foreach digit in digits:
    output = output * base + digit

按相反的顺序,如下:

output = 0
multiplier = 1
foreach digit in digits:
    output = output + multiplier * digit
    multiplier = multiplier * base

您可以递归地使用您的 bigint 库,使用此数学计算出如何存储数字。我的意思是你需要实现 BigInt*BigInt 和 BigInt+BigInt,所以这就是转换基数的方法。这不是最有效的方法,但比除法快很多。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-10-25
    • 1970-01-01
    • 2017-02-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多