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.

Fractions

Discussion in 'Graveyard' started by Bribe, Oct 3, 2010.

  1. Bribe

    Bribe

    Joined:
    Sep 26, 2009
    Messages:
    8,059
    Resources:
    25
    Maps:
    3
    Spells:
    10
    Tutorials:
    3
    JASS:
    9
    Resources:
    25
    Code (vJASS):

    library Fractions
    //===========================================================================
    // Created by Bribe. Largely based on the "fractions" module used in Python.
    // It allows you to do things like:
    //
    // call Fraction(1, 2).add(Fraction(3, 2)).print(5.00)
    //
    // Which displays the message "Fraction(2, 1)" for 5 seconds. "Fractions"
    // allows you to do math without the imprecision of real numbers, and auto-
    // matically simplifies results ((3, 12) becomes (1, 4)).
    //
       
       
        //=======================================================================
        // Returns 0.14 from 3.14. Its purpose is to get the right-side of the
        // decimal point of a real number.
        //
        function GetRemainder takes real r returns real
            return r - R2I(r)
        endfunction

        //=======================================================================
        // Returns 2 for 10; 4 for 1000. Its purpose is to find out how many
        // digits are in a given integer.
        //
        function CountDigits takes integer i returns integer
            return StringLength(I2S(i))
        endfunction

        //=======================================================================
        // Turns 0.15 (with p == 2) into 15. Its purpose is to swap imprecise
        // real numbers into workable integers.
        //
        function PromoteReal takes real r, integer p returns integer
            return R2I(r * Pow(10, p))
        endfunction

        //=======================================================================
        // Turns 15 into 0.15; 165 into 0.165. Its purpose is to reverse the
        // effects of PromoteReal.
        //
        function DemoteInteger takes integer i returns real
            return i / Pow(10, CountDigits(i))
        endfunction

        //=======================================================================
        // Returns true for 1.00, false for 3.14. Its purpose is to determine
        // if a real number is also a rational number.
        //
        function IsRational takes real r returns boolean
            return r * 10000 == 0
        endfunction

        //=======================================================================
        // Rounds 1.2 to 1, 1.7 to 2. Its purpose is to not simply truncate reals
        // vith R2I, but to also round the number if its remainder is higher than
        // 0.50.
        //
        function Real2Int takes real r returns integer
            if r > 0 then
                return R2I(r + 0.50)
            endif
            return R2I(r - 0.50)
        endfunction
       
        //=======================================================================
        // Finds the greatest-common-denominator for a fraction to be simplified
        // into.
        //
        public function GCD takes integer a, integer b returns integer
            local integer a2
            loop
                exitwhen b == 0
                set a2= a
                set a = b
                set b = ModuloInteger(a2, b)
            endloop
            return a
        endfunction
       
       
        struct fraction
           
            readonly integer num // numerator
            readonly integer den // denominator
           
           
            //===================================================================
            // f.reset(1, 2) resets the numerator and denominator to whatever you
            // want.
            //
            method reset takes integer a, integer b returns thistype
                local integer d = GCD(a, b)
                if (d != 0) then
                    set num = a / d
                    set den = b / d
                else
                    set num = 0
                    set den = 1
                endif
                return this
            endmethod
           
            //===================================================================
            // f = fraction.create(1, 2) creates a new fraction instance with the
            // first value as the numerator, the second as the denominator.
            //
            static method create takes integer num, integer den returns thistype
                return thistype.allocate().reset(num, den)
            endmethod
           
            //===================================================================
            // f.product() returns 0.50. This is useful when you need a real num-
            // ber as a parameter.
            //
            method product takes nothing returns real
                return (num + 0.) / den
            endmethod
           
            //===================================================================
            // f2 = f.copy() returns a new fraction instance with the same num-
            // erator and denominator as f.
            //
            method copy takes nothing returns thistype
                return thistype.create(num, den)
            endmethod
           
            //===================================================================
            // Fraction(1, 3).add(Fraction(1, 3)) makes Fraction(2, 3).
            //
            method add takes thistype f returns thistype
                return this.reset((this.num * f.den) + (this.den * f.num), (this.den * f.den))
            endmethod
           
            //===================================================================
            // Fraction(2, 3).subtract(Fraction(1, 3)) makes Fraction(1, 3).
            //
            method subtract takes thistype f returns thistype
                return this.reset((this.num * f.den) - (this.den * f.num), (this.den * f.den))
            endmethod
           
            //===================================================================
            // Fraction(1, 2).multiply(Fraction(2, 3)) makes Fraction(1, 3).
            //
            method multiply takes thistype f returns thistype
                return this.reset(this.num * f.num, this.den * f.den)
            endmethod
           
            //===================================================================
            // Fraction(3, 4).divide(Fraction(4, 5)) makes Fraction(15, 16).
            //
            method divide takes thistype f returns thistype
                return this.reset(this.num * f.den, this.den * f.num)
            endmethod
           
            //===================================================================
            // f.eq(f2) returns true if the numerator and denominator are the
            // same for both f and f2.
            //
            method eq takes thistype f returns boolean
                return this.num == f.num and this.den == f.den
            endmethod
           
            //===================================================================
            // f.gt(f2) returns true if f is greater than f2.
            //
            method gt takes thistype f returns boolean
                return this.num * f.den > f.num * this.den
            endmethod
           
            //===================================================================
            // f.lt(f2) returns true if f is less than f2.
            //
            method lt takes thistype f returns boolean
                return this.num * f.den < f.num * this.den
            endmethod
           
            //===================================================================
            // f.print(5.00) displays Fraction(1, 2) for 5 seconds, useful for
            // debugging or for playing around with some math.
            //
            method print takes real duration returns nothing
                call DisplayTimedTextToPlayer(GetLocalPlayer(), 0.00, 0.00, duration, "Fraction(" + I2S(num) + ", " + I2S(den) + ")")
            endmethod
           
            //===================================================================
            // Turns "10" into Fraction(10, 1). Easy way to convert an integer to
            // a fraction.
            //
            static method fromint takes integer i returns thistype
                return thistype.create(i, 1)
            endmethod
           
            //===================================================================
            // Turns "0.5" (with p==1) into Fraction(1, 2). Easy way to convert a
            // real number into a fraction. "p" is the amount of precision to
            // check on the right side of the floating point. A low "p" produces
            // more simplified fractions than a high "p".
            //
            static method fromreal takes real r, integer p returns thistype
                set p = R2I(Pow(10, p))
                return thistype.create(R2I(r * p), p)
            endmethod
           
           
        endstruct
       
       
        globals
            private timer g_timer = CreateTimer()
            private integer g_size = 0
            private fraction array a_list
        endglobals
       
        //=======================================================================
        // Auto-destroys fraction instances created with "Fraction(1, 2)".
        //
        private function Recycle takes nothing returns nothing
            local integer i = 0
            loop
                call a_list[i].destroy()
                set i = i + 1
                exitwhen i == g_size
            endloop
            set g_size = 0
        endfunction
       
        //=======================================================================
        // Returns a temporary fraction, great for numers you only need for a
        // single instance. f.add(Fraction(1, 2)) is an ideal way to use it.
        //
        function Fraction takes integer num, integer den returns fraction
            local fraction f = fraction.create(num, den)
            set a_list[g_size] = f
            set g_size = g_size + 1
            call TimerStart(g_timer, 0.00, false, function Recycle)
            return f
        endfunction
       
       
    endlibrary
     
     
    Last edited: Nov 8, 2010
  2. watermelon_1234

    watermelon_1234

    Joined:
    Nov 18, 2007
    Messages:
    1,066
    Resources:
    10
    Spells:
    9
    JASS:
    1
    Resources:
    10
    I'm not sure if there's much use for this, though rounding reals is pretty nice.

    Is
    ZeroShift(10)
    better than just
    Pow(10,10)
    ?
    I think that ZeroShift would get slower depending on how high the power is.

    I think
    GetRemainder
    should return an absolute value.
     
  3. Adiktuz

    Adiktuz

    Joined:
    Oct 16, 2008
    Messages:
    9,674
    Resources:
    23
    Models:
    2
    Packs:
    1
    Maps:
    1
    Spells:
    16
    Tutorials:
    1
    JASS:
    2
    Resources:
    23
    wouldn't this return -.14? since it will be 3 - 3.14
    Code (vJASS):

     //=======================================================================
        // Returns 0.14 from 3.14.
        //
        function GetRemainder takes real r returns real
            return R2I(r) - r
        endfunction
     
     
  4. Bribe

    Bribe

    Joined:
    Sep 26, 2009
    Messages:
    8,059
    Resources:
    25
    Maps:
    3
    Spells:
    10
    Tutorials:
    3
    JASS:
    9
    Resources:
    25
    Useage -> this is mostly for the "fractions" struct, which I have yet to write a description for and is still a bit incomplete.

    Pow(10,10) still returns a real value, and reals are calculated poorly no matter how you slice it. ZeroShift keeps things integer-based, which is one of the key goals of this library.
     
  5. Nestharus

    Nestharus

    Joined:
    Jul 10, 2007
    Messages:
    6,146
    Resources:
    8
    Spells:
    3
    Tutorials:
    4
    JASS:
    1
    Resources:
    8
    I think you should go with
    Pow
    also : |..

    furthermore, the errors in reals come from the rounding >.<. If you keep everything in local scope, it won't round until it gets returned or goes into a global as long as you do things in intervals of 2^32/2.

    The above was from my own testing. Keep in mind the above only works because wc3 engine treats reals as strings at that point : |... this means the operations are insanely slow.
     
  6. Bribe

    Bribe

    Joined:
    Sep 26, 2009
    Messages:
    8,059
    Resources:
    25
    Maps:
    3
    Spells:
    10
    Tutorials:
    3
    JASS:
    9
    Resources:
    25
    I am particularly concerned about whether a designated integer-variable syntaxes properly as a parameter in Pow. Pow(10, i), whereas i is an integer...
     
  7. Nestharus

    Nestharus

    Joined:
    Jul 10, 2007
    Messages:
    6,146
    Resources:
    8
    Spells:
    3
    Tutorials:
    4
    JASS:
    1
    Resources:
    8
    Let your worries be released; it does.
     
  8. xD.Schurke

    xD.Schurke

    Joined:
    Feb 22, 2006
    Messages:
    948
    Resources:
    5
    Maps:
    1
    Spells:
    4
    Resources:
    5
    your real to int can be done shorter:

    Code (vJASS):

    function RealToInt takes real r returns integer
         return R2I(r+0.5)
    endfunction
     
  9. YourNameHere

    YourNameHere

    Joined:
    Apr 29, 2007
    Messages:
    745
    Resources:
    4
    Maps:
    1
    Spells:
    2
    JASS:
    1
    Resources:
    4
    Wrong. What about negative values?
    Code (vJASS):
    function RealToInt takes real r returns integer
        if r > 0 then
            return R2I(r+.5)
        endif
        return R2I(r-.5)
    endfunction
     
  10. azlier

    azlier

    Joined:
    Oct 3, 2008
    Messages:
    354
    Resources:
    4
    JASS:
    4
    Resources:
    4
    It depends on the type of rounding you want, really. But yeah, that's the one for the round function most people have in mind.
     
  11. xD.Schurke

    xD.Schurke

    Joined:
    Feb 22, 2006
    Messages:
    948
    Resources:
    5
    Maps:
    1
    Spells:
    4
    Resources:
    5
    true, only thought about positive values ;)
     
  12. Bribe

    Bribe

    Joined:
    Sep 26, 2009
    Messages:
    8,059
    Resources:
    25
    Maps:
    3
    Spells:
    10
    Tutorials:
    3
    JASS:
    9
    Resources:
    25
    Thank you all for the suggestions. I have finally found the time to add a description to each function/method so someone can follow my thinking.
     
  13. PurgeandFire

    PurgeandFire

    Code Moderator

    Joined:
    Nov 11, 2006
    Messages:
    7,426
    Resources:
    18
    Icons:
    1
    Spells:
    4
    Tutorials:
    9
    JASS:
    4
    Resources:
    18
    Code (vJASS):
        function Real2Int takes real r returns integer
            if r > 0 then
                return R2I(r + 0.50)
            else
                return R2I(r - 0.50)
            endif
        endfunction


    -->

    Code (vJASS):
    function Real2Int takes real r returns integer
        if r > 0 then
            return R2I(r+.5)
        endif
        return R2I(r-.5)
    endfunction


    As yournamehere posted. If I remember correctly, it either won't parse or it'll just not work if you don't have a return at the end. ;P
     
  14. Bribe

    Bribe

    Joined:
    Sep 26, 2009
    Messages:
    8,059
    Resources:
    25
    Maps:
    3
    Spells:
    10
    Tutorials:
    3
    JASS:
    9
    Resources:
    25
    It syntaxes correctly, try it for yourself :)

    That's one of the few intelligent things about war3's syntax checker: it knows that the "else" block is valid for a final return statement.
     
  15. YourNameHere

    YourNameHere

    Joined:
    Apr 29, 2007
    Messages:
    745
    Resources:
    4
    Maps:
    1
    Spells:
    2
    JASS:
    1
    Resources:
    4
    It's better performance-wise without an else. Not that it would make any difference since JASS is pretty slow anyway :D.
     
  16. Bribe

    Bribe

    Joined:
    Sep 26, 2009
    Messages:
    8,059
    Resources:
    25
    Maps:
    3
    Spells:
    10
    Tutorials:
    3
    JASS:
    9
    Resources:
    25
    An 'else' as a performance hit? That would have to be the smallest performance hit in recorded history.

    I choose readability.
     
  17. azlier

    azlier

    Joined:
    Oct 3, 2008
    Messages:
    354
    Resources:
    4
    JASS:
    4
    Resources:
    4
    No. Do not use else.

    Especially with some older patch versions, not having the return on the last line can be buggy. With a chance of bugs. And if anything it detracts from readability. I'm telling you this for your own health.

    And mine.
     
  18. xD.Schurke

    xD.Schurke

    Joined:
    Feb 22, 2006
    Messages:
    948
    Resources:
    5
    Maps:
    1
    Spells:
    4
    Resources:
    5
    no it won't bug, since a boolean only can be true/false so one of those two if cases will be called :O
     
  19. Bribe

    Bribe

    Joined:
    Sep 26, 2009
    Messages:
    8,059
    Resources:
    25
    Maps:
    3
    Spells:
    10
    Tutorials:
    3
    JASS:
    9
    Resources:
    25
    Aye, as I have not toyed with previous versions of war3 JASS, I cannot argue the chance it may have bugged in the past. Fixed for everyone's benefit.
     
  20. Laiev

    Laiev

    Joined:
    Oct 11, 2008
    Messages:
    273
    Resources:
    1
    Template:
    1
    Resources:
    1
    Code (vJASS):
    function IsRational takes real r returns boolean
            return S2I(SubString(R2SW(r - R2I(r), 0, 5)), 2, 6) == 0
        endfunction


    >>

    Code (vJASS):
    function IsRational takes real r returns boolean
            return S2I(SubString(R2SW(r - R2I(r), 0, 5), 2, 6)) == 0
        endfunction