我正在尝试实现BigInt并阅读了一些关于它的线程和文章,其中大多数建议使用更高的基数(256或2 ^ 32甚至2 ^ 64)。
为什么更高的基数有利于此目的?
我遇到的其他问题是我应该如何将字符串转换为更高的字符串(> 16)。我读过没有标准的方法,除了base64。最后一个问题,我如何使用这些更高的基础。一些例子会很棒。
答案 0 :(得分:8)
用于乘以或添加适合寄存器的数字的CPU周期往往是相同的。因此,通过使用整个寄存器,您将获得最少的迭代次数和最佳性能。也就是说,在32位架构上,使基本单元为32位,在64位架构上,使其为64位。否则 - 比方说,如果你只填满32位寄存器的8位 - 你就是在浪费周期。
答案 1 :(得分:2)
第一个答案说得最好。我个人使用base 2 ^ 16来防止乘法溢出。这允许任何两个数字一起乘以一次而不会溢出。
转换为更高的基数需要快速分割方法以及尽可能地打包数字(假设你的BigInt lib可以处理多个碱基)。
考虑基数10 - >基数2.实际转换数为10 - > 10000 - > 32768 - > 2.这可能看起来较慢,但从10基数转换为10000是非常快的。在10000和32768之间进行转换的迭代次数非常快,因为迭代的数字非常少。将32768打包成2也非常快。
首先将基地打包到它可以去的最大基地。要做到这一点,只需将数字组合在一起。该基数应为< = 2 ^ 16以防止溢出。
接下来,将数字组合在一起,直到它们是> =目标基数。从这里开始,使用快速划分算法除以目标基数,该算法通常会在任何其他场景中溢出。
一些快速代码
if (!packed) pack()
from = remake() //moves all of the digits on the current BigInt to a new one, O(1)
loop
addNode()
loop
remainder = 0
remainder = remainder*fromBase + from.digit
enter code here`exitwhen remainder >= toBase
set from = from.prev
exitwhen from.head
if (from.head) node.digit = remainder
else node.digit = from.fastdiv(fromBase, toBase, remainder)
exitwhen from.head
看看快速划分
loop
digit = remainder/divide
remainder = remainder%divide
//gather digits to divide again
loop
this = prev
if (head) return remainder
remainder = remainder*base + digit
exitwhen remainder >= divide
digit = 0
return remainder
最后,如果你应该解压缩,请解压缩
打包只是将数字组合在一起。
基础10到基础10000的实例
4th*10 + 3rd
*10 + 2nd
*10 + 1st
你应该有一个Base类来存储toString的字母+大小。如果Base无效,则只需在逗号分隔列表中显示数字。
你所有的方法都应该使用BigInt的当前基础,而不是一些常量。
这就是全部?
从那里,你将能够做到像
这样的事情BigInt i = BigInt.convertString("1234567", Base["0123456789"])
[]重载的地方,将创建一个新的基础或返回已经创建的基础。
您还可以执行
之类的操作i.toString()
i.base = Base["0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"]
i.base = 256
i.base = 45000
etc ^ _ ^。
另外,如果你使用整数并希望能够返回BigInt余数,则除法可能会有点棘手= P,但它仍然很容易^ _ ^。
This is a BigInt library I coded in vjass (yes, for Warcraft 3, lol, don't judge me)
像TriggerEvaluate(evalBase)
之类的东西只是为了防止线程崩溃(邪恶的操作限制)。