Exponents and cmath
Understand the math foundations needed for game programming in C++, including power and root functions.
Math and programming go hand in hand, especially in game development. We'll cover the core concepts throughout this chapter, starting from the basics and moving on to concepts that allow us to implement things like virtual cameras and physics systems.
In this first lesson, we're starting with the fundamentals - exponents and square roots. We'll explore how these work in C++, look at different ways to implement them, and start thinking about performance considerations. This sets the stage for the more complex math concepts we'll tackle as we move forward.
Exponents
Exponentiation is the process of raising a number to the power of another number. We can think of it as multiplying a number by itself, multiple times.
The number we start with is called the base, and the number of times it is multiplied by itself is called the power, or the exponent. For example:
- to the power of is equivalent to , which is equal to
- to the power of is equivalent to , which is equal to
- to the power of is equivalent to , which is equal to
We generally represent this operation with a superscript notation, for example:
- to the power of is written as
- to the power of is written as
- to the power of is written as
The most common form of exponentiation we will see is raising a number to the power of , for example, .
An operation like this, where the exponent is , is commonly called squaring. The result of such an operation is called the square of the base number.
For example, the square of is , because .
Order Of Operations
In the order of operations, exponentiation happens before multiplication, but after brackets/parentheses. For example:
The cmath Header and std::pow()
To access the standard library's math utilities, we need to include <cmath>:
#include <cmath>After including cmath or math.h, the pow function is now available within the std namespace:
main.cpp
#include <iostream>
#include <cmath>
int main(int argc, char** argv) {
std::cout << "2 to the power of 3 is "
<< std::pow(2, 3);
return 0;
}2 to the power of 3 is 8Small Exponents
When we need to raise something to a small power, we don't need a helper function. For example, to raise a to the power of 2, it's often preferred to implement that as a * a rather than std::pow(a, 2).
Using SDL_pow() and SDL_powf()
When we're using SDL, alternatives to std::pow() are available in the form of SDL_pow(), which accepts and returns double values, and SDL_powf(), which accepts and returns float values:
main.cpp
#include <iostream>
#include <SDL3/SDL.h>
#include <SDL3/SDL_main.h>
int main(int argc, char** argv) {
std::cout << "2 to the power of 3 is "
<< SDL_pow(2, 3);
std::cout << "\n3 to the power of 4 is "
<< SDL_powf(3, 4);
return 0;
}2 to the power of 3 is 8
3 to the power of 4 is 81Square Root
Finding the square root of a number is, in effect, reversing the process of squaring. For example, the square root of 25 is the number that, if squared, would result in 25.
In other words, the square root of is the value of such that . We saw, from the previous section, that an answer is , because . Therefore, the square root of is .
Square roots are often denoted using the radical sign, which looks like this:
Expressions of any length can appear under a radical sign. That expression should be resolved before calculating the square root. For example:
Using std::sqrt()
To calculate square roots in our programs, the standard library includes the std::sqrt() function within <cmath>:
main.cpp
#include <cmath>
#include <iostream>
int main(int argc, char** argv) {
std::cout << "The square root of 25 is "
<< std::sqrt(25);
return 0;
}The square root of 25 is 5Using SDL_sqrt() and SDL_sqrtf()
Programming a computer to calculate the square root of an input variable is not as easy as it seems. Many different algorithms can be used, each with its advantages and disadvantages. SDL provides optimized implementations that favor speed over maximum precision.
The standard library's std::sqrt() function has the advantage of being highly accurate but may be slower than approximation methods. This is rarely the trade-off we want when working with graphics, particularly when we may be doing thousands of these calculations per frame.
Typically, we prefer a faster implementation that gets an approximate answer. When we're using SDL, we can use the SDL_sqrt() function, which returns and accepts double values, or SDL_sqrtf(), which returns and accepts float values:
main.cpp
#include <SDL3/SDL.h>
#include <SDL3/SDL_main.h>
#include <iostream>
int main(int argc, char** argv) {
std::cout << "The square root of 25 is "
<< SDL_sqrt(25.0);
std::cout << "\nThe square root of 36 is "
<< SDL_sqrtf(36.0f);
return 0;
}The square root of 25 is 5
The square root of 36 is 6Multiple Roots
You may have noted that equations like have multiple possible solutions:
This means that both and are solutions (or roots) to the equation . Such solutions are commonly denoted using the symbol. For example, if , then .
However, it is commonly the case that we are only looking for the positive root, sometimes also called the principal root. The radical notation, such as , indicates we only want the positive root. As such, the only solution to is .
Square Roots of Negative Numbers
What if we wanted to get the square root of -25? There's no real number that can be multiplied by itself to result in -25, or any other negative number.
Because of this, when we're using square root functions, we typically want to make sure that the thing we're trying to calculate the square root of is positive. If our program ever finds itself needing to get the square root of a negative number, it's likely we made a mistake in our logic somewhere.
Summary
This lesson has introduced you to implementing mathematical operations that are fundamental to game development and graphics programming.
We've covered exponentiation and square roots, exploring both the standard library implementations and the optimized SDL versions. Key takeaways:
- Exponentiation involves a base number raised to a power (exponent).
- The notation represents raised to the power of .
- C++'s standard library provides
std::pow()for calculating powers. - SDL's
SDL_pow()andSDL_powf()functions offer performance-focused alternatives for graphics code. - Square roots are calculated with
std::sqrt()in the standard library andSDL_sqrt()/SDL_sqrtf()in SDL. - SDL's math functions typically prioritize speed over maximum precision.
- For simple operations like squaring, direct multiplication (e.g.,
x * x) is often preferred. - Be cautious with square roots of negative numbers.
Spaces, Vectors and Coordinates
Learn the fundamentals of coordinate systems and vectors to create spatial representations