我已经寻找了一段时间来找到一种将整数转换为字符串的算法。我的要求是手动操作,因为我正在使用自己的大数类型。我已经定义了+ - * /(with remainder)
,但是需要找到一种从double int(高和低,如果int为64位,总共128位)中打印单个数字的方法。
我看到了一些答案,例如
Convert integer to string without access to libraries
Converting a big integer to decimal string
,但想知道是否可以使用更快的算法。我愿意直接使用位(例如,从base2到base10字符串-但是我找不到这样的算法),但是我只是希望避免对可能最大为2 ^ 128的数字重复除以10。
答案 0 :(得分:2)
您可以使用分治法,以便使用标准库将零件转换为字符串(通常在该工作中效率很高)。
因此,您不必例如在每次迭代中都除以10,除以10 ** 15,然后让您的库将这些块转换为15位数字的字符串。经过最多三个步骤,您就可以完成。
当然,您必须对零填充进行一些字符串操作。但是,如果您对所有较低的部分使用lapply/do.call/rbind.data.frame
零填充格式,而对于最高的非零部分使用非填充%015d
,则您的库也可以在这里为您提供帮助格式。
答案 1 :(得分:0)
您可以按以下方法尝试使用运气。
数字可以使用二进制编码的十进制表示形式表示。在此表示形式中,每个十进制数字都存储在4位上,当执行加法运算时,如果两个数字的总和超过9,则将6加起来并移到左边。
如果您预先存储了所有2的幂的BCD表示形式,则最多需要128个加法运算来执行转换。事实证明,对于低功率,您不需要全长加法(39位数字)。
但这听起来像是很多操作。您可以通过将多个BCD数字打包在一个整数中来“并行化”它们:32位整数相加等效于8个同时BCD数字相加。但是我们在携带上有问题。要解决此问题,我们可以将数字存储在5位而不是4位,并且进位将出现在第五位。然后我们可以通过掩蔽获得进位,将它们加到下一位(左移5位),然后调整位的总和(乘以10并减去)。
2 3 4 5 6
+ 7 6 9 2 1
= 9 913 7 7
携带:
0-0-1-0-0
调整:
9 913 7 7
-0000010000
= 9 9 3 7 7
实际上,您必须处理可能的级联进位,因此总和将涉及两个加数和进位,并生成总和并执行。
32位运算允许您一次处理6位数字(39位为7轮),而64位运算为12位数字(39位为4轮)。
答案 2 :(得分:0)
如果您只想将数字编码为字符串
使用 hex 数字,速度很快,因为您可以仅通过位运算来转换所有数字...也可以通过位运算+翻译来使用 Base64 编码表。展位表示只能在O(n)
中以小整数算术完成,其中n
是打印位数。
如果您需要base10
然后打印一个 hex 字符串,并将其转换为十进制字符串,如下所示:
这比#1 慢得多,但仍然可以在小型int算术上使用...您也可以使用dec2hex
反过来执行此操作(从字符串输入数字)...
对于 bigint 库,还有另一种简化字符串/整数转换的方法:
BCD
二进制编码的十进制数...以十六进制显示的数字是十进制数字。因此,每个数字都有4位。这会浪费一些内存,但是许多CPU都支持BCD,并且可以在本地对此类整数进行操作。
基础10^n
有时以10^n
为基础,而不是2^m
10^n <= 2^m
m
是原子整数的位宽,而n
是包含在其中的十进制数字的位数。
例如,如果您的原子无符号整数是16位,则它可以在基数65536
中容纳多达2
个值。如果您使用的是10000
底数,则可以从左用零填充键将每个原子打印为十进制数字,然后将所有这些打印件堆叠在一起。
这也会浪费一些内存,但通常不会浪费太多(如果合理地选择了位宽),并且您可以在整数上使用标准指令。只有进位传播会有所改变...
例如32位字词:
2^32 = 4294967296 >= 1000000000
所以我们每32位浪费log2(4.2949...) = ~2.1
位。这比BCD log2(16/10)*(32/4)= ~5.42
位要好得多,而且通常在位宽较高的情况下甚至更好