I grew up in a time when computers couldn’t compute trigonometric functions. The available alternatives where either not use trigonometry in your programs (that’s when algebra and its cross and dot products shine), or to store tables of trigonometric functions and interpolate an approximate values when an evaluation was needed. That created a scar in many of us, and quite like a trauma, these days we still tend to underestimate (of not deny) the brutal evolution that the silicon has undergone.
Today I was doing some real-time mathematical image. In my oldschoolness, I thought I might attempt to speed up the rendering by replacing some trigonometric functions with something approximate but cheaper that would “look” the same in screen. This time I went for my well known and multi-purpose parabola f(x) = 4·x·(1-x). Here I’m scaling the domain from 0..Tau (2PI) to 0..1. It’s easier to work with normalized frequencies (Tau’s) than weird radians. Now, because the parabola (sort of) gives you half the sinus, you gotta duplicate it and put the copy upside down to get the full cycle. You can do that by multiplying the domain by two and renormalizing it to the unit segment by taking its fractional part. Then of course you want to make your function periodic so you end up having something like where I’m using the hat symbol to express the fractional part of a number. This results in something like this:
where the red curve is the real sinus and the blue one is the periodic parabola. Not bad. The problem is probably that there are two fractional part computations (one for 2x, one for x), which are expensive. I thought I might be able to do better that this.
My second attempt was therefore to use (again) a polynomial to generate a full cycle at once, then make that one periodic with a single fractional part computation. Since the curve has to pass by zero, one half and one, such polynomial could simply be g(x) = k·x·(x-0.5)·(x-1). In order to get k such that the function goes from -1 to 1, one has to make sure that g(x)=1 for the value of x that makes the derivative g'(x) = k·(3x² – 3x + 0.5) equal zero, resulting in k = 36/√3, making the complete function . The nice thing about this curve is that g'(0) = g'(1) = k/2, which means that the function is not only periodic, but it’s also smooth at the tiling points. It’s the blue curve in the following graph:
The function is a bit off the sinus, but it’s perfectly fine to be used in pattern generation for mathematical images/textures/animation. So, when I found it I copied it to the code and got my pretty image indeed. I was expecting to see my performance boost, call the whole thing a good move, and continue with my image design. However I got the very disappointing surprise of realizing that g(x) wasn’t faster, but actually much slower than using the original sin(2PIx) that I had been trying to avoid.
And that’s when I realized that I had to unlearn what I once knew to be true. Indeed, these days trigonometric functions are not 110 times slower than arithmetic instructions as they used to be back when they finally implemented them in computers, but they are in fact, basically as fast. And I knew this, yet… So, I wasted about 15 minutes of my evening. The good thing is that I have un-learned a good lesson. I hope this time is for real.