问题
I'm trying to implement BigInt and have read some threads and articles regarding it, most of them suggested to use higher bases(256 or 2^32 or even 2^64).
Why higher bases are good for this purpose?
Other question I have is how am I supposed to convert a string into higher base(>16). I read there is no standard way, except for base64. And the last question, how do I use those higher bases. Some examples would be great.
回答1:
The CPU cycles spent multiplying or adding a number that fits in a register tend to be identical. So you will get the least number of iterations, and best performance, by using up the whole register. That is, on a 32-bit architecture, make your base unit 32 bits, and on a 64-bit architecture, make it 64 bits. Otherwise--say, if you only fill up 8 bits of your 32 bit register--you are wasting cycles.
回答2:
first answer stated this best. I personally use base 2^16 to keep from overflowing in multiplication. This allows any two digits to be multiplied together once without ever overflowing.
converting to a higher base requires a fast division method as well as packing the numbers as much as possible (assuming ur BigInt lib can handle multiple bases).
Consider base 10 -> base 2. The actual conversions would be 10 -> 10000 -> 32768 -> 2. This may seem slower, but converting from base 10 to 10000 is super fast. The amount of iterations for converting between 10000 and 32768 is very fast as there are very few digits to iterate over. Unpacking 32768 to 2 is also extremely fast.
So first pack the base to the largest base it can go to. To do this, just combine the digits together. This base should be <= 2^16 to prevent overflow.
Next, combine the digits together until they are >= the target base. From here, divide by the target base using a fast division algorithm that would normally overflow in any other scenario.
Some quick code
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
A look at fast division
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
Finally, unpack if you should unpack
Packing is just combining the digits together.
Example of base 10 to base 10000
4th*10 + 3rd
*10 + 2nd
*10 + 1st
- ???
You should have a Base class that stores alphabet + size for toString. If the Base is invalid, then just display the digits in a comma separated list.
All of your methods should be using the BigInt's current base, not some constant.
That's all?
From there, you'll be able to do things like
BigInt i = BigInt.convertString("1234567", Base["0123456789"])
Where the [] is overloaded and will either create a new base or return the already created base.
You'll also be able to do things like
i.toString()
i.base = Base["0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"]
i.base = 256
i.base = 45000
etc ^_^.
Also, if you are using integers and you want to be able to return BigInt remainders, division can get a bit tricky =P, but it's still pretty easy ^_^.
This is a BigInt library I coded in vjass (yes, for Warcraft 3, lol, don't judge me)
Things like TriggerEvaluate(evalBase)
are just to keep the threads from crashing (evil operation limit).
Good luck :D
来源:https://stackoverflow.com/questions/10178055/why-to-use-higher-base-for-implementing-bigint