DEV Community

Cover image for DeepCode’s Top Findings#7: Python Use Real Floor Division
cu_0xff 🇪🇺 for DeepCode.AI

Posted on • Originally published at Medium

DeepCode’s Top Findings#7: Python Use Real Floor Division

Language: Python
Defect: DivisionRounding
Diagnose: Use // instead of / to make sure the value is rounded to an integer and not fractional. %function% expects an int as its first argument.

This example is sponsored by tensorflow / models and you can follow along by loading it into your dashboard on deepcode.ai

Screenshot

I was fascinated by this as it shows a difference between Python 2.7 and 3. The code snippet below shows the interesting parts.

...
 def take_action(self, current_node_ids, action, step_number):
...
    goal_number = step_number / self.task_params.num_steps
    ...
      if n == self.episode.goal_node_ids[goal_number][i]:
    ...

Enter fullscreen mode Exit fullscreen mode

step_number and self.task_params.num_steps are both integers. In Python 2.7, the division operator / works as a floor division. But dividing integers will always result in an integer.

Python 2.7.16 (default, Jul 13 2019, 16:01:51)
[GCC 8.3.0] on linux
> 3/4
0
> 9/10
0
Enter fullscreen mode Exit fullscreen mode

This is no longer true with Python 3.

Python 3.7.4 (default, Jul  9 2019, 00:06:43)
[GCC 6.3.0 20170516] on linux
> 3/4
0.75
> 9/10
0.9
> 4/2
2.0
Enter fullscreen mode Exit fullscreen mode

See the difference? In Python 3, the division behaves differently, so you need to be careful. A division between two integers results in a floating-point number, even if there is no remainder.
What DeepCode did under the hood was a type analysis and it inferred that goal_number is a floating-point number. It traced goal_number to its definition and found it to be a result of a division of two integers. But it is later used as the parameter for an index operator which needs to be an integer. If the program calls the index-operator with float, it results in TypeError. DeepCode learned from scanning thousands of open source repos that typically this should have been a real floor division // instead of a division /. And it happens quite frequently when porting code from Python 2.7 to Python 3.

Python 3.7.4 (default, Jul  9 2019, 00:06:43)
[GCC 6.3.0 20170516] on linux
> table = [1,2,3,4,5,6,7,8,9,10]
> a = 30
> b = 10
> table[a/b]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: list indices must be integers or slices, not float
> table[a//b]
4
Enter fullscreen mode Exit fullscreen mode

To "simulate" the Python 2.7 behavior, you can use the floor division operator //.

Python 3.7.4 (default, Jul  9 2019, 00:06:43)
[GCC 6.3.0 20170516] on linux
> 3//4
0
> 9//10
0
Enter fullscreen mode Exit fullscreen mode

Not sure if this still is of interest but in Python 2.7 // works on integers just as expected so it is safe to use.

Top comments (0)