maxpayne
maxpayne

Reputation: 1111

Create a Fast Sin() function to improve fps ? Fast sin() function?

I am rendering 500x500 points in real-time. I have to compute the position of points using atan() and sin() functions. By using atan() and sin() I am getting 24 fps (frames per second).

float thetaC = atan(value);
float h = (value) / (sin(thetaC)));

If I don't use sin() I am getting 52 fps.

and if I dont use atan() I am 30 fps.

So, the big problem is with sin(). How can I use Fast Sin version. Can I create a Look Up Table for that ? I don't have any specific values to create LUT. what can I do in this situation ?

PS: I have also tried fast sin function of ASM but not getting any difference.

Thanks.

Upvotes: 5

Views: 6282

Answers (3)

Eric
Eric

Reputation: 3172

It depends on the accuracy that you need. The maximum derivative of sin is 1, so if if x1 and x2 are within epsilon of one another, then sin(x1) and sin(x2) are also within epsilon. If you just need accuracy to within, say 0.001, then you can create a lookup table of 1000 * PI = 3142 points, and just look up the value closest to the one you need. This can be faster than what the native code does, since the native code (probably) uses a lookup table for polynomial coefficients, and then interpolates, and since this table can be small enough to stay in cache easily.

If you need complete accuracy over the whole range, then there's probably nothing better that you can do.

If you wanted, you could also create a lookup table over (1/sin(x)), since that's your actual function of interest. Either way, you'll want to be careful around sin(x) = 0, since a small error in sin(x) can cause a big error in 1/sin(x). Defining your error tolerance is important for figuring out what shortcuts you can take.

You'd create the lookup table with something like:

float *table = malloc(1000 * sizeof(float));
for(int i = 0; i < 1000; i++){
  table[i] = sin(i/1000.0);
}

and would access it something like

float fastSin(float x){
  int index = x * 1000.0;
  return table[index];
}

This code isn't complete (and will crash for anything outside of 0 < x < 1, because of array bounds), but should get you started.

Upvotes: 6

paddy
paddy

Reputation: 63471

Hang on a second....

You have a triangle, you're computing the hypoteneuse. First, you're taking atan(value) to get the angle, and then using value again with sin to compute h. So we have the scenario where one side of the triangle is 1:

   /|
h / | value
 /  |
/C__|
  1

All you really need to do is calculate h = sqrt(value*value + 1); ... But then, sqrt isn't the fastest function around either.

Perhaps I've missed the point or you've left something out. I've always used lookup tables for sin and cos, and found them to be fast. If you don't know the values ahead of time then you need to approximate, but this means a multiplication, truncation to integer (and possibly sign conversion) in order to get the array index. If you can convert your units to work in integers (effectively making your floats into fixed-point), it makes the lookup even quicker.

Upvotes: 11

Matt Phillips
Matt Phillips

Reputation: 9691

For sin (but not atan) you can actually get simpler than a table--just create

float sin_arr[31416]; //Or as much precision as you need
for (int i=0; i<31416; ++i)
   sin_arr[i] = sin( i / 10000.0 );

//...

float h = (value) / sin_arr[ (int)(thetaC*10000.0) % 31416 ];

My guess is that this will give you a speed improvement.

Upvotes: 2

Related Questions