Why to use higher base for implementing BigInt?

前端 未结 2 1823
长情又很酷
长情又很酷 2020-12-12 01:16

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 232 or even 264

相关标签:
2条回答
  • 2020-12-12 02:01

    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.

    0 讨论(0)
  • 2020-12-12 02:07
    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

    0 讨论(0)
提交回复
热议问题