|
-
Mar 1st, 2006, 09:24 AM
#1
Thread Starter
Frenzied Member
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:
Public Function Julian(y As Long, m As Long, d As Long) As Long
Dim jy As Long
Dim ja As Long
Dim jm As Long
Dim intgr As Long
If (m > 2) Then
jy = y
jm = m + 1
Else
jy = y - 1
jm = m + 13
End If
intgr = Fix(Fix(365.25 * jy) + Fix(30.6001 * jm) + d + 1720995)
ja = Fix(0.01 * jy)
intgr = intgr + 2 - ja + Fix(0.25 * ja)
CGreg2Jul = intgr
End Function
So, ignoring the subtleties of the 'FIX' function, I rewrote it in C and housed it in a DLL as:
VB Code:
int _stdcall Julian (int y, int m, int d)
{
int jy,ja,jm,intgr;
if (m>2)
{
jy=y;
jm=m+1;
}
else
{
jy=y-1;
jm=m+13;
};
ja = int(0.01*jy);
intgr = int(int(365.25*jy)+int(30.6001*jm)+d+1720995);
intgr = intgr+2-ja+int(0.25*ja);
return intgr;
};
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:
[
uuid(ad534fb5-794a-11da-8cd6-0800200c9a66),
version(1.0),
helpstring("Date Win32 Library")
]
library Date
{
[dllname("Date.dll")]
module Date_API
{
[entry("Julian")]
long Julian ([in] int y,[in] int m,[in] int d);
}
}
. . . 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
-
Mar 1st, 2006, 06:43 PM
#2
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:
Dim lngCount as Long
Dim lngFixJM(14) as Long
For lngCount = 3 to 14
lngFixJM(lngCount) = Fix(30.6001 * lngCount)
Next lngCount
Then in the code instead of using "Fix(30.6001 * jm)", you can use "lngFixJM(jm)".
-
Mar 2nd, 2006, 03:21 AM
#3
Thread Starter
Frenzied Member
Re: Speed?
 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:
Dim lngCount as Long
Dim lngFixJM(14) as Long
For lngCount = 3 to 14
lngFixJM(lngCount) = Fix(30.6001 * lngCount)
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
-
Mar 3rd, 2006, 03:44 AM
#4
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.
-
Mar 13th, 2006, 07:38 AM
#5
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.
-
Mar 13th, 2006, 10:11 AM
#6
Thread Starter
Frenzied Member
Re: Speed?
I don't see where the binary search idea came from
Anyway. I rewrote the algorithm, in C, as:
VB Code:
double _stdcall CJulian(GREGORIAN *Value)
{
long d,m,y;
GREGORIAN Ret;
Ret = *Value;
d=Ret.Day;
m=Ret.Month;
y=Ret.Year;
return ( 1461 * ( y + 4800 + ( m - 14 ) / 12 ) ) / 4 +
(367 * ( m - 2 - 12 * ( ( m - 14 ) / 12 ) ) ) / 12 -
( 3 * ( ( y + 4900 + ( m - 14 ) / 12 ) / 100 ) ) / 4 +
d - 32075.5;
};
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:
typedef struct {
double Degrees;
double Minutes;
double Seconds;
} SEXAGESIMAL;
// Converts decimal value to Sexagesimal value
//
SEXAGESIMAL _stdcall CSexagesimal (double Value)
{
double Whole,Fraction;
SEXAGESIMAL Ret;
Fraction=modf(Value,&Whole);
Ret.Degrees=Whole;
Fraction=modf(Fraction*60,&Whole);
Ret.Minutes=Whole;
Ret.Seconds=Fraction*60;
return Ret;
};
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
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|