Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/70.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 将bignum类型结构转换为可读字符串的有效方法是什么?_C_Biginteger_C99 - Fatal编程技术网

C 将bignum类型结构转换为可读字符串的有效方法是什么?

C 将bignum类型结构转换为可读字符串的有效方法是什么?,c,biginteger,c99,C,Biginteger,C99,我有点问题。为了增加我对C的了解,我决定尝试实现一个基本的bigint库 bigint结构的核心将是一个32位整数的数组,之所以选择它是因为它们将适合寄存器。这将允许我在64位整数中溢出的数字之间执行操作(在x86-64上,它也可以装入寄存器),并且可以将结果的每个部分进行位移位。我已经实现了基本加法,为了测试它是否工作,我必须打印数组。出于我自己的测试目的,如果我使用printf()并以十六进制输出每个数字,那就好了。我看得很清楚 然而,大多数人不会读十六进制。由于数字存储在(基本上)基数2^

我有点问题。为了增加我对C的了解,我决定尝试实现一个基本的bigint库

bigint结构的核心将是一个32位整数的数组,之所以选择它是因为它们将适合寄存器。这将允许我在64位整数中溢出的数字之间执行操作(在x86-64上,它也可以装入寄存器),并且可以将结果的每个部分进行位移位。我已经实现了基本加法,为了测试它是否工作,我必须打印数组。出于我自己的测试目的,如果我使用
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),而不是具有二次运行时复杂度的朴素算法

  • 在不丧失一般性的情况下,假设数字A为2n+1位长。它可能有前导零
  • 如果这是最高递归级别,则通过重复平方运算计算i到n的数字22i的十进制表示形式
  • 将输入编号的位序列分为两部分B和C。具有较低有效位的部分C包括A的2n个最低有效位,而部分B是剩余的较高有效位
  • 使用 二次运行时算法,如果它们足够短,或者通过递归调用此算法
  • 将B的十进制表示形式乘以缓存的十进制表示形式22n,然后将C的十进制表示形式相加,得到A的十进制表示形式

  • 在步骤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