Results 1 to 6 of 6

Thread: Speed?

  1. #1

    Thread Starter
    Frenzied Member yrwyddfa's Avatar
    Join Date
    Aug 2001
    Location
    England
    Posts
    1,253

    Speed?

    Interesting, this.

    I need to get more speed out of some date mathematics. The following is a well known algorithm (so the way it works, is not important.

    VB Code:
    1. Public Function Julian(y As Long, m As Long, d As Long) As Long
    2.  
    3.     Dim jy As Long
    4.     Dim ja As Long
    5.     Dim jm As Long
    6.     Dim intgr As Long
    7.    
    8.     If (m > 2) Then
    9.         jy = y
    10.         jm = m + 1
    11.     Else
    12.         jy = y - 1
    13.         jm = m + 13
    14.     End If
    15.    
    16.     intgr = Fix(Fix(365.25 * jy) + Fix(30.6001 * jm) + d + 1720995)
    17.    
    18.     ja = Fix(0.01 * jy)
    19.     intgr = intgr + 2 - ja + Fix(0.25 * ja)
    20.    
    21.     CGreg2Jul = intgr
    22.    
    23. End Function

    So, ignoring the subtleties of the 'FIX' function, I rewrote it in C and housed it in a DLL as:

    VB Code:
    1. int _stdcall Julian (int y, int m, int d)
    2. {
    3.  
    4.     int jy,ja,jm,intgr;
    5.  
    6.  
    7.     if (m>2)
    8.     {
    9.         jy=y;
    10.         jm=m+1;
    11.     }
    12.     else
    13.     {
    14.         jy=y-1;
    15.         jm=m+13;
    16.     };
    17.  
    18.     ja = int(0.01*jy);
    19.     intgr = int(int(365.25*jy)+int(30.6001*jm)+d+1720995);
    20.     intgr = intgr+2-ja+int(0.25*ja);
    21.  
    22.     return intgr;
    23. };

    I was hoping, by default, for a marvellous jump in speed, here. But I didn't get it. I tried two things:

    (i) Compiled, and calling the function using a Declare stmt = virtually identical speed. On some runs the C DLL perfoms around 20% better
    (ii) Through a typelib . . .

    VB Code:
    1. [
    2.     uuid(ad534fb5-794a-11da-8cd6-0800200c9a66),
    3.     version(1.0),
    4.     helpstring("Date Win32 Library")
    5. ]
    6. library Date
    7. {
    8.  
    9.     [dllname("Date.dll")]
    10.  
    11.     module Date_API
    12.     {
    13.  
    14.         [entry("Julian")]
    15.         long Julian ([in] int y,[in] int m,[in] int d);
    16.  
    17.     }
    18. }

    . . . which consistently gets around 20% improvement in speed, but sometimes jumps to about 40% improvement.

    I was hoping for >100% improvement in speed.

    Just goes to show, that the architecture (ie how it's put together) in some cases is much more important than the raw code.

    Any thoughts?
    "As far as the laws of mathematics refer to reality, they are not certain; and as far as they are certain, they do not refer to reality." - Albert Einstein

    It's turtles! And it's all the way down

  2. #2
    Super Moderator si_the_geek's Avatar
    Join Date
    Jul 2002
    Location
    Bristol, UK
    Posts
    41,974

    Re: Speed?

    How is this code being called, and how many times?

    I presume from what you have said that it is in a "large" loop, being called multiple times. Is this right?


    If that is the case, one way to speed it up noticably would be to put the code "inline", rather than calling the function each time - as the time to call a sub/function is actually quite large.


    Another thing, depending on the range of values (and the number of times it is run) you may be able to get a speed boost by pre-calculating the results of the Fix() function, and storing these values in an array. This would replace a function call (admittedly an inbuilt one) and a floating point calculation with a comparatively simple array access (I have noticed decent gains on this for a simple "Square" operation).

    For example: Presumably the values for JM are limited to the range 3-14, so a simple array could be made like this:
    VB Code:
    1. Dim lngCount as Long
    2. Dim lngFixJM(14) as Long
    3.   For lngCount = 3 to 14
    4.     lngFixJM(lngCount) = Fix(30.6001 * lngCount)
    5.   Next lngCount
    Then in the code instead of using "Fix(30.6001 * jm)", you can use "lngFixJM(jm)".

  3. #3

    Thread Starter
    Frenzied Member yrwyddfa's Avatar
    Join Date
    Aug 2001
    Location
    England
    Posts
    1,253

    Re: Speed?

    Quote Originally Posted by si_the_geek
    How is this code being called, and how many times?

    I presume from what you have said that it is in a "large" loop, being called multiple times. Is this right?


    If that is the case, one way to speed it up noticably would be to put the code "inline", rather than calling the function each time - as the time to call a sub/function is actually quite large.


    Another thing, depending on the range of values (and the number of times it is run) you may be able to get a speed boost by pre-calculating the results of the Fix() function, and storing these values in an array. This would replace a function call (admittedly an inbuilt one) and a floating point calculation with a comparatively simple array access (I have noticed decent gains on this for a simple "Square" operation).

    For example: Presumably the values for JM are limited to the range 3-14, so a simple array could be made like this:
    VB Code:
    1. Dim lngCount as Long
    2. Dim lngFixJM(14) as Long
    3.   For lngCount = 3 to 14
    4.     lngFixJM(lngCount) = Fix(30.6001 * lngCount)
    5.   Next lngCount
    Then in the code instead of using "Fix(30.6001 * jm)", you can use "lngFixJM(jm)".
    Nice idea - I'll give it a go . . .
    "As far as the laws of mathematics refer to reality, they are not certain; and as far as they are certain, they do not refer to reality." - Albert Einstein

    It's turtles! And it's all the way down

  4. #4
    VB6, XHTML & CSS hobbyist Merri's Avatar
    Join Date
    Oct 2002
    Location
    Finland
    Posts
    6,654

    Re: Speed?

    There is also one unrequired Fix:

    intgr = Fix(Fix(365.25 * jy) + Fix(30.6001 * jm) + d + 1720995)

    There is no need to do the everything wrapping Fix as the combined value is already non-floating point.

  5. #5
    type Woss is new Grumpy; wossname's Avatar
    Join Date
    Aug 2002
    Location
    #!/bin/bash
    Posts
    5,682

    Re: Speed?

    That looks like a binary search to me, since binary searching is logarithmic in terms of speed of execution (doubleing the search space only increases time by a small amount), expecting a 100% increase seems a little ambitious.

    Also I don't think you need this outer cast...

    Code:
    intgr = int(int(365.25*jy)+int(30.6001*jm)+d+1720995);
    I don't live here any more.

  6. #6

    Thread Starter
    Frenzied Member yrwyddfa's Avatar
    Join Date
    Aug 2001
    Location
    England
    Posts
    1,253

    Re: Speed?

    I don't see where the binary search idea came from

    Anyway. I rewrote the algorithm, in C, as:

    VB Code:
    1. double _stdcall CJulian(GREGORIAN *Value)
    2. {
    3.  
    4.     long        d,m,y;
    5.     GREGORIAN   Ret;
    6.  
    7.     Ret = *Value;
    8.     d=Ret.Day;
    9.     m=Ret.Month;
    10.     y=Ret.Year;
    11.  
    12.     return ( 1461 * ( y + 4800 + ( m - 14 ) / 12 ) ) / 4 +
    13.             (367 * ( m - 2 - 12 * ( ( m - 14 ) / 12 ) ) ) / 12 -
    14.             ( 3 * ( ( y + 4900 + ( m - 14 ) / 12 ) / 100 ) ) / 4 +
    15.             d - 32075.5;
    16. };

    There are some opportunities for further optimisation, but at this stage, it runs fast enough.

    One thing you C boys might be able to help me out with is this. I need to extract the integer, and the floating point of the double. Currently, I do it using the modf function in this lot:

    VB Code:
    1. typedef struct {
    2.     double Degrees;
    3.     double Minutes;
    4.     double Seconds;
    5. } SEXAGESIMAL;
    6.  
    7. // Converts decimal value to Sexagesimal value
    8. //
    9. SEXAGESIMAL _stdcall CSexagesimal (double Value)
    10. {
    11.  
    12.     double      Whole,Fraction;
    13.     SEXAGESIMAL Ret;
    14.  
    15.     Fraction=modf(Value,&Whole);
    16.     Ret.Degrees=Whole;
    17.  
    18.     Fraction=modf(Fraction*60,&Whole);
    19.     Ret.Minutes=Whole;
    20.  
    21.     Ret.Seconds=Fraction*60;
    22.  
    23.     return Ret;
    24. };

    Now this routine is critical to what I'm doing. So if there's a real nice inline assembly procedure to replace the modf function, and you'd be willing to share it, I would be eternally grateful. Might even buy you a virtual pint!
    "As far as the laws of mathematics refer to reality, they are not certain; and as far as they are certain, they do not refer to reality." - Albert Einstein

    It's turtles! And it's all the way down

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width