How a computer really calculates the value of sine? (film, 8 minutes)
In the latest video, SimonDev discusses how trigonometric functions actually operate, introducing viewers to a more accessible way of understanding them. He begins with the classic right-angled triangle, where he defines fundamental functions such as sine, cosine, and tangent. However, Simon notes that these methods are largely impractical in modern programming, and a much more helpful way to visualize them is by considering the unit circle. The concept of radians is also explained, illustrating the relationship between angles and the lengths of arcs. Through this visualization, Simon aims to simplify understanding of the sinusoidal function graphs, demonstrating how their values change as the vector rotates around the unit circle.
Next, Simon delves into the dot product, which is related to the cosine function. He utilizes the notion of vectors and scalars, emphasizing how these mathematical concepts apply to calculations in game programming. Thanks to the visualization from the unit circle, viewers can better grasp why the dot product corresponds to the value of cos theta, regardless of the angle. Simon also touches on how trigonometric functions are implemented in code, presenting various approximation methods and the use of lookup tables.
He cites historical approaches to computing sine, including those by Indian mathematician Bhaskara, who created a formula that delivered highly accurate results for angles ranging from 0 to pi. In the context of modern programming, Simon explains why lookup tables are no longer commonly used due to cache issues. Instead, programmers now rely on solutions that employ Taylor series expansions and other methods that facilitate calculations.
As the video concludes, Simon promises more content related to trigonometry and matrices in the future, which will certainly attract viewers seeking intuitive explanations of mathematics for game development. This teaching approach, which simplifies complex topics, has been positively received.
As of this writing, the video on the SimonDev channel has garnered an impressive 315,401 views and 15,131 likes, indicating that the topic has piqued the interest of the programming community. Furthermore, the upcoming offering of a math course, including trigonometry, is likely to draw even more attention.
Toggle timeline summary
-
Introduction to trigonometric functions, focusing on right-angled triangles.
-
Discussion of sine, cosine, and tangent ratios.
-
Visualizing trigonometric functions using a unit circle.
-
Introduction of radians as a unit for measuring angles.
-
Explanation of sine, cosine, and tangent in terms of the unit circle.
-
Graphical representation of sine, cosine, and tangent functions.
-
Understanding the undefined nature of tangent at certain angles.
-
Explaining the dot product in relation to cosine.
-
Expounding on the relationship between dot product and cosine.
-
Discussion on how trigonometric functions are implemented in code.
-
Introduction of Taylor expansion as a method to compute trigonometric functions.
-
Optimization techniques for computing sine including range reduction.
-
Description of how sine functions are computed in hardware.
-
Announcement of an upcoming math course covering trigonometry and game development.
Transcription
In school, I learned the trigonometric functions kind of like this. You have a right-angled triangle, an angle typically called theta here, mathematicians love Greek letters, and you label the sides opposite-adjacent hypotenuse. Then you have the famous formulas, sine equals opposite over hypotenuse, cosine equals adjacent over hypotenuse, and tan equals opposite over adjacent. So in 20 years of development, even in graphics work, I think for me this triangle has come in handy close to zero times. So instead, another way of visualizing this is to start with a circle. And to simplify things further, we can use one with a radius of exactly 1. That is, any point that lies here on the circle is at a distance of exactly 1 from the center. Typically, this angle here between our vector and the x-axis, theta, is expressed in degrees, ranging from 0 to 360. But apparently this is some arbitrary system left over from, well, they're not quite sure. But if you think about the circumference of a circle, that's defined by 2 times pi times the radius, r. With a radius of 1, that boils down to just 2 times pi. So instead of degrees, if we started at the x-axis here, and moved one unit of distance along the circle, we could invent a new unit for angles, called a radian. So now we express angles in terms of distance along the outside of the circle. And thus a circle is 2 pi radians instead of 360 degrees. And that's how radians are made. Now, given this point here on the circle, it forms an angle theta. And since the radius of this circle is 1, the hypotenuse is 1. So sine is just the distance here along the vertical. And that means that cosine is just the distance here along the horizontal. And tan? Well, if you extend a line here from x equals 1 upwards, and you extend the vector forming your hypotenuse out this way, where the two meet, tan gives you this distance here. The distance from their intersection down to the x-axis. I never use this, but it's there. As you move this point around the circle, we obviously expect cos theta, sine theta, and tan theta to change. And we can graph those changes. So sine theta oscillates between 1 and negative 1 as this vector rotates the circle. And cos theta oscillates in much the same way, but just slightly offset from sine of theta. Tan is interesting, because at pi over 2 and negative pi over 2, you can see that tan theta is undefined. Hopefully now seeing this in action, and what tan really is, the graph of tan theta makes much more sense. That's why it kind of freaks out at certain values. This is where it gets a little interesting. If we call this vector a, we know that cos theta is just the x component of this vector here on the unit circle. Or you could say this in a different way. A slightly longer way of saying it is in terms of the full vector a. It is a dot x times 1 plus a dot y times 0. Or again, now we can say it in terms of both a and b, where you know the b vector is just the x axis, or 1, 0. So it's a dot x times b dot x plus a dot y times b dot y, which is now defined in a more mathematical way. It has a name. It's the dot product. So the dot product of a and b is equal to cos theta, which is just this horizontal distance here, if a and b are unit vectors. The more general equation you were taught in school was that a dot b is equal to the length of a times the length of b times cos theta. So now it might make more intuitive sense, then, for why, given any two unit vectors, if we take the dot product between them, you get cos theta. Because if you were to rotate these things around the circle until one hits the x axis, and suddenly this is just reduced to our simple distance along the x axis. Actual real proofs exist, with, like, real math and everything. This isn't one of them, just a nice way of visualizing things. But this is also why the dot product is used to get the scale or projection of one vector onto another. Because that's all this distance is. So then, how are these functions implemented? If you have a chunk of code, when you call your hardware or library function for stuff like sine, what kind of math sorcery are they doing? Well, these tend to be computed in different ways. Various approximations have existed for ages. Back in the 7th century, the Indian mathematician Bhaskara gave the following formula, which I'm not going to read, but it worked really well in the range of 0 to pi, giving an absolute error of, like, 0.0016. In game development, way back in the day, it was often acceptable to use something called a lookup table. By precomputing values and either finding the closest match, or linearly interpolating between adjacent values, it was possible to use a relatively small lookup table to get acceptable results. A lookup table with 512 entries might have an error of around 0.00001, or 1 e to the negative 6. But getting things super right in games isn't usually critical. No one's life is on the line, unless you're Jigsaw. So for example, you could use 16 values from 0 to pi over 2, and that gives an error of 0.0014. But cache misses are expensive these days, so lookup tables aren't used as often anymore. If you were to compute these trig functions directly, the first thought is a Taylor expansion, and courtesy of Wikipedia, they look like this, which does the job nicely. But a common complaint with Taylor series is that the error isn't uniform. The error scales the further you are from 0. Better approaches have a general theme. They combine a whole bunch of ideas. They tend to do what's called a range reduction, followed by an approximation, and then a reconstruction step. First off, looking at a sine wave, you clearly don't need to approximate from negative infinity to infinity. We already know that it repeats after 0 to 2 pi. From there, you can exploit symmetry. This half is really the same as this half, just upside down. And this half of the wave is really just a mirror of the other side. So in reality, you only need to approximate a small portion. So now you have 4 identical quadrants for this function, just flipped and reversed. So given a point in any of these quadrants, you'd map it to a point in the first. Then you may use a polynomial approximation, like the Taylor series we just covered, or something more advanced like minimax. Anyway, you compute your value, then you map it back into the appropriate quadrant, and voila, you have an idea of how your hardware computes the sine value. The sine function on the screen is running the code you see on the left. Intel has a paper from like 20 years ago which details how a lot of their trig functions were implemented. You can also poke around the new C library and see similar ideas in action, if you can read the code. It's not the easiest to work through. Robin Green also has a nice write-up on their blog as well, which is linked in the description. Lastly, this explanation is taken from an up-and-coming math course I'm working on. It'll be available soon. If you're interested in more intuitive explanations of trigonometry, matrices, and math for game development, check it out. Until next time, cheers.