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

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

cu_0xff profile image cu_0xff 🇪🇺 Originally published at Medium ・2 min read

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]:
    ...

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

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

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

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

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.

Posted on by:

cu_0xff profile

cu_0xff 🇪🇺

@cu_0xff

Veteran in IT, Xoogler, Ex-Microsoft, works in Static Program Analysis

DeepCode.AI

DeepCode learns from GitHub project data to give developers AI-powered code reviews

Discussion

markdown guide