Image of A Detailed Look at the Python floor() Function

ADVERTISEMENT

Introduction

The Python math module contains several functions that allow you to perform various mathematical calculations on real numbers. One of those functions is floor(), which returns the largest integer not greater than its argument. The Python floor() function is part of the standard library, meaning it comes prepackaged with every installation of Python and is ready to be used immediately.

In this article, you'll take a closer look at the Python floor() function and gain a solid understanding of what values you can expect it to return.

Overview of the Python floor() Function

The Python floor() function performs a calculation similar to that of rounding down. Given a number, floor() will return the largest integer value less than or equal to that same number. For example:

>>> import math
>>> math.floor(6.253)
6

Here, you pass the float 6.253 into the Python floor() function, which returns the integer value 6.

Note that you first had to import the math module in order to access the floor() function. While floor() is a part of the standard library, you have to explicitly tell Python that you want to be able to use this function. import math accomplishes this step.

However, typing math.floor(number) can get pretty tiresome. You can modify the import statement to where you only need to call floor() in the interpreter:

>>> from math import floor
>>> floor(7.79)
7

Here, you've told the interpreter to specifically load the Python floor() function from the math module. Now, you can simply call floor(number) instead of having to prepend math. to each function call.

NOTE: Later in this article, you'll use special constants from the math module - like math.e and math.pi - to demonstrate the functionality of floor(). To ensure you can run such examples, be sure to include the call import math in your interpreter.

Flooring Numbers

Most of us are familiar with the concept of rounding down. It's the process by which we take a number with digits after the decimal place and figure out which whole number we should use to represent it instead.

Rounding in Python will return the next closest integer to a given number. For instance, the number 7.4 would round down to 7, as it's only four "steps" away from 7 but six "steps" away from 8. In contrast, 7.6 would round up to 8.

This rule, however, invites a conundrum with numbers like 7.5, which is equally far apart from both 7 and 8. In these cases of rounding, Python 3 will then choose the closest even integer to the given number. In other words, 7.5 would round up to 8, but 6.5 would round down to 6:

>>> round(7.4) # closer to 7; round down
7
>>> round(7.6) # closer to 8; round up
8
>>> round(7.5) # choose closest even integer: round up to 8
8
>>> round(6.5) # choose closest even integer: round down to 6
6

This may be different from what you know to do by hand (and in Python 2), which is to round up for any number whose ending digit is 5. Note that in Python 2 the round() function returns a float, whereas in Python 3 it returns an integer.

Flooring numbers, on the other hand, is a bit simpler. When you're flooring numbers, you don't have to worry about choosing the closest integer or looking for an even number. Instead, you only need to consider the number that comes before the decimal point. This is the floor of that number: the largest integer less than or equal to a given number.

Here's how the examples from the previous code block work when you floor the numbers instead of round them:

>>> # closer to 7, but 7 is still largest integer <= 7.4
>>> floor(7.4)
7
>>> # closer to 8, but 7 is still largest integer <= 7.6
>>> floor(7.6) 
7
>>> # equidistant between 7 and 8, but 7 is still largest integer <= 7.5
>>> floor(7.5)
7
>>> # exactly equal to 7, and 7 is still largest integer <= 7
>>> floor(7)
7

In each instance, the number 7 is returned as the floor, as it is always the largest integer less than or equal to the given number.

Flooring Negative Numbers

At this time in Python 3, the Python floor() function might just be seen as another way to convert a float to an integer by truncating any numbers after the decimal. In that case, why not just use int()? To answer this question, let's take a slight detour and talk about the weather.

Weather widgets are extremely common applications. Chances are you have one running on your device right now. Having an accurate idea of what the weather will be like on any given day is a crucial part of planning for many industries, from construction to travel and beyond.

Let's say that following the freak winter storm that hit the US state of Texas in mid-February 2021, you've been hired by an energy company to develop a weather dashboard in Python. The company sends you a list of temperatures each day and would like them to be rounded down to the next lowest whole degree. Their goal is to develop a freeze warning alert system that will notify customers when temperatures drop below freezing.

If you stick with round() or even int(), then you'll quickly find out that your code won't quite meet the specifications stated by the client. For example, here's what these two functions return when the temperature drops below zero degrees Celsius:

>>> round(-0.4)
0
>>> int(-0.4)
0

int() truncates the number you pass to it, moving the value closer to 0. In this case, it removes the decimal point and the number that follows it, leaving -0 which simply resolves to 0. Similarly, round() sees that -0.4 is only four "steps" away from 0 (compared to the six steps it is away from -1) and returns 0 as well.

However, your client has asked you to round all temperatures "down to the next lowest whole degree." This means that a temperature value of -0.4 should return -1, not 0.

In fact, the Python floor() function is the answer to this problem:

>>> floor(-0.4)
-1

Here, floor() looks for the next lowest whole integer that is less than or equal to -0.4. The largest integer that is less than -0.4 is -1, and the Python floor() function correctly returns this value.

The Python floor() function is what you would want to use in order to correctly process the numbers for the energy company's freeze warning alert dashboard. That's because, as soon as temperatures start to drop below zero ([-0.1, -0.2, -0.3, ...]), the app will send the proper notification, as floor() will round these temperatures down to -1. Had you used round() or int() instead, then the app would experience a delay, with temperatures ranging from -0.1 to -0.9 degrees without any notification being sent. As we've seen in Texas in February 2021, early warnings are critical when it comes to freezing temperatures. The Python floor() function will ensure you're returning the right value every time.

Flooring Constants in Python 2 vs Python 3

The Python standard library also contains several numeric constants that can be accessed through the math module. These include:

>>> math.pi # pi: ratio of a circle's circumference to its diameter
3.141592653589793
>>> math.e # e: base of the natural logarithm
2.718281828459045
>>> math.tau # tau: ratio of a circle's circumference to its radius, equal to 2?
6.283185307179586
>>> math.inf # floating-point positive infinity
inf
>>> -math.inf # floating-point negative infinity
-inf
>>> math.nan # not a number
nan

Many of these constants have only existed as part of the math module since Python 3. math.inf and math.nan were added in Python 3.5, while math.tau was included from Python 3.6 and onwards. Previously, the values inf and nan could only be created by passing a string to float().

The changes to how these numbers are represented in Python has also changed how they respond to being passed as arguments into the Python floor() function. These changes will give you an understanding of how the floor() function has changed from Python 2 to 3. Let's take a look at each of them in turn, and compare their return values in Python 2 vs Python 3.

math.pi

Both Python 2 and Python 3 contain the constant math.pi, but the values returned are of different types:

>>> # Python 2
>>> floor(math.pi)
3.0
>>>
>>> # Python 3
>>> floor(math.pi)
3

In Python 2, floor(math.pi) returns a float value, whereas in Python 3, an int value is returned. In general, the Python 2 floor() function returns float values, whereas the Python 3 floor() function returns integer values. This makes sense, as the core functionality of floor() is returning the next lowest integer for a given number.

math.e

The constant math.e is present in both Python 2 and Python 3:

>>> # Python 2
>>> floor(math.e)
2.0
>>> 
>>> # Python 3
>>> floor(math.e)
2

Again, the Python 2 floor() function returns the float 2.0 whereas the Python 3 floor() function returns the integer 2.

math.tau

The constant math.tau does not exist in Python 2:

>>> # Python 2
>>> floor(math.tau)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'module' object has no attribute 'tau'

However, mathematically the constant tau is equal to two times the constant pi. Thus, tau can be represented by simply multiplying math.pi by two and passing the result into the Python floor() function:

>>> # Python 2
>>> floor(2*math.pi)
6.0
>>>
>>> # Python 3
>>> floor(math.tau)
6

Note that math.tau does exist as a constant in Python 3, and the Python 3 floor() function has no trouble returning the correct value.

math.inf and -math.inf

The concept of infinity can bring some interesting and potentially unexpected return values in Python, no matter which version you're running. To complicate things, the Python floor() function wants to return the largest integer less than or equal to a given number. How can this work with infinity?

Let's start with seeing how Python 2 and Python 3 represent the concept of infinity:

>>> # Python 2
>>> math.inf
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'module' object has no attribute 'inf'
>>> 
>>> float('inf')
inf
>>>
>>> # Python 3
>>> math.inf
inf

As you can see, math.inf was explicitly added as a constant for Python version 3.5 and up. In Python 2, you can access an infinite value by passing the string 'inf' to float().

However, Python 2 is the version that actually returns a floored value for infinity with no error:

>>> # Python 2
>>> floor(float('inf'))
inf
>>> 
>>> # Python 3
>>> floor(math.inf)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
OverflowError: cannot convert float infinity to integer

Interestingly, Python 2 actually returns a value when flooring infinity, whereas Python 3 raises an OverflowError. This updated functionality makes more sense: the Python floor() function is meant to return the next lowest integer less than or equal to the number you gave it. What number is less than or equal to infinity? The question has no answer: all numbers are less than infinity, and infinity cannot equal itself.

Both versions of Python behave similarly to the previous example when trying to floor negative infinity:

>>> # Python 2
>>> floor(-float('inf'))
-inf
>>>
>>> # Python 3
>>> floor(-math.inf)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
OverflowError: cannot convert float infinity to integer

Infinity, by definition, cannot be represented as an integer. Since the Python floor() function looks for the next lowest and largest integer, it should - in theory - be unable to return a result for either negative or positive infinity. Newer versions of Python, such as 3.5 and above, successfully takes this mathematical conundrum into account by raising an OverflowError when trying to call the Python floor() function on an infinite value.

math.nan

The last constant we'll consider here is math.nan. This is a special data type that stands for not a number (NaN). In other words, the returned value is either not defined, unrepresentable, or missing.

As you saw in the previous section, Python 2 is relatively consistent about returning a value from float(), even if that value might not make mathematical sense. The same pattern can be seen in its treatment of nan:

>>> # Python 2
>>> floor(float('nan'))
nan
>>> 
>>> # Python 3
>>> floor(math.nan)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: cannot convert float NaN to integer

Here, Python 2 simply returns the passed-in argument nan as its own floor. However, Python 3 takes the mathematical complexity of NaN into consideration and instead raises a ValueError, which states that the float nan cannot be converted to an integer for flooring. Indeed, this should be the case, as any value that is "not a number" should indeed not be able to be converted to a numeric type, as the value does not exist.

Understanding Floor Division

The Python floor() function can be used for one additional mathematical calculation, and that is to find the floor of a division expression.

The result of a division operation generally has two parts: the quotient and the remainder. The quotient is the part of the result that shows how many times one number goes into another. For example, the expression 12 / 5 results in the value 2.4:

>>> 12 / 5
2.4

5 goes into 12 two full times, and this is represented by the 2 in front of the decimal point. From there, the remainder is the amount we have left over. Since 5 * 2 is only 10, we still need two more numbers to reach 12. So, the remainder is 2. This remainder can be represented as a decimal point by dividing it by the divisor, which is 5. 2 / 5 simplifies to 0.4, and this is the .4 from the expression above.

Recall that the process of flooring a number seeks to return the next lowest and largest integer to the given number. This concept can be combined with general division to perform what's called floor division.

In floor division, there is no remainder returned in the final value. Instead, the division is performed, and then the Python floor() function returns the floor of the result:

>>> 12 / 5
2.4
>>> floor(12 / 5) # 2 is largest integer <= 2.4
2

Here, you can see that the Python floor() function returns the largest integer lower than or equal to the result of the original division. The result is the same when dividing negative integers:

>>> floor(-12 / 5) # -3 is largest integer <= -2.4
-3

You can also use the double slash operator // to perform floor division in Python, instead of calling the Python floor() function directly:

>>> 12 // 5
2
>>> -12 // 5
-3

Here, the floor division operator // returns the same values as the Python floor() function.

Conclusion

In this article, you took a closer look at the Python floor() function to see what values it returns and how this has changed from Python 2 to Python 3.

You've examined the differences between floor(), int(), and round(), and considered a scenario in which the Python floor() function is the superior choice. You've seen how to floor positive numbers, negative numbers, and special constants defined in the math module. Lastly, you took a quick look at floor division and learned how to use the floor division operator.

The Python floor() function is part of the Python standard library, and is likely one of those functions you'll come across early on in your Python learning journey. If you're interested in learning more about the basics of coding and software development, check out our Coding Essentials Guidebook for Developers, where we cover the essential languages, concepts, and tools that you'll need to become a professional developer.

Thanks and happy coding! We hope you enjoyed this article! If you have any questions or comments, feel free to reach out to jacob@initialcommit.io.