25
\$\begingroup\$

I am working on generation 3d perlin noise. The C# Math library seems like overkill for what I need since most of its functions use double percision. I use Math.Sin() in several places to generate the noise. Does anyone know of a faster sine function?

\$\endgroup\$
1
  • \$\begingroup\$ There is MathF \$\endgroup\$
    – Brackets
    Mar 26 '20 at 9:23
32
\$\begingroup\$

You can use a parabola to aproximate the value of the sine function. This has the advantage of having the roots at exactly -pi/2 and pi/2 which is usually not the case with other fast approximations based on the TaylorSeries or MaclaurinSeries.

public float Sin(float x)
{
    const float B = 4 / PI;
    const float C = -4 / (PI*PI);

    return -(B * x + C * x * ((x < 0) ? -x : x));
} 

Here is a comparison to the actual sine function:

alt text

\$\endgroup\$
5
  • 3
    \$\begingroup\$ This is indeed a great solution. Here is an excellent article from devmaster.net which describes why this works and gives some implementation details: devmaster.net/forums/showthread.php?t=5784 \$\endgroup\$
    – reverbb
    Oct 23 '10 at 20:25
  • \$\begingroup\$ I don't know about C#, but the abs() function in most C environments will likely be faster than a branch (the ?: operator), when optimized. \$\endgroup\$
    – user744
    Oct 23 '10 at 20:50
  • 3
    \$\begingroup\$ I removed the Math.Abs() call because I assumed that this code might run on the Xbox 360 or Windows Phone 7. The JIT compiler on Xbox 360 does not inline anything. A call to Math.Abs() is actually more expensive. \$\endgroup\$
    – zfedoran
    Oct 23 '10 at 21:09
  • \$\begingroup\$ @reverbb Link is 404. Here is a cached copy. \$\endgroup\$ Jan 13 '15 at 0:36
  • 1
    \$\begingroup\$ @zfedoran Why do you negate the return value? It appears to be a negative sine wave. \$\endgroup\$ Jan 13 '15 at 1:36
12
\$\begingroup\$

What is the range of input values to your sin() function? For what you're using it for, it sounds like they might be limited, which means you could pre-compute the values. For instance, if you're rounding up the input values to the nearest degree, then you only have 360 possible values - just pre-compute them and store in a table.

If you need slightly more values, say to one decimal place, you could interpolate from the table - I'm not familiar with perlin noise, but the word "noise" seems to indicate it doesn't require high accuracy. :) (You could also just make a larger table, 3600 entries isn't much space).

\$\endgroup\$
2
  • 3
    \$\begingroup\$ If speed is your number-one concern, and you do not mind sacrificing a bit of accuracy, this is the best answer. \$\endgroup\$ Oct 24 '10 at 21:07
  • 1
    \$\begingroup\$ I don't know about "best" - As shown in another answer, you can get another very good approximation in five ops + abs (the speed of which depends on your arch / compiler, but is often branchless). If the lookup table is not in cache, it's going to be much slower. \$\endgroup\$
    – user744
    Oct 26 '10 at 12:31
4
\$\begingroup\$

You might want to read this too, it's got fast sine and cosine approximations

\$\endgroup\$
1

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .