5

For an ocean shader, I need a fast function that computes a very approximate value for sin(x). The only requirements are that it is periodic, and roughly resembles a sine wave.

The taylor series of sin is too slow, since I'd need to compute up to the 9th power of x just to get a full period.

Any suggestions?

EDIT: Sorry I didn't mention, I can't use a lookup table since this is on the vertex shader. A lookup table would involve a texture sample, which on the vertex shader is slower than the built in sin function. It doesn't have to be in any way accurate, it just has to look nice.

Hannesh
  • 7,256
  • 7
  • 46
  • 80
  • Is the Taylor series slow for x between 0 and π/2? If it's acceptable, then you can use the symmetries of sin to compute it for other values. – lhf Aug 23 '11 at 23:21

5 Answers5

6

Use a Chebyshev approximation for as many terms as you need. This is particularly easy if your input angles are constrained to be well behaved (-π .. +π or 0 .. 2π) so you do not have to reduce the argument to a sensible value first. You might use 2 or 3 terms instead of 9.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • +1 for Chebyshev, it's the best way to go. However, range reduction is a huge advantage if possible. – Jason S Aug 24 '11 at 00:46
3

A rational algebraic function approximation to sin(x), valid from zero to π/2 is:

f = (C1 * x) / (C2 * x^2 + 1.) 

with the constants:

c1 =   1.043406062 
c2 =  .2508691922 

These constants were found by least-squares curve fitting. (Using subroutine DHFTI, by Lawson & Hanson).

If the input is outside [0, 2π], you'll need to take x mod 2 π.
To handle negative numbers, you'll need to write something like:

t = MOD(t, twopi)
IF (t < 0.) t = t + twopi

Then, to extend the range to 0 to 2π, reduce the input with something like:

IF (t  < pi) THEN
  IF (t < pi/2) THEN
    x = t
  ELSE
      x = pi - t
   END IF
 ELSE 
   IF (t < 1.5 * pi) THEN
     x = t - pi
  ELSE
     x = twopi - t
   END IF
END IF

Then calculate:

f = (C1 * x) / (C2 * x*x + 1.0)
IF (t > pi) f = -f

The results should be within about 5% of the real sine.

andy_a
  • 131
  • 2
  • I've edited my answer in response to these criticisms. To clarify, the rational function f = (c1 * x) / (c2 * x^2 + 1) is valid 0 to π/2. The reduction IF-block extends it to 0 to 2π, but you have to do that beforehand. You have to take the mod 2π first. Lawson and Hanson wrote a least-squares subroutine that is helpful in finding the constants, any least-squares routine will serve the purpose. If you can compress the 13 lines of correction code into a one-liner, show it to me. – andy_a Apr 02 '21 at 17:37
  • [Optimized for relative error](https://www.wolframalpha.com/input/?i=plot+%28%28%281.01815748+*+x%29+%2F+%280.23133484+*+x%5E2+%2B+1.%29%29+-+sin%28x%29%29%2Fsin%28x%29++for+x+in+%5B0%2C+pi%2F2%5D) instead of absolute error: `float sin_rational (float a) { return (1.01815748f * a) / (0.23133484f * a * a + 1.0f); }` – njuffa Apr 03 '21 at 19:44
  • Andy, I took back my unfavorable vote because I appreciate the response. I will get back to you about the rest when I find the time to do so. – Mike Nakis Apr 04 '21 at 13:43
  • I apologize, the function does indeed work if implemented properly, which I initially failed to do. However, my benchmark shows that it is considerably slower than Java's built-in `Math.sin()` function running on a modern PC, ***and*** my tests how that it is significantly less precise than an alternative method (see https://stackoverflow.com/a/28050328/773113) which also happens to be much faster than Java's built-in function. – Mike Nakis Apr 04 '21 at 14:11
3

You can make a look-up table with sin values for some values and use linear interpolation between that values.

Mircea Ispas
  • 20,260
  • 32
  • 123
  • 211
1

Well, you don't say how accurate you need it to be. The sine can be approximated by straight lines of slopes 2/pi and -2/pi on intervals [0, pi/2], [pi/2, 3*pi/2], [3*pi/2, 2*pi]. This approximation can be had for the cost of a multiplication and an addition after reducing the angle mod 2*pi.

President James K. Polk
  • 40,516
  • 21
  • 95
  • 125
  • Well, more accurate than that :P It doesn't need to be 'accurate' in that sense, I'm not concerned about finding the approximate sine of a given angle. I'm just trying to find smooth function that looks like a wave. – Hannesh Aug 24 '11 at 09:51
  • @Hannesh: Ha, ok, at least I didn't say it could be approximated by the function f(x) = 0. – President James K. Polk Aug 24 '11 at 11:19
0

Using a lookup table is probably the best way to control the tradeoff between speed and accuracy.

Ernest Friedman-Hill
  • 80,601
  • 10
  • 150
  • 186
  • -1 because this justisn't true today i guess, especially when the clock rates go way more up in the future – Quonux Feb 12 '14 at 23:30