Search code examples
game-physicstrigonometryparticle-system

Smoothly Looping Periodic Trigonometric Functions


Unfortunately, I'm a novice programmer but a relatively experienced mathematician.

I wanted to get into developing games, and I think I've almost mastered the basic linear algebra mathematics behind some things like OpenGL. Unfortunately, I don't have the technical know-how yet to do graphical simulations.

As a bit of an elementary exercise, I wanted to try and simulate the continuous movement of a particle in a circular path. I used the simple parametrization

double t=0;
double x = cos(t), y = sin(t);

I'm aware that double has a range of 1.7E +/- 308 according to Microsoft. My question would then be, "How can I ensure the smoothest continuous circular loop of the particle?" The problem that I thought might happen is that if the program ran long enough as t grew larger and larger, we'd reach the point where t would reset to its lowest value and that might cause a "jump" in the position of the particle.

I've thought about this and I wondered if it would be necessary to create a mapping for t from [1.7E-308, 1.7E+308) → [0,2π). Would this help prevent any position "jumps"? Or is there a problem in doing this that I'm not forseeing? My plan would've been to increase t at a predetermined rate, which I haven't determined yet. But I see the rate at which t increases determines how fast the x and y coordinates change.


Solution

  • You worry too much. Or at least about the wrong thing. The sun will turn into a red giant, and swallow earth, long before you exceed the maximum of a double by adding small increments.

    A slightly more serious problem is that the absolute precision of t decreases as its magnitude increases. This is based on the fact that the precision of a double is relative to its magnitude. Even that will take a very long time before it becomes a real problem, but it happens long before t exceeds the double range.

    Another related and more real concern is that the cos()/sin() implementation might become less precise for larger input values. The high quality implementations that you would typically find in a standard library, or in hardware, would hopefully reduce the argument, so that should not be much of a problem.

    All of that being said, avoiding any of these problems, as remote as they may be in reality, is so easy that you might as well take care of it. You simply reduce the value of t as soon as it exceeds 2 * pi after incrementing it:

    t += tInc;
    if (t > 2.0 * M_PI)
    {
        t -= 2.0 * M_PI;
    }
    

    With this, the value will always stay between 0 and 2 * pi.

    BTW: It should be very rare that you need double precision for anything related to graphics. Using variables and constants of type float should be sufficient unless you have a very unusual use case. The graphics library you will be using will typically operate in float precision anyway, so using double in your own code will just use additional memory, and result in a lot of type conversions.