• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.
  • Create a faction for Warcraft 3 and enter Hive's 19th Techtree Contest: Co-Op Commanders! Click here to enter!
  • Create a void inspired texture for Warcraft 3 and enter Hive's 34th Texturing Contest: Void! Click here to enter!
  • The Hive's 21st Texturing Contest: Upgrade is now concluded, time to vote for your favourite set of icons! Click here to vote!

Came Up With Reliable Division Algorithm!!!

Status
Not open for further replies.
What is 83/19?

1. Divide first digits
[8]3/[1]9
8/1 = 8

2. Subtract second digit * guess
If second digit >= base/2, subtract second digit * guess * 1/2 + 1

83/1[9]

Guess: 8
9*8 = [7]2
9 >= 10/2
7/2 = 3 + 1 = 4
8 - 4 = 4

3. Multiply by guess
19*4 = 76

4. Subtract
83-76 = 7

5. Repeat until remainder < divisor
7 < 19

Answer: 4 r7


With this, I can now go back to BigInt v2 ;D

edit
1 snag in the algorithm, but fixed it

If the initial guess is 0, do first 2 digits of dividend divided by first digit of divisor. From there, instead of subtracting first digit of product guess*2nd last digit, do product/first 2 digits of dividend. Appears to work perfectly.

edit
Ok, here is the library. If anyone could try out a variety of numbers to make sure I got all of the bugs, I'd really appreciate it ^)^. Just make sure the output is what it's supposed to be.

You can't add/divide/multiply/subtract numbers of different bases, so if you purposefully make the 2 numbers different bases, it won't work. I haven't done stuff to avoid op limit in this yet, so if you don't see the messages, don't whine about it because I already know. Please use base 32768 as higher bases have less accuracy for guessing ^)^. The current numbers in there do in fact give out correct results.

Do not check the results against microsoft's calculator as BigInt is more accurate >.<, meaning you will get strange things for large numbers. Use this site instead -> http://world.std.com/~reinhold/BigNumCalc.html


Anyways, as soon as I write some docs, make this work off of Base, and add a few more features, this'll be ready for release given nobody gets bad output ;D. Oh, and if you take a look, the multiply algorithm is actually a lot faster than it used to be ; P. And yes, this division algorithm is 100% reliable, 0 chance of overflow, fuahahahah ;D.

Oh yea, and this is still totally unsigned... signed bit ints for wc3 are totally pointless >.<.
JASS:
//! textmacro TEST
    struct Tester extends array
        private static method init takes nothing returns nothing
            local string dividendV = "120043923300"
            local string divisorV = "15339"
            local BigInt remainder
            local BigInt dividend = BigInt.convertString(dividendV, 32768)
            local BigInt divisor = BigInt.convertString(divisorV, 32768)
            
            call DestroyTimer(GetExpiredTimer())
            
            call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,10,"Divisor: " + divisorV + " == " + divisor.toString())
            call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,10,"Dividend: " + dividendV + " == " + dividend.toString())
            
            //call divisor.addBig(dividend)
            //call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,10,divisor.toString())
            
            set remainder = dividend.divide(divisor)
            
            call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,10,"Divided: "+dividend.toString())
            call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,10,"Remainder: "+remainder.toString())
        endmethod
        
        private static method onInit takes nothing returns nothing
            call TimerStart(CreateTimer(), 0, false, function thistype.init)
        endmethod
    endstruct
//! endtextmacro

library BigInt
    private struct BigInt extends array
        readonly thistype next
        readonly thistype prev
        integer digit
        readonly boolean head
        readonly integer base
        
        private static integer count = 0
        
        private static method allocate takes nothing returns thistype
            local thistype this = thistype(0).next
            if (0 == this) then
                set this = count + 1
                set count = this
            else
                set thistype(0).next = next
            endif
            
            set digit = 0
            
            return this
        endmethod
        private method ad takes thistype n returns nothing
            set n.next = this
            set n.prev = prev
            set prev.next = n
            set prev = n
        endmethod
        private method adp takes thistype n returns nothing
            set n.next = next
            set n.prev = this
            set next.prev = n
            set next = n
        endmethod
        private method carryOver takes thistype root, integer carry, integer base returns nothing
            loop
                exitwhen 0 == carry
                set this = next
                if (head) then
                    set this = allocate()
                    call root.ad(this)
                endif
                set digit = digit + carry
                set carry = digit/base
                set digit = digit - digit/base*base
            endloop
        endmethod
        method add takes integer i returns nothing
            local integer base = this.base
            local integer carry = 0
            local thistype root = this
            
            loop
                exitwhen 0 == i
                set this = next
                set digit = digit + i - i/base*base + carry
                set i = i/base
                set carry = digit/base
                set digit = digit - digit/base*base
                if (head) then
                    set this = allocate()
                    call root.ad(this)
                endif
            endloop
            
            call carryOver(root, carry, base)
        endmethod
        method addBig takes BigInt i returns nothing
            local integer base = this.base
            local integer carry = 0
            local thistype root = this
            local integer count = 0
            
            set i = i.next
            loop
                exitwhen i.head
                
                set carry = i.digit
                set i = i.next
                set this = next
                if (head) then
                    set this = allocate()
                    call root.ad(this)
                endif
                set digit = digit + carry
                set carry = digit/base
                set digit = digit - digit/base*base
            endloop
            
            call carryOver(root, carry, base)
        endmethod
        method operator < takes thistype i returns boolean
            loop
                set this = next
                set i = i.next
                exitwhen head or i.head
            endloop
            return (head == i.head and prev.digit < i.prev.digit) or (head and not i.head)
        endmethod
        method eq takes thistype i returns boolean
            loop
                set this = next
                set i = i.next
                exitwhen head or i.head or digit != i.digit
            endloop
            return head and i.head
        endmethod
        method ltoe takes thistype i returns boolean
            loop
                set this = next
                set i = i.next
                exitwhen head or i.head
            endloop
            return (head == i.head and prev.digit <= i.prev.digit) or (head and not i.head)
        endmethod
        static method create takes integer i, integer base returns thistype
            local thistype this = allocate()
            
            set this.base = base
            set next = this
            set prev = this
            set head = true
            
            call add(i)
            
            return this
        endmethod
        method clear takes nothing returns nothing
            if (not next.head) then
                set prev.next = thistype(0).next
                set thistype(0).next = next
            endif
            set digit = 0
        endmethod
        method destroy takes nothing returns nothing
            set head = false
            set prev.next = thistype(0).next
            set thistype(0).next = this
        endmethod
        method copy takes nothing returns thistype
            local thistype clone = allocate()
            local thistype n = clone
            set clone.next = clone
            set clone.prev = clone
            set clone.base = base
            set clone.head = true
            loop
                set this = next
                exitwhen head
                set n = allocate()
                call clone.ad(n)
                set n.digit = digit
            endloop
            return clone
        endmethod
        method remake takes nothing returns thistype
            local thistype clone = allocate()
            set clone.base = base
            set clone.head = true
            if (not next.head) then
                set clone.next = next
                set clone.prev = prev
                set clone.next.prev = clone
                set clone.prev.next = clone
                set next = this
                set prev = this
            else
                set clone.next = clone
                set clone.prev = clone
            endif
            return clone
        endmethod
        method enq takes integer i returns nothing
            local thistype n = allocate()
            call ad(n)
            set n.digit = i
        endmethod
        method push takes integer i returns nothing
            local thistype n = allocate()
            call adp(n)
            set n.digit = i
        endmethod
        method toInt takes nothing returns integer
            local integer i = 0
            local integer base = this.base
            loop
                set this = prev
                exitwhen head
                set i = i*base+digit
            endloop
            return i
        endmethod
        method toString takes nothing returns string
            local string s = ""
            
            if (next.head) then
                return "0"
            endif
            loop
                set this = next
                exitwhen head
                set s = I2S(digit) + ", " + s
            endloop
            
            return s
        endmethod
        method subtract takes BigInt i returns nothing
            local integer base = this.base
            loop
                set this = next
                exitwhen i.head
                if (digit < i.digit) then
                    set next.digit = next.digit - 1
                    set digit = digit + base
                endif
                set digit = digit - i.digit
                set i = i.next
            endloop
            
            set base = prev
            loop
                set this = base
                set base = prev
                exitwhen 0 != digit or head
                set next.prev = prev
                set prev.next = next
                set next = thistype(0).next
                set thistype(0).next = this
            endloop
        endmethod
        method multiply takes integer i returns nothing
            local integer carry = 0
            local integer base = this.base
            local thistype root = this
            local integer m = 0
            loop
                set this = next
                exitwhen head and 0 == carry
                if (head) then
                    set this = allocate()
                    call root.ad(this)
                endif
                set digit = digit*i + carry
                set carry = digit/base
                set digit = digit - digit/base*base
            endloop
        endmethod
        method addString takes string s returns nothing
            local integer base = this.base
            local integer carry = 0
            local thistype root = this
            local integer i = StringLength(s)
            
            loop
                exitwhen 0 == i
                set carry = S2I(SubString(s, i - 1, i))
                set i = i - 1
                set this = next
                if (head) then
                    set this = allocate()
                    call root.ad(this)
                endif
                set digit = digit + carry
                set carry = digit/base
                set digit = digit - digit/base*base
            endloop
            call carryOver(root, carry, base)
        endmethod
        static method convertString takes string s, integer base returns thistype
            local thistype this = allocate()
            
            set this.base = base
            set next = this
            set prev = this
            set head = true
            
            call addString(s)
            
            return this
        endmethod
        
        private boolean hit
        private static boolean act
        private method subtractFront takes BigInt i, BigInt d, integer guess returns nothing
            local integer base = this.base
            local thistype root = this
            local boolean b
            local boolean b2
            local thistype mult2
            local BigInt mult
            local integer c = 0
            
            loop
                set this = root
                set b = false
                set b2 = false
                set mult = d.copy()
                call mult.multiply(guess)
                set mult2 = mult
                loop
                    set mult = mult.next
                    set mult2 = mult2.prev
                    exitwhen mult.head
                    set this = prev
                    set b = b or (not b2 and digit < mult2.digit)
                    set b2 = b2 or digit != mult2.digit
                endloop
                
                if (b) then
                    set guess = guess - 1
                    if (0 == guess) then
                        set this = prev
                        set guess = 1
                        exitwhen true
                    else
                        call mult.destroy()
                    endif
                else
                    exitwhen true
                endif
            endloop
            
            //call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,10,"Solution: "+I2S(guess))
            //call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,10,I2S(guess)+"*"+d.toString()+" = "+mult.toString())
            //call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,10,root.toString()+" - "+mult.toString())
            
            set mult = mult.next
            loop
                if (hit) then
                    set act = true
                elseif (act) then
                    if (0 < c) then
                        call i.push(0)
                    endif
                    set c = c + 1
                endif
                set hit = true
                if (digit < mult.digit) then
                    set next.digit = next.digit - 1
                    set digit = digit + base
                endif
                set digit = digit - mult.digit
                set mult = mult.next
                set this = next
                exitwhen mult.head
            endloop
            
            set this = root
            set base = prev
            loop
                set this = base
                set base = prev
                exitwhen 0 != digit or head
                set next.prev = prev
                set prev.next = next
                set next = thistype(0).next
                set thistype(0).next = this
            endloop
            
            call mult.destroy()
            
            call i.push(guess)
        endmethod
        method divide takes thistype d returns integer
            local BigInt r = remake()
            local integer guess
            local integer base = this.base
            
            //local integer m = 90
            local integer d2
            
            set act = false
            
            if (r.next.head and d.next.head) then
                set this.next.digit = r.next.digit/d.next.digit
                set r.next.digit = r.next.digit - r.next.digit/d.next.digit*d.next.digit
            endif
            
            loop
                set r = r.next
                exitwhen r.head
                set r.hit = false
            endloop
            
            loop
                exitwhen r.ltoe(d)
                
                set guess = r.prev.digit/d.prev.digit
                if (0 == guess) then
                    set guess = (r.prev.digit*base+r.prev.prev.digit)/d.prev.digit
                    //call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,10,"("+I2S(r.prev.digit)+"*"+I2S(base)+" + "+I2S(r.prev.prev.digit)+")/"+I2S(d.prev.digit))
                    //call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,10,I2S(r.prev.digit)+","+I2S(r.prev.prev.digit)+"-> "+I2S(r.prev.digit*base+r.prev.prev.digit)+"/"+I2S(d.prev.digit))
                else
                    set guess = (r.prev.digit*base+r.prev.prev.digit)/(d.prev.digit*base+d.prev.prev.digit)
                    //call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,10,"("+I2S(r.prev.digit)+"*"+I2S(base)+" + "+I2S(r.prev.prev.digit)+")/("+I2S(d.prev.digit)+"*"+I2S(base)+" + "+I2S(d.prev.prev.digit)+")")
                    if (0 == guess) then
                        set guess = base - 1
                    endif
                    //call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,10,I2S((r.prev.digit*base+r.prev.prev.digit))+"/"+I2S((d.prev.digit*base+d.prev.prev.digit)))
                endif
                if (0 > guess) then
                    set guess = guess/0
                endif
                
                //call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,10,"First Guess: "+I2S(guess))
                
                call r.subtractFront(this, d, guess)
                
                //call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,10,"-> "+r.toString())
                //call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,10,"New Dividend: "+this.toString())
                
                //set m = m - 1
                //if (0 == m) then
                //    return r
                //endif
            endloop
            
            if (act and not r.next.hit) then
                call push(0)
                set this = next.next
                
                set d = allocate()
                set d.next = next
                set d.prev = this
                set next.prev = d
                set next = d
            endif
            
            return r
        endmethod
    endstruct
    
    //! runtextmacro TEST()
endlibrary
 
Last edited:
Status
Not open for further replies.
Top