Why to use higher base for implementing BigInt?

僤鯓⒐⒋嵵緔 提交于 2019-12-29 09:07:09

问题


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:


  1. 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.

  2. 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
  1. ???

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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!