4.1 Rounding Floating Point Numbers
Floating point numbers in English are called floating point number — numbers with a floating point: In the US, a dot is used to separate the whole and fractional parts of a number. Hence the name float.
As we've discussed, when converting a floating point number (float) to an integer (int), it's always rounded down to the nearest whole number — its fractional part is simply discarded. But it's easy to imagine a situation when a floating point number needs to be rounded to the nearest whole number. What do you do in such a case?
For this, Python has a built-in function round(). It was created before the math library, so it's not part of it. Functions for rounding down and rounding up are found in the math library.
The round() function rounds a number to the nearest whole number:
round(floating_number)
This function will return the nearest whole number to the float that was passed in. It's important to note that if the fractional part of the number equals 0.5, the round() function uses the method of rounding to the nearest even whole number. This is called "bankers' rounding" and helps reduce systematic error when rounding multiple times. For example:
Examples:
| Command | Result |
|---|---|
| x = round(4.1) | 4 |
| x = round(4.5) | 4 |
| x = round(4.9) | 5 |
| x = round(5.5) | 6 |
Function math.ceil() rounds the number up to the next whole number, examples:
| Command | Result |
|---|---|
| x = math.ceil(4.1) | 5 |
| x = math.ceil(4.5) | 5 |
| x = math.ceil(4.9) | 5 |
Function math.floor() rounds the number down to the nearest whole number, examples:
| Command | Result |
|---|---|
| x = math.floor(4.1) | 4 |
| x = math.floor(4.5) | 4 |
| x = math.floor(4.9) | 4 |
Though for rounding down to the nearest whole number, it's simpler to use the type conversion function int():
| Command | Result |
|---|---|
| x = int(4.9) | 4 |
If you're finding it hard to remember these commands, a little English lesson might help:
math— mathematicsround— round/round offceiling— ceilingfloor— floor
4.2 Structure of Floating Point Numbers
The float type in Python can store values in the range -1.7*10308 to +1.7*10308. This huge range of values is explained by the fact that the float type is structured entirely differently compared to integer types. Each variable of type float contains two numbers: the first is called the mantissa and the second is the exponent.
Suppose we have the number 123456789, and we store it in a variable of type float. Then the number will be converted to the form 1.23456789*108, and inside the float type, two numbers will be stored — 23456789 and 8. The "significant part of the number" (the mantissa) is highlighted in red, and the exponent in green.
This approach allows for storing both very large numbers and very small numbers. But since the size of the number is limited to 8 bytes (64 bits) and part of the bits are used to store the exponent (as well as the sign of the number and the sign of the exponent), the maximum length of the mantissa is limited to 15 digits.
This is a very simplified description of how floating point numbers work; for a more complete explanation, you can google it.
4.3 Loss of Precision with Floating Point Numbers
When working with floating point numbers, it's important to remember that floating point numbers are not exact. There will always be rounding errors, conversion errors from decimal to binary, and finally, the most common — loss of precision when adding/subtracting numbers of vastly different magnitudes.
The latter is the most unexpected situation for newbie programmers.
If you subtract 1/109 from 109, you'll end up with 109 again.
| Subtraction of numbers with vastly different magnitudes | Explanation |
|---|---|
|
The second number is too small, and its significant part is ignored (highlighted in gray). The digits highlighted in red are the 15 significant digits. |
What can I say, programming isn't just math.
4.4 The Danger of Comparing Floating Point Numbers
Another danger awaits programmers when comparing floating point numbers. Since rounding errors may accumulate when working with these numbers, it's possible to encounter situations where floating point numbers should be equal, but they're not. Conversely: numbers should not be equal, but they are.
Example:
| Command | Explanation |
|---|---|
| a = 1000000000.0 b = 0.000000001 c = a – b | The variable a will hold the value 1000000000.0 The variable c will hold the value 1000000000.0 (the number in variable b is way too small) |
In the example above, a and c should not be equal, but they are.
Let's take another example:
| Command | Explanation |
|---|---|
| a = 1.00000000000000001 b = 1.00000000000000002 | The variable a will hold the value 1.0 The variable b will hold the value 1.0 |
In practice, floating point numbers are compared like this:
A very small number is chosen. If the difference between the numbers (absolute value) is smaller than this small number, they are considered equal. Example:
a = 0.00000000012
b = 0.000000000011
if abs(a - b) < 0.00001:
print("equal")
else:
print("not equal")
GO TO FULL VERSION