Lesson 11 - Mathematical functions in the C language - The Math library
Lesson highlights
Are you looking for a quick reference on the
<math.h>
C library instead of a thorough-full lesson? Here it
is:
Using <math.h>
constants:
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
int main()
{
printf("Pi: %lf \n", M_PI);
printf("e: %lf \n", M_E);
return 0;
}
Min/max of 2 values:
{C_IMPORTS}
#include <math.h>
{C_MAIN_BLOCK}
printf("Min: %lf \n", fmin(5, 10));
printf("Max: %lf \n", fmax(5, 10));
{/C_MAIN_BLOCK}
All roundings:
{C_IMPORTS}
#include <math.h>
{C_MAIN_BLOCK}
printf("Round: %lf \n", round(-0.2));
printf("Ceiling: %lf \n", ceil(-0.2));
printf("Floor: %lf \n", floor(-0.2));
printf("Truncate: %lf \n", trunc(-0.2));
double d = 2.72;
int a = (int)round(d); // casting the rounded double to the int type
{/C_MAIN_BLOCK}
Abs:
{C_IMPORTS}
#include <math.h>
{C_MAIN_BLOCK}
printf("Abs: %d \n", abs(-10));
{/C_MAIN_BLOCK}
Trigonometric functions:
{C_IMPORTS}
#include <math.h>
{C_MAIN_BLOCK}
printf("Sin: %lf \n", sin(M_PI)); // almost 0
printf("Cos: %lf \n", cos(M_PI));
printf("Tan: %lf \n", tan(M_PI)); // almost 0
printf("Acos: %lf \n", acos(0));
printf("Asin: %lf \n", asin(-1));
printf("Atan: %lf \n", atan(0));
{/C_MAIN_BLOCK}
Powers, roots, logarithms:
{C_IMPORTS}
#include <math.h>
{C_MAIN_BLOCK}
printf("Pow: %lf \n", pow(2, 3));
printf("Sqrt: %lf \n", sqrt(144));
printf("Exp: %lf \n", exp(2));
printf("Log: %lf \n", log(100));
printf("Log10: %lf \n", log10(100));
{/C_MAIN_BLOCK}
Dividing whole numbers in C always results in another whole number:
{C_CONSOLE}
int a = 5 / 2;
double b = 5 / 2;
double c = 5.0 / 2;
double d = 5 / 2.0;
double e = 5.0 / 2.0;
int f = 5 / 2.0;
printf("a = %d \n", a);
printf("b = %lf \n", b);
printf("c = %lf \n", c);
printf("d = %lf \n", d);
printf("e = %lf \n", e);
printf("f = %d \n", f);
{/C_CONSOLE}
The remainder after division (modulo):
{C_CONSOLE}
printf("%d", 5 % 2); // prints 1
{/C_CONSOLE}
Would you like to learn more? A complete lesson on this topic follows.
In the previous C lesson, Multidimensional arrays in the C language, we learned about multi-dimensional
arrays. Today's tutorial is about mathematical functions in the
math.h
standard library that will certainly come handy in our
future programs.
fmin()
, fmax()
,
fdim()
Let's start with some simple methods All 3 functions take two numbers of the double
type as
parameters. Fmin()
returns the smallest number, fmax()
returns the largest one, fdim()
returns x-y
in cases
when x > y
or it returns 0
otherwise.
round()
, ceil()
,
floor()
, and trunc()
All the functions are related to rounding. The return value of all the
functions is also a double
. Round()
takes a decimal
number as a parameter and returns the rounded number in the way we learned in
school (from 0.5
it's rounded upwards, otherwise it's rounded
downwards). Ceil()
rounds upwards and floor()
rounds
downwards no matter what. Trunc()
cuts the decimal part off and
leaves the whole number part intact (does not round it whatsoever).
We'll certainly use round()
very often. I've used the other
functions to do things like determine the number of pages in a guestbook. For
example, when we have 33
comments and we only print 10
comments per page. Therefore, they'd occupy 3.3
pages. The result
must be rounded up since there will actually be 4
pages.
If you think that floor()
and trunc()
do the same
thing, think again! They behave differently for negative numbers.
Floor()
rounds negative numbers down to the next "more negative"
number, trunc()
always rounds to zero when the input is
negative.
We round decimal numbers and store them in int
variables like
this:
double d = 2.72; int a = (int)round(d);
Casting to int
is necessary despite the fact that the
round()
method returns a whole number. It is still of the
double
type, due to the fact that all mathematical functions work
with double
types to keep a consistent interface. All the following
functions will return double as well.
abs()
and signbit()
Both methods take a single number as a parameter. Abs()
returns
its absolute value and signbit()
returns -1
if the
number is negative, otherwise, it returns 0
. The
signbit()
function is not supported by all C compilers so it's
possible you won't be able to use it in certain places.
sin()
, cos()
,
tan()
Classic trigonometric functions, all take an angle as a double, which has to
be entered in radians (not degrees if your country uses them). To convert
degrees to radians we multiply them by * (M_PI / 180)
.
acos()
, asin()
,
atan()
Inverse trigonometric (arcus, sometimes cyclometric) functions, which return
the original angle according to the trigonometric value. Those are inverse
functions to the sin()
, cos()
, and tan()
functions. The parameter is a double
and the returned angle is in
radians. If we wanted to have the angle in degrees, we'd have to divide the
radians by * (180 / M_PI)
.
pow()
and sqrt()
Pow()
takes two parameters. The first is the base of the power
and the second is the exponent. If we wanted to calculate eg. 23, the
code would be as follows:
#include <stdio.h>
#include <math.h>
int main(void)
{
printf("%lf", pow(2, 3));
return 0;
}
Sqrt()
is an abbreviation of SQuare RooT, which returns the
square root of the number given as a double.
exp()
, log()
,
log10()
Exp()
returns Euler's number raised to the given exponent.
Log()
returns the natural logarithm of the given number.
Log10()
returns the decadic logarithm of the number.
Hopefully, you noticed that the method list lacks any general root function. We, however, can calculate it using the functions the library provides.
We know that roots work like this: 3rd root of 8 = 8^(1/3)
.
Therefore, we can write:
#include <stdio.h>
#include <math.h>
int main(void)
{
printf("%lf", pow(8, (1.0/3.0)));
}
It is very important to write at least one number with a decimal point when
we are dividing. Otherwise, the C language will assume that we want it to apply
whole-number division, and the result would have been 8 ^ 0 = 1
in
this case.
Division
Programming languages often differ in how they perform the division of numbers. You need to be aware of these issues to avoid being, unpleasantly, surprised afterwards. Let's write a simple program:
{C_CONSOLE}
int a = 5 / 2;
double b = 5 / 2;
double c = 5.0 / 2;
double d = 5 / 2.0;
double e = 5.0 / 2.0;
int f = 5 / 2.0;
printf("a=%d b=%f c=%f d=%f e=%f e=%d", a, b, c, d, e, f);
{/C_CONSOLE}
We divide 5/2
several times in the code. Mathematically, it is
2.5
. Nonetheless, the results will not be the same in all cases.
Can you guess what we'll get in each case? Go ahead, give it a try
Console application
a=2 b=2.000000 c=2.500000 d=2.500000 e=2.500000 f=2
We see the result of this division is sometimes decimal and sometimes whole. It doesn't only matter what the data type of the variable we're assigning the result to is. What also matters is the data type of the numbers we divide by. If one of the numbers is a decimal, the outcome will always result in a decimal number. Division of 2 integers always returns an integer. Keep in mind that if you compute the average and want a decimal result, at least one variable must be cast to a double.
int sum = 10; int count = 4; double average = (double)sum / (double)count;
Note: For example, the PHP language always returns the decimal result of the division. When you divide in different programming languages make sure you check how division works before you use it.
The remainder after division
In our applications, we often need the remainder after an integer division
(i.e. modulo). In our example of 5/2
, the integer result is
2
and modulo is 1
(what's left over). Modulo is often
used to determine whether the number is even (when the remainder of a division
by 2
is 0
). You would also use it if you wanted to,
for example, draw a checkerboard and fill in the fields based on whether they
are even or odd, calculate the deviance of your position from some square grid,
and so on.
In the C language and C-like languages in general, modulo is a percent sign,
i.e. %
:
{C_CONSOLE}
printf("The remainder after 5/2 is %d", 5 % 2); // prints 1
{/C_CONSOLE}
That's it. In the next lesson, Solved tasks for C lessons 10-11, we'll introduce user functions which are very important to divide our application logically into multiple code blocks.
In the following exercise, Solved tasks for C lessons 10-11, we're gonna practice our knowledge from previous lessons.