Strange Arithmetic

What gets printed?

int x = 1/2 + 1/3 + 1/4;
cout << x << "\n";

What gets printed?

double x = 1/2 + 1/3 + 1/4;
cout << x << "\n";

dividing two ints always returns an int (truncated)

What gets printed?

double x = 1.0/2 + 1/3 + 1/4;
cout << x << "\n";

What gets printed?

double x = 1.0/2.0 + 1.0/3.0 + 1.0/4.0;
cout << x << "\n";  // 1.08333

What’s the value and type?

double(1)/2 evaluates to the double 0.5

double(1/2) evaluates to the double 0.0

1/double(3) evaluates to the double 0.33333

double(1)/double(4) evaluates to the double 0.25

Dividing by 0 in math class

in math class, what is \(\frac{3}{0}\)?

answer (in math class): division by 0 is undefined, you just can’t do it

(in math class) it’s just like trying divide 3 by a rectangle — you can’t do that because it’s undefined

Division by 0 (int literals)

cout << "2 / 0 = " << (2 / 0);

compiler error (for us!)

error: division by zero

Division by 0 (int variables)

int n = 2;
int zero = 0;
cout << "n / zero = " << (n / zero);

// Run-time error: Floating point exception (core dumped)

Division by 0 (int variables)

int n = 2;
int five = 5;
cout << "five / (n - n) = " << (five / (n - n));

// compiler error (for us!): error: division by zero

Division by 0.0 (doubles)

cout << "4.0 / 0.0 = " << (4.0 / 0.0);
// 4.0 / 0.0 = inf  (!)

inf is a value representing positive infinity

cout << "0.0 / 0.0 = " << (0.0 / 0.0);
// 0.0 / 0.0 = -nan  (!)

nan is a value representing “not a number”

nan and inf are both doubles and they are not equal to each other

Round-off Errors

there are infinitely many real numbers, but only a finite number of doubles, so round-off errors are unavoidable

cout << 1.0 / 3.0;
// 0.333333

0.333333 is a little less than the true value \(\frac{1}{3} = 0.3333\ldots\)

for example:

double a = 1.0 - (2.0/3.0);
double b = 1.0 / 3.0;
cout << "a = " << a << "\n";
cout << "b = " << b << "\n";
cout << "a - b = " << (a - b) << "\n";
if (a == b) {
    cout << "no round-off error\n";
} else {
    cout << "round-off error\n";
}

the printed values of a and b look the same, but their not!

when << prints a double, it prints a certain number of digits by default; you can change the number of printed digits using setprecision, e.g.:

double a = 1.0 - (2.0/3.0);
double b = 1.0 / 3.0;
cout << "a = " << setprecision(20) << a << "\n";
cout << "b = " << setprecision(20) << b << "\n";
cout << "a - b = " << (a - b) << "\n";
if (a == b) {
    cout << "no round-off error\n";
} else {
    cout << "round-off error\n";
}

now you can see that a and b are different

for most practical applications, though, a and b are so close that it is fine to treat them as equal

Comparing Floating Point Numbers

x == y is often a bad way of comparing two doubles

round-off errors might make x and y not exactly equal

use abs(x - y) < EPSILON, where EPSILON is a small double you define (e.g. maybe 0.000001)

Computer arithmetic is not regular arithmetic!

in mathematics these facts are true

for any real number \(x\)

  • if \(x > 0\) then \(x + 1 > 0\)
  • \(|x| \geq 0\)
  • \(x = x\)
  • if \(f(1) = 2\), then \(f(1) + f(1) = 2 + 2 = 4\)

but these are not all true in C++!

Computer Arithmetic Can be Strange

if \(x > 0\) then \(x + 1 > 0\)

int a = 2147483647;
int b = 1;
cout << a + b;
// -2147483648

2147483647 is the max int (\(2^{31} - 1\))

-2147483648 is the min int (\(-2^{31}\))

adding 1 to the max int gives you the min int

Computer Arithmetic Can be Strange

\(|x| \geq 0\)

cout << abs(-2147483648);

-2147483648 is the min int

due to 0, there is one more negative int than positive int

so -2147483648 has no matching positive int

Computer Arithmetic Can be Strange

\(x = x\)

double x = 0.0 / 0.0;
bool same = (x == x);
cout << same;

prints 0, which means x == x is false (!)

0.0 / 0.0 is nan, i.e. “not a number”

nan != nan

Computer Arithmetic Can be Strange

if \(f(1) = 2\), then \(f(1) + f(1) = 2 + 2 = 4\)

consider this C++ function:

int count = 0;

int f(int n) {
    ++count;
    return n + count;
}

then f(1) + f(1) evaluates to 5 (!)

you could also have a completely unpredictable function like this

int g(int n) {
    int a;
    cin >> a;
    return n + a;
}

we have no idea what g(1) returns!!

we can even have functions that don’t return at all, e.g.:

int h(int n) {
    if (n <= 1) cmpt::error("oops");
    return n + 1;
}

h(1) does not return any value

instead, it throws an exception

Advice

important floating point calculations must be done with great care

however, we will mostly ignore round-off errors in this course and hope they don’t cause problems