Floats and Ints

Manipulating numbers is one of the most important and useful things a computer can do. We’ll look at two number types in this course: int for integers (i.e. whole numbers), and float for floating point numbers, i.e. numbers a decimal point in them.

Integers

In Processing, an int is a whole number (i.e. an integer), such as:

4
-61
0
183993

These are called int literals to distinguish them from variables of type int. For example:

int age = 18;

This statement does two things:

  • It declares age to be a variable of type int.
  • It assigns the value 18 to age. Since this is the first value assigned to age, we say it initializes age.

Keep in mind that age is a variable of type int, while 18 is an int literal. We usually refer to both as ints, but sometimes the distinction matters.

Integer Arithmetic

You can perform arithmetic on ints using the basic arithmetic operators. For example:

int averageLifespan = 82;  // for Canadians

println(2014 + averageLifespan - 18);  // 2078

Or:

int minsInOneHour = 60;
int hoursInOneDay = 24;
int daysInOneYear = 365;
int minsInOneYear = minsInOneHour * hoursInOneDay * daysInOneYear;

println(minsInOneYear); // 525600 --- about half a million minutes in a year

Integer Division

Dividing two ints always returns an int in Processing. For example:

println(1 / 2);  // 0
println(3 / 2);  // 1
println(4 / 2);  // 2

It might come as a surprise that 1 / 2 evaluates to 0. The “correct” answer is 0.5, but the problem is that 0.5 is not an int (it’s a float). So, after Processing divides two ints, if the result has any non-zero digits to the right of the decimal point they get truncated (i.e. chopped off). This is called integer division: dividing two ints always returns an int.

There is one exception, though. Dividing by 0 is an undefined operation in mathematics, and in Processing it causes an error, e.g.:

println(5 / 0);  // ArithmeticException: / by zero

This statement crashes the program and issues the error message “ArithmeticException: / by zero”.

Min and Max Integers

It is important to know that there is a min int and a max int:

println(Integer.MIN_VALUE);  // -2147483648
println(Integer.MAX_VALUE);  // 2147483647

As this shows, the maximum value for an int in Processing is, exactly, the number 2147483647, which is a little over 2.1 billion. Similarly, the smallest int is a little less than -2.1 billion.

This means is that you cannot represent, say, the number 2.5 billion using an int. It can also result in some weird calculations, e.g. here’s what happens if you add 1 to the maximum int:

println(2147483647 + 1);  // -2147483648

This is pretty disturbing when you think about it: by adding two positive numbers together we got a negative number!

Here’s another strange behaviour:

println(2147483648);  // literal out of range

2147483648 is one more than the max int, so it is not an int. This program doesn’t even run: You get a “literal out of range error” when you compile this statement.

Another fact about ints is that there is one more negative int than positive int. The smallest int is \(-2^{31} = -2147483648\), but the biggest int is only \(2^{32}-1\). One place were this might be a small problem is the abs(x) function, that should return x if x >= 0, and -x if x < 0. But the problem is what is abs(-2147483648)? The correct answer is 2147483648, but 2147483648 is not an int: it’s too big! In this one case, the abs function cannot possible return the right answer, and so it does this:

println(abs(-2147483648));
// -2147483648

Note

Processing has a bigger integer type called long, which can represent any integer in the range -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807. That’s about -9.2 quintillion to 9.2 quintillion.

You may be interested to know that 9223372036854775807 has its own Wikipedia page, but -9,223,372,036,854,775,808 doesn’t.

If you need integers bigger than long, then Java (on which Processing is based) has a special type called BigInteger that can represent arbitrarily long integers that are limited only by the amount of memory in your computer.

The Mod Operator

There’s one other useful int operator you should know about: the % operator, which is called the mod operator, or the remainder operator. For instance:

println(5 % 2);  // 1
println(6 % 2);  // 0
println(14 % 8); // 6

The expression 5 % 2 is read “5 mod 2”, and it calculates the remainder when 5 is divided 2: since 2 goes into 5 two times with 1 left over, 5 % 2 equals 1.

One application of % is to test if a number is even or odd. For example, 178 % 2 is 0, which means 178 is even (because 2 goes into 178 exactly 89 times with 0 left over). In general, if n is a positive int and n % 2 is 0, then n must be even. The only other possibility is that n % 2 is 1, which means n is odd.

Here’s an example of you might use % in animation. This program makes a ball wrap-around the screen without using an if-statement:

float x;

void setup() {
  size(500, 500);
}

void draw() {
  background(255);

  ellipse(x, 250, 100, 100);

  x += 2;
  x = x % 500;
}

Floating Point Numbers

In Processing, a float is a number with a decimal point in it, such as:

4.5
-61.2
0.0
-3.0
183.993

These are examples of float literals, which are so-named to distinguish them from variables of type float. For example:

float speed = 1.8;

Here, speed is a variable of type float, while 1.8 is a float literal. Just as for ints, this statement does two things:

  • It declares speed to be a variable of type float.
  • It assigns speed the initial value of 1.8.

Floating Point Arithmetic

In most cases, floating point arithmetic works like regular arithmetic. For example:

println(1.2 + 3.2);     // 4.4
println(6.0 - 3.344);   // 2.7
println(2.1 * 3.14);    // 6.594
println(-18.6 / 29.1);  // -0.63917524
println(10.0 / 2.0);    // 5.0

Notice that 10.0 / 2.0 evaluates to 5.0, which is a float. Whenever you divide two floats, the result is always a float.

However, there are a few important details you need to be aware of.

Division by 0.0

Dividing a number by 0.0 is undefined mathematically, but for a float we get a surprising result:

println(5.6 / 0.0);  // Infinity

There is no error message here — the actual result is a special float value called infinity. Another special float value occurs in this case:

println(5.6 / 0.0 - 5.6 / 0.0);  // NaN

Again, this does not cause an error, but instead prints the special float value NaN, which means “not a number”.

If you think about this, it leads to a strange conclusion: if x is a float, then it is possible that x - x is not equal to 0.0!

The reasons when and how floats use these special values are quite technical and beyond the scope of the course. The important thing for us is to know that these values exist and can occur in ordinary calculations.

Min and Max floats

The smallest and largest float values are as follows:

println(Float.MIN_VALUE);  // 1.4E-45
println(Float.MAX_VALUE);  // 3.4028235E38

Notice a few things here:

  • The numbers 1.4E-45 and 3.4028235E38 are written in exponential notation, and are equivalent to \(1.4 \times 10^{-45}\) and \(3.4028235 \times 10^{38}\).
  • The min float is 1.4E-45, and it is traditionally called machine epsilon. It is, approximately, the smallest possible number that we can represent as a float. Any positive number less than 1.4E-45 is treated as equivalent to 0.0.
  • The max value, 3.4028235E38, is a huge number with 39 digits in it. However, only the first 8 or so digits are significant, i.e. after 8 digits all the digits are 0.
  • The smallest float is -3.4028235E38, which is just the negation of the max float.

Rounding Errors

A major problem with floating point numbers is that they are often unavoidably inaccurate. For example, in mathematics \(\frac{1}{3} = 0.3333 \dots\), where the \(\ldots\) means there are an infinite number of 3s after the decimal point. But a Processing float can’t have an infinite number of digits:

println(1.0 / 3.0);  // 0.33333334

As you can see, there are a finite number digits, plus the final digit has been rounded to 4. So it is not exactly equal to \(\frac{1}{3}\), but is instead a little bit bigger.

For many programs, round-off errors don’t make any noticeable difference. But sometimes they can be the source of serious bugs that are very hard to fix. There is an entire sub-field of computer science called numerical analysis that studies how to do accurate and efficient floating point arithmetic on machines.

In this course, we will usually just ignore round-off errors and hope that our floating point calculations are accurate enough.

Mixing ints and floats

You can often use ints and floats together without a problem. For example:

println(4.0 + 5); // 9.0

In the expression 4.0 + 5, 4.0 is of type float, and 5 is of type int. Processing doesn’t actually know how to add float and int, so it automatically converts 5 into the float 5.0. This makes the expression equivalent to 4.0 + 5.0, which is 9.0.

You can also assign an int to a float without error, e.g.:

float temperature = 21;   // 21 is an int, but temperature is a float

This works because Processing automatically converts 21 to 21.0.

By default, you cannot assign a float to an int:

int age = 5.5;  // compiler error

This statement fails to compile because 5.5 is of type float, and you are not allowed to store a float in an int variable. However, you can explicitly convert 5.5 to a float like this:

int age = int(5.5);

println(age);  // 5

Summary Table

  int float
Sample literals 4, -5, 0 -4.0, 3.14, 0,0
Min -2147483648 -3.4028235E38
Max 2147483647 3.4028235E38
Smallest positive 1 1.4E-45
When dividing by 0 run-time error infinity or NaN
Special values none infinity, NaN

Questions

  1. Give an example of:

    • a positive int literal
    • a negative int literal
    • an int literal that is neither positive nor negative
    • statement that declares a new int variable and initializes it to 15
  2. What does this print?

    println(5 * (1/2 + 1/3 + 1/4 + 1/5));
    
  3. In regular arithmetic, \(\frac{5}{\frac{1}{2}} = 5 \cdot \frac{2}{1} = 10\). What does the equivalent expression, 5 / (1 / 2), evaluate to in Processing?

  4. What is the biggest possible int? You answer should be accurate to within about 2 million.

  5. Suppose n is a positive int. Is the expression n + 1 always greater than 0? Why, or why not?

  6. What is the name of the % operator?

  7. What are the values of the following expressions?

    • 8 % 2
    • 8 % 3
    • 17 % 4
    • (100 % 2) + (100 % 3) + (100 % 4)
  8. Give an example of:

    • a positive float literal greater than 100
    • a positive float literal between 0 and 1
    • statement that declares a new float variable and initializes it to 3.14
  9. How many digits are there in the maximum possible float value? Your answer should be correct within 1 digit.

  10. What does NaN stand for?

  11. What does this print?

    println(91.22 / 0.0);
    
  12. Give a simple example of an expression involving floats that suffers from a round-off error.

  13. What does this print?

    println(91.22 / 0);
    
  14. What does this print?

    println(int(6.9) + 3);
    
  15. Answer “true” or “false” for each of the following questions:

    1. If n is a positive int, then n + 1 is also a positive int.
    2. If a and b are both of type int, and a > b is true, then a + 1 > b is also true.
    3. If n is a positive int, then n - n is 0.
    4. If x is a float, then x - x is 0.0.