1. Updated Resource Submission Rules: All model & skin resource submissions must now include an in-game screenshot. This is to help speed up the moderation process and to show how the model and/or texture looks like from the in-game camera.
    Dismiss Notice
  2. DID YOU KNOW - That you can unlock new rank icons by posting on the forums or winning contests? Click here to customize your rank or read our User Rank Policy to see a list of ranks that you can unlock. Have you won a contest and still havn't received your rank award? Then please contact the administration.
    Dismiss Notice
  3. The Lich King demands your service! We've reached the 19th edition of the Icon Contest. Come along and make some chilling servants for the one true king.
    Dismiss Notice
  4. The 4th SFX Contest has started. Be sure to participate and have a fun factor in it.
    Dismiss Notice
  5. The poll for the 21st Terraining Contest is LIVE. Be sure to check out the entries and vote for one.
    Dismiss Notice
  6. The results are out! Check them out.
    Dismiss Notice
  7. Don’t forget to sign up for the Hive Cup. There’s a 555 EUR prize pool. Sign up now!
    Dismiss Notice
  8. The Hive Workshop Cup contest results have been announced! See the maps that'll be featured in the Hive Workshop Cup tournament!
    Dismiss Notice
  9. Check out the Staff job openings thread.
    Dismiss Notice
Dismiss Notice
60,000 passwords have been reset on July 8, 2019. If you cannot login, read this.

[Snippet] Complex Numbers

Discussion in 'JASS Resources' started by Malhorne, Dec 2, 2013.

  1. Malhorne

    Malhorne

    Joined:
    Sep 14, 2012
    Messages:
    2,330
    Resources:
    6
    Spells:
    4
    Tutorials:
    1
    JASS:
    1
    Resources:
    6
    If it can be used by someone I share it :
    Code (vJASS):
    library Complex/*
    ************************************************************************************
    *       Description
    *       -------------------------
    *
    *           This is a library that allows you to use complex number to do some gemotry
    *           or some special calculus.
    *
    *
    *       Credits to :
    *       -------------------------
    *           - looking_for_help for the InternLn function :)
    *
    *
    *       Fields
    *       -------------------------
    *
    *           struct Complex
    *               real re
    *               real im
    *
    *
    *       Methods
    *       -------------------------
    *          
    *           static method create takes nothing returns thistype
    *           static method createPolar takes real abs, real phase returns thistype
    *
    *           method destroy takes nothing returns nothing
    *
    *
    *           method add takes thistype z returns thistype
    *               ~ It returns this+z
    *
    *           method sub takes thistype z returns thistype
    *               ~ It returns this-z
    *
    *           method mul takes thistype z returns thistype
    *               ~ It returns this*z
    *
    *           method div takes thistype z returns thistype
    *               ~ It returns this/z
    *
    *           method conj takes nothing returns thistype
    *               ~ It returns the conjugate of this
    *
    *           method operator abs takes nothing returns real
    *               ~ It returns abs(this)
    *
    *           method operator abs= takes real value returns nothing
    *               ~ Change the abs of the complex of the number to value
    *
    *           method operator arg takes nothing returns real
    *               ~ It returns arg(this)
    *
    *           method operator arg= takes real value returns nothing
    *               ~ Change the argument of the complex of the number to value
    *
    *           method toString takes nothing returns string
    *               ~ It returns "a+bi"
    *
    *           method toStringPolar takes nothing returns string
    *               ~ It returns "abs*e^(arg*i)"
    *
    *           method ln takes nothing returns thistype
    *               ~ It returns ln(this)
    *
    *           method exp takes nothing returns thistype
    *               ~ It returns e^this
    *
    *           method pow takes thistype a returns thistype
    *               ~ It returns this^a
    *
    *           method sqrt takes nothing returns thistype
    *               ~ It returns sqrt(this)
    *
    *           method equals takes thistype z returns boolean
    *               ~ It returns if this==z or not
    ************************************************************************/

        globals
            private constant real E = 2.718282
            private constant real PI = 3.141592
            private constant real INV_E = 1/E
           
            //Change the maximum number of instance of complex number
            private constant integer MAX_NUMBER = 8190
        endglobals

        struct Complex [MAX_NUMBER]
            real re
            real im
       
            static method create takes real r, real i returns thistype
                local thistype this = thistype.allocate()
                set this.re = r
                set this.im = i
                return this
            endmethod
           
            static method createPolar takes real abs, real phase returns thistype
                if (abs < 0) then
                    debug call BJDebugMsg("thistype : Creating a Complex Number with abs<0, crashing the thread!")
                    return 1/0
                endif
                return create(abs*Cos(phase), abs*Sin(phase))
            endmethod
           
            //Thanks to looking_for_help !
            private static method internLn takes real r returns real
                local real sum = 0.0
                local real sign = 1.0
                if r < 1.0 then
                    set r = 1.0/r
                    set sign = -1.0
                endif
                loop
                    exitwhen r < E
                    set r = r*INV_E
                    set sum = sum + 1.0
                endloop
                loop
                    exitwhen r < 1.2840254
                    set r = r*0.778808
                    set sum = sum + 0.25
                endloop

                return sign*(sum + 0.125*(r - 1.0)*(1 + 9.0/(2.0 + r) + 4.5/(0.5 + r) + 1.0/r))
            endmethod
       
       
            method add takes thistype z returns thistype
                return create(this.re + z.re, this.im + z.im)
            endmethod
           
            method sub takes thistype z returns thistype
                return create(this.re - z.re, this.im - z.im)
            endmethod
           
            method mul takes thistype z returns thistype
                return create(this.re*z.re - this.im*z.im, this.re*z.im + this.im*z.re)
            endmethod
           
            method conj takes nothing returns thistype
                return create(this.re, -this.im)
            endmethod
           
            method div takes thistype z returns thistype
                local real dv = z.re*z.re + z.im*z.im
                if (dv!=0) then
                    return create((this.re*z.re + this.im*z.im)/dv, (this.im*z.re - this.re*z.im)/dv)
                endif
                debug call BJDebugMsg("thistype Error : Divide by 0!! Crashing thread")
                return 1/0
            endmethod
           
            method operator abs takes nothing returns real
                return SquareRoot(this.re*this.re + this.im*this.im)
            endmethod
           
            method operator arg takes nothing returns real
                return Atan2(this.im, this.re)
            endmethod
           
            method operator abs= takes real value returns nothing
                local real angle = Atan2(this.im, this.re)
                set this.re = value*Cos(angle)
                set this.im = value*Sin(angle)
            endmethod

            method operator arg= takes real value returns nothing
                local real abs = SquareRoot(this.re*this.re + this.im*this.im)
                set this.re = abs*Cos(value)
                set this.im = abs*Sin(value)
            endmethod
           
            method toString takes nothing returns string
                if (this.im >= 0) then
                    return R2S(this.re)+"+"+R2S(this.im)+"i"
                endif
                return R2S(this.re)+R2S(this.im)+"i"
            endmethod
           
            method toStringPolar takes nothing returns string
                return R2S(this.abs)+"*e^("+R2S(this.arg)+"*i)"
            endmethod
           
            method ln takes nothing returns thistype
                if this.re == 0 and this.im == 0 then
                    debug call BJDebugMsg("thistype Error : Attempt to do something bad like ln(0) !! Crashing thread")
                    return 1/0
                endif
                return create(internLn(this.abs), this.arg)
            endmethod
           
            method exp takes nothing returns thistype
                return create(Pow(E, this.re)*Cos(this.im), Pow(E, this.re)*Sin(this.im))
            endmethod
           
            method pow takes thistype z returns thistype
                return this.ln().mul(z).exp()
            endmethod
           
            method sqrt takes nothing returns thistype
                local thistype c = thistype.allocate()
                if (this.im == 0) then
                    if (this.re > 0) then
                        set c.re = SquareRoot(this.re)
                        set c.im = 0
                    else
                        set c.re = 0
                        set c.im = SquareRoot(-this.re)
                    endif
                else
                    set c.re = SquareRoot((this.re + this.abs)/2)
                    set c.im = SquareRoot((this.abs - this.re)/2)
                    if this.im < 0 then
                        set c.im = -c.im
                    endif
                endif
                return c
            endmethod
           
            method equals takes thistype z returns boolean
                return this.re==z.re and this.im==z.im
            endmethod
        endstruct
    endlibrary


    Feel free to use it if you want to do complex geometry in your map or something.
    You can use it for example to create some fractals like Mandelbrot's or Julia's.
     
    Last edited: Jun 22, 2015
  2. T. D. W.

    T. D. W.

    Joined:
    Jul 31, 2012
    Messages:
    1,505
    Resources:
    5
    Spells:
    5
    Resources:
    5
    Complexe Numbers :vw_love:
    k, i'll see this after i learn it this year at school, lol

    besides, i was thinking of something like that in WE xD
     
  3. Dr Super Good

    Dr Super Good

    Spell Reviewer

    Joined:
    Jan 18, 2005
    Messages:
    25,588
    Resources:
    3
    Maps:
    1
    Spells:
    2
    Resources:
    3
    Complex numbers could probably be implemented as some kind of vector and matrix system. after all, they basically act like a 2D vector with x being real and y being imaginary.

    This also raises an interesting argument of what about multiple dimensions of complexity? I mean in theory you could have a constant like i/j that acts exactly like i/j with the real values but also with i/j since it is perpendicular to both. However this is getting kind of off topic.

    You are missing important operators. Such as the exponential of a complex number (a rotational operation), conversion to polar form (the angle). Simple mathematical operators between complex numbers (+, -, /, * etc) are also missing.
     
  4. Malhorne

    Malhorne

    Joined:
    Sep 14, 2012
    Messages:
    2,330
    Resources:
    6
    Spells:
    4
    Tutorials:
    1
    JASS:
    1
    Resources:
    6
    Ah yes sorry xD
    I did this in english class when I was bored but I forgot many operators you're right :)
    (Besides I searched what could be useful xD)

    I might do quaternions too later (but dunno if someone will use it a day ^^)

    Anyway thanks for the replay DSG it is honor for me that you came comment this !
     
  5. Malhorne

    Malhorne

    Joined:
    Sep 14, 2012
    Messages:
    2,330
    Resources:
    6
    Spells:
    4
    Tutorials:
    1
    JASS:
    1
    Resources:
    6
    Updated :)
    Dunno if divide is good or not....
    I didn't make many test on it. But seems good from what I saw.
     
  6. Dr Super Good

    Dr Super Good

    Spell Reviewer

    Joined:
    Jan 18, 2005
    Messages:
    25,588
    Resources:
    3
    Maps:
    1
    Spells:
    2
    Resources:
    3
    Code (vJASS):

            //It will put the result on the first complex
             static method mul takes thistype z, thistype z2 returns nothing
                 local real temp = z.re*z2.im + z.im*z2.re
                 set z.re = z.re*z2.re - z.im*z2.im
                 set z.im = temp
             endmethod
     

    Why is a local declared when the value produced is only ever used once?
     
  7. Malhorne

    Malhorne

    Joined:
    Sep 14, 2012
    Messages:
    2,330
    Resources:
    6
    Spells:
    4
    Tutorials:
    1
    JASS:
    1
    Resources:
    6
    The problem is that I loose the value of z.re during the calculus
     
  8. Dr Super Good

    Dr Super Good

    Spell Reviewer

    Joined:
    Jan 18, 2005
    Messages:
    25,588
    Resources:
    3
    Maps:
    1
    Spells:
    2
    Resources:
    3
    Oh yeh intermediate values, did not see that one. I have been using matlab too much recently... In any case "nim" would probably be a better name for it than temp since it is shorter and more readable (new im).

    You are still lacking a natural exponential operation that takes a complex number and returns a complex number.
     
  9. Malhorne

    Malhorne

    Joined:
    Sep 14, 2012
    Messages:
    2,330
    Resources:
    6
    Spells:
    4
    Tutorials:
    1
    JASS:
    1
    Resources:
    6
    I don't see how to programm this well to create a good API for natural exponential :/
    Because it is only : abs(z)*e^(i*angle(z)) :/
     
  10. Dr Super Good

    Dr Super Good

    Spell Reviewer

    Joined:
    Jan 18, 2005
    Messages:
    25,588
    Resources:
    3
    Maps:
    1
    Spells:
    2
    Resources:
    3
    Not entirely true.

    z = e^ln(z)
    as such
    abs(z) * e ^ (i * angle(z)) = e ^ ln(abs(z)) * e ^ (i * angle(z))

    Which if you simplify... because e ^ a * e ^ b = e ^ (a + b)
    = e ^ (ln(abs(z)) + i * angle(z))

    ln(abs(z)) + i * angle(z) is a complex number with both a real part (ln(abs(z))) and imaginary part (angle(z)).

    As such polar form can be represented as a single complex number instead of 2 separate angle and magnitude values. This complex number could then be represented as another polar form complex number and repeated to form an infinitely deep series. No idea why one would ever do that though.

    You may be thinking "How is this possible?". Well here is the proof that what I said makes total sense. Putting (ln(10) + i * pi) through the natural exponential function yields -10 as it is a magnitude of 10 at 180 degrees.

    As such you need a natural exponential function that takes a complex number and returns a complex number.
     
  11. Malhorne

    Malhorne

    Joined:
    Sep 14, 2012
    Messages:
    2,330
    Resources:
    6
    Spells:
    4
    Tutorials:
    1
    JASS:
    1
    Resources:
    6
    Oh my god :eek:
    Thanks for telling this
    I didn't know this ....
    I didn't really understand completely since I'm french :s
     
  12. Malhorne

    Malhorne

    Joined:
    Sep 14, 2012
    Messages:
    2,330
    Resources:
    6
    Spells:
    4
    Tutorials:
    1
    JASS:
    1
    Resources:
    6
    Added complex exponential and logarithm
     
  13. edo494

    edo494

    Joined:
    Apr 16, 2012
    Messages:
    3,846
    Resources:
    5
    Spells:
    1
    JASS:
    4
    Resources:
    5
    useless decimal precision on e, Jass uses floating points, which have precision of 7-9 decimal points
     
  14. Malhorne

    Malhorne

    Joined:
    Sep 14, 2012
    Messages:
    2,330
    Resources:
    6
    Spells:
    4
    Tutorials:
    1
    JASS:
    1
    Resources:
    6
    I was trolling on the decimal precision dude ^^'
    I just know them by heart that's why I wanted to troll a bit since it doesn't slow the code or nothing it doesn't hurt at all....
     
  15. chobibo

    chobibo

    Joined:
    Sep 24, 2005
    Messages:
    2,701
    Resources:
    0
    Resources:
    0
    [​IMG] Trolling on your own resource?
     
  16. Malhorne

    Malhorne

    Joined:
    Sep 14, 2012
    Messages:
    2,330
    Resources:
    6
    Spells:
    4
    Tutorials:
    1
    JASS:
    1
    Resources:
    6
    Ahah yeah I can add a comment to those but I really wanted to put them ^^
     
  17. Nestharus

    Nestharus

    Joined:
    Jul 10, 2007
    Messages:
    6,146
    Resources:
    8
    Spells:
    3
    Tutorials:
    4
    JASS:
    1
    Resources:
    8
    Add some documentation
     
  18. Malhorne

    Malhorne

    Joined:
    Sep 14, 2012
    Messages:
    2,330
    Resources:
    6
    Spells:
    4
    Tutorials:
    1
    JASS:
    1
    Resources:
    6
    Ah yes sorry ^^'
    I forgot this since I added some asm style methods xD

    I'll put a doc with the next update which will support z1^z2 and x^z where x real and z1, z2 complexs.
     
  19. Malhorne

    Malhorne

    Joined:
    Sep 14, 2012
    Messages:
    2,330
    Resources:
    6
    Spells:
    4
    Tutorials:
    1
    JASS:
    1
    Resources:
    6
    Updated (added the doc)
     
  20. edo494

    edo494

    Joined:
    Apr 16, 2012
    Messages:
    3,846
    Resources:
    5
    Spells:
    1
    JASS:
    4
    Resources:
    5
    Code (vJASS):


                if z2.abs == 0 then
                    call BJDebugMsg("Complex library -> Attempt to divide by 0 !! Crashing the thread")
                    return 0
                endif
     


    I would prefer:

    Code (vJASS):


                if z2.abs == 0 then
                    debug call BJDebugMsg("thistype: Attempt to divide by 0 !! Crashing the thread")
                    return 1/0
                endif
     


    also you are saying crashing the thread, but you only return, if you wanted to crash the thread, you actually have to divide by 0, or run infinite loop until OP limit is hit

    Also thistype, no matter if in string or not, will always result in the name of the struct being used(if it is private, it will also include the Private part of the name)