LogarithmsΒΆ
The logarithm of base \(b\) for value \(y\) is the power to which \(b\) is raised to get \(y\). Normally, this is written as \(\log_b y = x\). Thus, if \(\log_b y = x\) then \(b^x = y\), and \(b^{log_b y} = y\).
Logarithms have the following properties, for any positive values of \(m\), \(n\), and \(r\), and any positive integers \(a\) and \(b\).
\(\log (nm) = \log n + \log m\).
\(\log (n/m) = \log n - \log m\).
\(\log (n^r) = r \log n\).
\(\log_a n = \log_b n / \log_b a\).
The first two properties state that the logarithm of two numbers multiplied (or divided) can be found by adding (or subtracting) the logarithms of the two numbers. [1] Property (3) is simply an extension of property (1). Property (4) tells us that, for variable \(n\) and any two integer constants \(a\) and \(b\), \(\log_a n\) and \(\log_b n\) differ by the constant factor \(\log_b a\), regardless of the value of \(n\). Most runtime analyses we use are of a type that ignores constant factors in costs. Property (4) says that such analyses need not be concerned with the base of the logarithm, because this can change the total cost only by a constant factor.
C and C++ have always included functions to compute \(\log_e\) and \(\log_{10}\). New in C++11 is a function specifically for base 2. As we will see, base 2 logarithms are used frequently and it is convenient to not have to perform change in base calculations when \(\log_2\) is needed.
double x = std::log(1000); // natural log of 1000
double x = std::log10(1000); // base 10 log of 1000
double x = std::log2(1000); // base 2 log of 1000
In this course, nearly all logarithms used have a base of two. This is because data structures and algorithms most often divide things in half, or store codes with binary bits. Whenever you see the notation \(\log n\) in this text, either \(\log_2 n\) is meant or else the term is being used asymptotically and so the actual base does not matter. For logarithms using any base other than two, we will show the base explicitly.
A useful identity to know is:
To give some intuition for why this is true: What does it mean to take the log (base 2) of \(n\)? If \(\log_2 n = x\), then \(x\) is the power to which you need to raise 2 to get back to \(n\). So of course, \(2^{\log n} = n\) when the base of the log is 2.
When discussing logarithms, exponents often lead to confusion. Property (3) tells us that \(\log n^2 = 2 \log n\). How do we indicate the square of the logarithm (as opposed to the logarithm of \(n^2\))? This could be written as \((\log n)^2\), but it is traditional to use \(\log^2 n\). On the other hand, we might want to take the logarithm of the logarithm of \(n\). This is written \(\log \log n\).
A special notation is used in the rare case when we need to know how many times we must take the log of a number before we reach a value \(\leq 1\). This quantity is written \(\log^* n\). For example, \(\log^* 1024 = 4\) because \(\log 1024 = 10\), \(\log 10 \approx 3.33\), \(\log 3.33 \approx 1.74\), and \(\log 1.74 < 1\), which is a total of 4 log operations.
Self Check
sc-1-2: Simplify the following expression into the form \(log(c)\): \(\log(15) - \log(3)\)
sc-1-3: Simplify the following expression into the form \(log(c)\): \(\log(3) + \log(4)\)
sc-1-4: Solve the following expression: \(\log_{729}(9)\)
Acknowledgements
This section is adapted from Open Data Structures (OpenDSA) by Ville Karavirta and Cliff Shaffer which is distributed under the MIT License.