C 将bignum类型结构转换为可读字符串的有效方法是什么?
我有点问题。为了增加我对C的了解,我决定尝试实现一个基本的bigint库 bigint结构的核心将是一个32位整数的数组,之所以选择它是因为它们将适合寄存器。这将允许我在64位整数中溢出的数字之间执行操作(在x86-64上,它也可以装入寄存器),并且可以将结果的每个部分进行位移位。我已经实现了基本加法,为了测试它是否工作,我必须打印数组。出于我自己的测试目的,如果我使用C 将bignum类型结构转换为可读字符串的有效方法是什么?,c,biginteger,c99,C,Biginteger,C99,我有点问题。为了增加我对C的了解,我决定尝试实现一个基本的bigint库 bigint结构的核心将是一个32位整数的数组,之所以选择它是因为它们将适合寄存器。这将允许我在64位整数中溢出的数字之间执行操作(在x86-64上,它也可以装入寄存器),并且可以将结果的每个部分进行位移位。我已经实现了基本加法,为了测试它是否工作,我必须打印数组。出于我自己的测试目的,如果我使用printf()并以十六进制输出每个数字,那就好了。我看得很清楚 然而,大多数人不会读十六进制。由于数字存储在(基本上)基数2^
printf()
并以十六进制输出每个数字,那就好了。我看得很清楚
然而,大多数人不会读十六进制。由于数字存储在(基本上)基数2^32中,所以打印有点麻烦。转换为10进制的好方法是什么
编辑:
这并不是要知道如何从一个基转换到另一个基,而是要知道实现这一点的好方法。我一直在考虑用另一个基数再做一个bigint,然后进行转换以进行打印。重复除以10的常规方法显然会非常缓慢 一个明显的快速方法是预先计算对应于每个位置每个数字值的bigint数组。然后,您可以进行二进制搜索和相对便宜的比较/减法,以找到ms数字,然后依次找到每个数字
当您回到最后32位(或64位)时,您可以恢复到10除法。首先,如果没有基本操作(例如除法和模),您无法以合理的方式进行I/O。为了提供将bigint转换为base-10字符串的有效实现,我正在研究两种可能的优化: 首先,你可以除以十的幂,而不是精确的十。这意味着,例如,每次将数字除以10000,您将得到四个以10为基数的数字 第二,你将如何选择10的哪一次方除以?10、100、1000、10000等……
似乎有一个很好的选择,它是适合您的字(32位)的最大10次方。幸运的是,与使用两个“bigint”时相比,您可以通过一个单词更有效地实现除法/模
我还没有给出一个实现,因为我仍在业余时间研究这个问题,因为我已经在我的库中实现了基本的操作,希望I/O是下一步;) 除以适合基本类型的最大10次方是最好的开始方式。在你的例子中,这是除以10^9。此代码应该是通用的,因为您可以将其重新用于通用除法/模代码的一部分 运行时间将为O(n^2)(即,如果您的数字是原来的两倍,则转换时间将延长四倍),但对于中等大小的数字,运行时间应该足够快 对于非常大的值,您需要缓存10的大幂,例如10^1000、10^2000、10^4000、10^8000等,然后除以大于或等于您尝试转换的数字的1/2的10幂。重复此过程,直到数字足够小,可以使用10^9除法快速转换。根据除法算法的效率,在遇到超过一百万位数或更多的数字之前,这种方法可能不会更快
如果您正在编写一个交互式计算器,其中每个数字都将显示出来,那么使用基数10^9将更快地显示出来(它将是O(n),即,如果您的数字是两倍大,则转换只需要两倍的时间)。我能想到的最有效的算法如下所示。它的运行时复杂度应为O(n·(logn)²•logn),而不是具有二次运行时复杂度的朴素算法
在步骤2和5中,您需要一个十进制乘法算法。对于数万位数的数字,应该使用以10为基数的Schönhage-Strassen算法版本。这将导致上述运行时复杂性。对于较短的数字,根据其长度,应使用Toom Cook算法、Karatsuba算法或长乘法。然而,我目前无法告诉如何在10进制中实现Schönhage-Strassen算法,因为我能找到的所有完整描述都是针对2进制的,我自己也不知道足够的数论来推导它。你打算缓存每个bigint?它们有无数个。@recursive-不是所有可能的bigint。所有可能的bigint都是零,除了一。因此,如果最大的bigint将导致以10为基数的28位数字,那么您将缓存280个值。@crhisharris:对于大多数典型的bigint使用,与更复杂的操作(如乘以两个bignum(或更糟糕的是,乘以它们的矩阵)相比,重复除以10的成本微不足道,或者测试它们的素数。我想我理解你的方法,但我不确定它会比每一步除以10更快。记住,比较占用k32位的两个bigint