This is a simple little C project demonstrating a useful application of logarithms, with the bonus of a few lines demonstrating localization.
Logarithms
I'll write a full post on logarithms at a later date, but here's a brief overview. The logarithm of a number to a specified base is the power to which the base must be raised to get the number, eg if
Exponentiation
102 = 100
then the base 10 logarithm of 100 is 2:
Logarithm
log10(100) = 2
Any number can be used as the base, but the usual bases are 2, 10 and e which is the base of natural logarithms. e is an irrational number and is 2.718281828 to 9dp. The C standard library provides functions for all three of these in math.h, and scientific calculators usually provide at least base e and base 10 logarithm keys.
John Napier 1550-1617, discoverer of logarithms
Since their invention by John Napier in the 17th century until a few decades ago slide rules and books of log tables were used to simplify multiplication by turning it into a process of addition. Modern science, technology and engineering all depended on that simple idea.
Get Coding
This project will consist of two parts. The first is ridiculously simple and just calculates compound interest over a period of several years, firstly just calculating the final amount and secondly calculating all interim yearly amounts.
The second part will carry out the process in reverse: starting with the opening balance and an interest rate we will calculate how long it will take for our money to grow to a specified amount. This is probably one of those little bits of mathematics that makes you think "hmm, we did that in school but I'd forgotten all about it".
As I mentioned above I will also be using a bit of localization to format numbers and get the local currency symbol.
I have used interest as an obvious example but of course the principle can be applied to any form of exponential growth or decay - reproduction of bacteria, radioactive decay and so on.
Create a new folder somewhere convenient and within it create an empty file called logarithms.c, or download the zip file or use the Github repository if you prefer. Then paste the following into the file.
Source Code Links
logarithms.c
#include<stdio.h> #include<math.h> #include<time.h> #include<locale.h> char* currsym; // global variable for local currency symbol //-------------------------------------------------------- // FUNCTION PROTOTYPES //-------------------------------------------------------- void calculateamounts(double startamount, double interest, int years); void timetoamount(double startamount, double interest, double requiredamount); //-------------------------------------------------------- // FUNCTION main //-------------------------------------------------------- int main() { // get set up for local number formatting and currency symbol setlocale(LC_ALL, ""); const struct lconv* const currentlocale = localeconv(); currsym = currentlocale->currency_symbol; puts("-----------------"); puts("| codedrome.com |"); puts("| Logarithms |"); puts("-----------------\n"); calculateamounts(1000, 1.1, 12); //timetoamount(1000, 1.1, 3138.43); return EXIT_SUCCESS; }
Note that locale.h is #included in this file. We'll use it to obtain the local currency symbol for the system the program is running on, as well as the local number formatting. This is what the first three lines of main achieve, and the currency symbol is stored in a global char* so it can be used across different functions.
Next we'll do the calculateamounts function. Paste the following below the existing code.
logarithms.c
//-------------------------------------------------------- // FUNCTION calculateamounts //-------------------------------------------------------- void calculateamounts(double startamount, double interest, int years) { // calculate and display amount after specified number of years double currentamount = startamount; double endamount = startamount * pow(interest, years); // calculate amounts for each year printf("startamount %s%'.2lf\n", currsym, startamount); printf("years %d\n", years); printf("interest %.2lf%%\n", (interest - 1) * 100); printf("endamount %s%'.2lf\n\n", currsym, endamount); for(int y = 1; y <= years; y++) { currentamount*= interest; printf("Year %2d: %s%'.2lf\n", y, currsym, currentamount); } }
We can now build and run the program. In your terminal type
Compiling
gcc logarithms.c -std=c11 -lm -o logarithms
IMPORTANT: as we are using math.h you need to include -lm. Run the program with
Running
./logarithms
and you should see
Program Output
puts("-----------------"); puts("| codedrome.com |"); puts("| Logarithms |"); puts("-----------------\n"); startamount £1,000.00 years 12 interest 10.00% endamount £3,138.43 Year 1: £1,100.00 Year 2: £1,210.00 Year 3: £1,331.00 Year 4: £1,464.10 Year 5: £1,610.51 Year 6: £1,771.56 Year 7: £1,948.72 Year 8: £2,143.59 Year 9: £2,357.95 Year 10: £2,593.74 Year 11: £2,853.12 Year 12: £3,138.43
All of the above is pretty trivial, but note the use of currsym, and in particular note this:
Number formatting example
%'.2lf
The apostrophe causes the number to be printed with local formatting applied, and the .2 causes the number to be printed with two decimal places.
Finally lets get to the main purpose of this little program: given a certain amount of money earning a certain amount of interest, how long will it take for the balance to grow to a certain amount? This is calculated by taking the logarithm of the new amount as a proportion of the original amount, and dividing it by the logarithm of the growth rate. That sentence probably doesn't make sense, even if you understood how to do it beforehand, so here it is as a formula.
Formula for yearstorequiredamount
yearstorequiredamount = log(requiredamount / startamount) / log(interest)
Using the values hardcoded into main, we already know that in 12 years £1,000 will grow to £3,138 at 10%pa. (If you know where I can get 10% interest please let me know immediately!) Plugging those numbers into the formula we get
Formula for yearstorequiredamount - example
yearstorequiredamount = log(3138.43 / 1000) / log(1.1) = log(3.13843) / log(1.1) = 0.496712446 / 0.041392685 = 12.00000546
The rounding error is less than 3 minutes so probably not worth worrying about, but basically we have turned the process round and calculated what we already knew, that it takes 12 years to get to the final amount from our starting point at the specified interest rate.
In math.h the log function is the natural logarithm (base e) while log10 and log2 are of course bases 10 and 2. It doesn't matter which you use as we are calculating ratios rather than actual amounts, but you must use the same one both times. If you have a minute to spare try out all three, and then try breaking the code by mixing up different log functions.
Let's finish of this program with the timetoamount function.
logarithms.c
//-------------------------------------------------------- // FUNCTION timetoamount //-------------------------------------------------------- void timetoamount(double startamount, double interest, double requiredamount) { double yearstorequiredamount = log(requiredamount / startamount) / log(interest); printf("\nstartamount %s%'.2lf\n", currsym, startamount); printf("interest %.2lf%%\n", (interest - 1) * 100); printf("requiredamount %s%'.2lf\n", currsym, requiredamount); printf("yearstorequiredamount %lf\n\n", yearstorequiredamount); }
Run the program again and you will see
Program Output
puts("-----------------"); puts("| codedrome.com |"); puts("| Logarithms |"); puts("-----------------\n"); startamount £1,000.00 years 12 interest 10.00% endamount £3,138.43 Year 1: £1,100.00 Year 2: £1,210.00 Year 3: £1,331.00 Year 4: £1,464.10 Year 5: £1,610.51 Year 6: £1,771.56 Year 7: £1,948.72 Year 8: £2,143.59 Year 9: £2,357.95 Year 10: £2,593.74 Year 11: £2,853.12 Year 12: £3,138.43 startamount £1,000.00 interest 10.00% requiredamount £3,138.43 yearstorequiredamount 12.000005