0

I have the following line of code:

SomeDouble= constant1/ ((a * b) * (Math.Asin((c- a) / (a * d)) + constant2))

The two constants are different and calculated out of the loops, a - d are variables that change each time.

And on the face of it it's pretty fast 0.002ms on average (47,633.588s for 26,508,249 hits). The issue I'm having is it's going to be called billions of times, literally around 20 billion hits each time the software is run. So if I can cut this down to 0.001ms the difference will be substantial. I know that dividing is a very slow process and I expect calculating arcsin is also slow. If anyone can suggest if there's a faster method of calculating arcsin or any other help in speeding up this line of code that would be great. On a side note any advice on whether vb.net's built in math functions are optimised for speed would be great I've noticed that math.sqrt(somevalue) is quicker than (somevalue)^0.5.

Thanks in advanced!

FraserOfSmeg
  • 1,128
  • 2
  • 23
  • 41
  • 1
    How much accuracy do you need? – recursive May 24 '13 at 17:11
  • Good question. The higher the accuracy the better. That being said if there's a way that I could increase speed at the cost of accuracy I would defiantly like to hear it so I can consider it. I've not specifically looked at the required accuracy of this variable (somedouble) I do have some accuracy requirements further down the code, which I'll go though now and see what the cost of losing accuracy here is. – FraserOfSmeg May 24 '13 at 17:15
  • Do any of the variables stay the same between calculations? Or change in predictable ways? – recursive May 24 '13 at 17:23
  • Unfortunately not. Each variable is completely unrelated it's counterpart in any of the other iterations. – FraserOfSmeg May 24 '13 at 17:25
  • Have you looked into something like this? http://cudafy.codeplex.com/ – recursive May 24 '13 at 17:32
  • Do you have multiple cores available? – recursive May 24 '13 at 17:47
  • 1
    Are there bounds on the range of values that a, b, c, and d can take on? – DuckMaestro May 24 '13 at 17:54
  • Thanks for all the replies. The process is already threaded on a larger scale (these are run many times for 100 simulations, so I've threaded each simulation with max concurrent threads at 7). – FraserOfSmeg May 24 '13 at 18:00
  • I've actually written cuda code for the software and it worked but it ended up being slower as the time spent sending the data to and from the GPU is a major bottleneck (I'm tempted to keep working with this to find a work around but I haven't gotten around to it yet). There are SOME bounds so for example all are positive, some are integers etc. there's also an upper limit to some of the values (for example value a has an upper limit of about 10,000. @DuckMaestro is there a way I can use this to speed up processing? Any other thoughts? – FraserOfSmeg May 24 '13 at 18:01
  • You should consider writing outer loop in c/c++ and using PInvoke for best performance – ghord May 24 '13 at 18:12
  • Do you have any information about the range (or better still: the distribution) of the argument `(c-a)/ (a*d)`? For example: if the majority is close to 0, you can use a really fast approximation there. – Jeffrey Sax May 24 '13 at 18:44
  • If the magnitude of the inputs to asin() is small and you don't need full double precision accuracy, you could try the approximation asin_core() that I posted in this thread: http://stackoverflow.com/questions/11261170/c-and-maths-fast-approximation-of-a-trigonometric-function/11575574#11575574 – njuffa May 25 '13 at 17:17

3 Answers3

2

I'd do some tests to make sure that the Math.Asin really is the slowest part of the formula. If it really is slow relative to the other multiplications and divisions, then you could try implementing your own lookup table for Math.Asin. In other words, calculate millions of Math.Asin values in advance, and code them into your program. This would trade the size of your program for speed, so if program size doesn't matter, it might help.

Stochastically
  • 7,616
  • 5
  • 30
  • 58
0

You can use the following approximation for Asin, in my tests it was just under twice as fast as Math.Asin (32bit, better if manually inlined, under 64bit it was slightly better than twice as fast) and it looked reasonably accurate, but you'd have to test whether the accuracy is acceptable.

static double Asin(double x)
{
    double x2 = x * x;
    double x3 = x2 * x;
    const double piover2 = 1.5707963267948966;
    const double a = 1.5707288;
    const double b = -0.2121144;
    const double c = 0.0742610;
    const double d = -0.0187293;
    return piover2 - Math.Sqrt(1 - x) * (a + b * x + c * x2 + d * x3);[]


}

(this is C# of course, but you can convert it I'm sure)

[EDIT] Here is the VB version.

Shared Function Asin(ByVal x As Double) As Double
    Dim x2 As Double = x * x
    Dim x3 As Double = x2 * x
    Const piover2 As Double = 1.5707963267948966
    Const a As Double = 1.5707288
    Const b As Double = -0.2121144
    Const c As Double = 0.0742610
    Const d As Double = -0.0187293
    Return piover2 - Math.Sqrt(1 - x) * (a + b * x + c * x2 + d * x3)
End Function
Walt Ritscher
  • 6,977
  • 1
  • 28
  • 35
harold
  • 61,398
  • 6
  • 86
  • 164
-1

You could try to implement the series expansion to whatever precision you require, and compare that against Stochastically's suggestion of a lookup table (which may well be how Math.asin ultimately calculates it) built to the precision required. It seems unlikely that you could enjoy the halving of processing time you'd like, however.

If the calculations aren't meaningfully dependent upon one another (or if the dependencies can be isolated into different batches), you might try to run them in parallel (whether on different systems or with different processors), but be wary -- I worked at a space physics lab, and we found that the precision we required generated really annoying anomalies when we ran tests on different systems.

(I also must say, I'm incredibly curious as to why you'd need to run billions of arc-sine calculations.)

cabbagery
  • 909
  • 7
  • 16
  • To answer your curiosity I'm simulating the progression of many objects moving over time. As this is probability based (for my purpose at least) I run 100 montecarlo simulations. Each simulation has around 20k objects and around 20k steps. So 20k*20k*100 = 40,000,000,000... I've rounded all the numbers up here a little but you get the idea. :) Thanks for the info I'll have a look into it soon :) – FraserOfSmeg May 25 '13 at 05:30
  • 1
    The series expansions Wolfram Alpha provides are terrible for approximating functions over an interval. They are for analytical purposes only (studying the properties of a function, assisting certain proofs, teaching students, et cetera). Function approximations should use minimax polynomials or something similar. – Eric Postpischil May 25 '13 at 11:51