Mathematical Expressions

Many people think that to be a good programmer, you need to be "good at math". However, I would argue that this is not necessarily the case. Being good at math is often equated to being good at arithmetic (add, subtract, multiply, divide numbers). While this skill is important and very very useful, the far more important skill is to understand what these operators do and when you should use what operator. Knowing what operator to apply in different situations will help you write better and more efficient programs.

This section looks at problems that have to do with using mathematical opertors. Data types that you learned about in the previous section will also play an important role.

Problem:

Write a program that will ask the user to enter the radius of a sphere (a floating point value). The program will then print out the volume of that sphere.

How would we go about solving this problem?

  1. We must ask user for radius (output)

  2. We must read in a radius value (input)

  3. We must use this number to calculate the volume of a sphere (calculation)

  4. We must print out the result.

Now, if we look at the above, we actually already know how to do steps 1, 2, and 4. This is actually very similar to the addition program in the last chapter. The only step that is really new is the addition of a more complicated operation for calculating volume of a sphere as opposed to just adding two numbers together.

Given this, we can set out the initial skeleton of our program as follows:

#include <stdio.h>
int main(void){

    double radius;  /*problem said radius was floating point*/

    double volume; /*it stands to reason that if the radius is a floating point, the volume will also be floating point*/
    printf("Please enter the radius of the sphere: ");
    /*note that while we may formulate our output with
    number of decimal places, it is always wrong to do it for scanf*/
    scanf("%lf",&radius);

    /*do some math here to find volume*/

    printf("The volume of the sphere is: %.2lf\n",volume);
}

Doing any quick web search, what you will find the following forula for calculating the volume of a sphere:

volumeofsphere=(4/3)pir3volume of sphere = (4/3)*pi* r^3

So, lets see how we would write this into our code:

Now... lets start with assignment operator. The assignment operator in C is written with a single = sign. In math, the = sign means things are the same on left and right. Usually it doesn't matter too much if we have x = y or y = x... because in the end it pretty much means the same things. At least that is what we are use to.

However, in C (and many many other programming languages), this is not the case.

In C, the = sign is called the assignment operator. It means MAKE the thing on the left be the same as right. Firstly it will never be correct to have an expression like the following:

So, firstly it will never be correct to have an expression like the following:

int x;

/*this is wrong, program will not compile*/
3 = x;

The reason this is wrong is because you cannot no matter how much you try, 3 cannot be anything other than 3. 3 is 3. Thats it.

The operand on the left hand side of the assignment (=) operator, must be an Lvalue. That is, it must be something that you can put a value into. So, since 3 is not an Lvalue (we can't change it), the expression we had will not compile.

int x;

/*this is correct*/
x = 3;

So... lets try putting the formula together with code:

volumeofsphere=(4/3)pir3volume of sphere = (4/3)*pi* r^3

Now, our variable to store the volume is volume. The radius was read in and stored in the variable radius... sooo would the following work?

volume = (4/3) * pi * radius ^ 3;

Now, if you try to compile this you will of course get the error that it has no idea what pi is. So, one solution to this problem is of course to replace pi with 3.14159.

volume = (4/3) * 3.14159 * radius ^ 3;

Now, if you put this line in you will next get another complaint involving the binary ^.

In other words, it doesn't seem to like the ^ operator. The reason for this is that in C, ^ is not the exponent operator. ^ is the bitwise exclusive or operator. It has nothing to do with exponents. This tells you that you should not assume that the normal symbols used to type out math expressions directly translates to C. It will be necessary to learn the operators and their rules for C.

In fact, there is no exponent operator in C at all. If you wish to calculate exponents, you can use the pow() function in the math.h library, or you can simply express it with multiplication. As radius3radius^3 is just radiusradiusradiusradius*radius*radius, this is probably the simplest solution to fixing the expression. We will use brackets to ensure correct order of operation (though not actually necessary here). In general if you aren't 100% confident you know the correct order of operations, () can be used to ensure that operators are performed in the order you expect.

volume = (4/3) * 3.14159 * (radius * radius * radius);

Now, if you compile this, it will compile. But ... we are not yet done here. We must now check to make sure that our code is correct. So, lets write out a simple test.

Lets start with something simple. Suppose the radius was 1. The volume would be:

volumeofsphere=(4/3)pir3=(4/3)3.14159(1)3=4.19volume of sphere = (4/3)*pi* r^3 = (4/3)*3.14159*(1)^3 = 4.19

Now, if we try our program with 1... what does it say?

Please enter the radius of the sphere: 1
The volume of the sphere is: 3.14

Clearly, something went wrong here. The type of error represented by the above is called a logical error. A logical error is an error where the logic of the program is not correct... this could be a miscalculation, a wrong sequencing of statements, a misplaced logical structure and more. Logical errors are not caught by the compiler. That is the program compiles into an executable. You can run it. It is just that the result is not correct. It is very important to always test your program.

So, what went wrong in our program? Now, the volume is calculated as just the value of pi. Now, if we look at our expression

(4/3)3.14159(1)3(4/3)*3.14159*(1)^3

we know that (1)3(1)^3 is just 1. So the expression is just (4/3)*3.14159 ... now in order for this to result in pi, the expression 4/3 must evaluate to 1... but how can this be?

Well the reason turns out has to do with data types and how the operators work with each data type.

In general here are the rules for +, - , * , / (addition, subtraction, multiplication and division)

data type of left operand

data type of right operand

data type of result

int

int

int

floating point

int

floating point

int

floating point

floating point

floating point

floating point

floating point

Now... so why would that make 4/3 evaluate to 1?

it is because when you write 4 and 3 like you did in that expression, both operands are considered to be an integer.

4/3 is int/int

Thus, the result of this is an int.

With integer division, the result's decimal places are truncated (chopped off). So 4/3 is 1.33333, chop off the .33333 and you are left with 1.

Note that results are always truncated. Thus, 5/3 = 1.6666 = 1

It does NOT round up. This may seem counter intuitive to all that you learned in math class. However, it turns out that there are some very useful applications to doing divisions this way.

Now, back to our problem. 4/3 results in 1 because 4 and 3 are both considered to be integers. So, if we want it to actually calculate to 1.33333 how would we do this?

One simple solution is to make at least one of these numbers a floating point. If at least one of the operand is a floating point the result is a floating point. if we replace 4 with 4.0 we will essentially solve our problem.

Thus our statement should be:

volume = (4.0/3) * 3.14159 * (radius * radius * radius);

Our final program is therefore:

#include <stdio.h>
int main(void){

    double radius;  /*problem said radius was floating point*/

    double volume; /*it stands to reason that if the radius is a floating point, the volume will also be floating point*/
    printf("Please enter the radius of the sphere: ");
    /*note that while we may formulate our output with
    number of decimal places, it is always wrong to do it for scanf*/
    scanf("%lf",&radius);

    volume = (4.0/3) * 3.14159 * (radius * radius * radius);

    printf("The volume of the sphere is: %.2lf\n",volume);
}

Order of operators

Similar to math, C has operator precedence. That means that if multiple operators appear in the same expression, the evaluation occurs according to this ordering. The result of applying one operator is then used to calculate the rest of the expression. If two operators are at the same level of precedence, you apply according to the operators associativity rule (left to right or right to left).

While there are many operators in C, we are going to focus on the arithmetic operators at this time. We will look at other operators as we go and augment the following chart. Each row is a different level of precedence. Operators in the same row have the same precedence and is evaluated according to their associativity.

operator symbol

what it does

associativity

* / %

multiplication, division, and modulus (remainder)

left to right

+ -

addition and subtraction

left to right

=

assignment

right to left

So, what does this all mean?

Lets consider the following snippet of code:

int x;
int y;
x = y = 6 + 3 * 3 % 4;

In the above expression there are 5 operators (=, =, +, * and %)

Now, according to the operator chart, we know that * and % come first. Then +, then the two = operators.

In the following, the calculations will be reduced by one operator each line according to their precedence.

x = y = 6 + 3 * 3 % 4   //starting expression
x = y = 6 + 9 % 4       // 3 * 3 is 9
x = y = 6 + 1           // 9 % 4 is the remainder of 9/4 which is 1
x = y = 7               // 6 + 1 is 7
x = 7                   /* result of = is value assigned 
                           (7 in this case).  y now has 7 */
7                       /* result of x = 7 is 7 as 7 was assigned
                           we don't do anything with it though.
                           x has value of 7*/

Assignment by operators

There are operators in C that allow you to express an assignment and operator in a single operator. These operators are +=, -=, *=, /=, and %=. In other words, its an operator that combines both an assignment and mathematical operator in one. The result is the value assigned to the left operand. As this operation is an assignment, you must have an lvalue (something you can modify like a variable) for the left operand.

How it works. these operands are a shortcut notation for applying an operation indicated to left and right operand. It then puts the result back into the left operand.

For example, suppose you had this code:

int x=5;
x = x + 2;   // x is 7 after this expression is evaluated

You can rewrite it using the += operator as follows:

int x = 5;
x += 2;     // x is 7 after this expression is evaluated

Increment and Decrement Operators

The increment and decrement operators are one of the most common sources of errors for beginner programmers. It is important to understand what they do so that you do not use it in the wrong manner.

The increment and decrement operators use the symbol ++ (increment) and -- (decrement). Unlike other operators, it only has 1 operand. The operand must be an lvalue (something that you can change).

prefix vs postfix.

While there are two symbols (++ and --), there are in fact 4 operators. The difference between them has to do with where the operator lies with respect to the operand.

post means after. So postfix means the operator comes AFTER the operand. pre means before. So prefix means the operator comes BEFORE the operand.

int x;
x++;    //postfix ++
++x;    //prefix ++

These two operators do NOT have the same order of precedence.

postfix has higher precedence than prefix.

what the operators do

The increment operator will increase the operand by 1. The decrement operator will decrease the operand by 1. This statement is true no matter if it is prefix or postfix.

Thus:

int x = 1;
int y = 1;
x++;
++y;

x and y both start at 1, incrementing them once each, will cause x to become 2, and y to become 2.

what do the operators evaluate to

The most common cause of beginner mistakes to these operators is in not understanding what they evaluate to. That is, what happens if you had a statement like:

a = x++;

Other than precedence, this is also where you will see the difference between prefix and postfix.

The postfix operator results in the original value of the operand before the increment/decrement. The prefix version results in the updated value of the operand.

int x = 1;   //both x and y start at 1
int y = 1;
int a;
int b;
a = x++;   //x becomes 2, a becomes 1 (old value of x)
b = ++y;   //y becomes 2, b becomes 2 (updated, new value of y)

This result is very subtle.

Last updated