3

I was wondering if there is any reason not to use the // operator to round a number to an integer. I didn't see much on this topic or really know what to look for to find out more.

>>> from random import random
>>> random() * 20 // 1
1.0
>>> random() * 20 // 1
0.0
>>> random() * 20 // 1
16.0
>>> random() * 20 // 1
11.0
>>> random() * 20 // 1
0.0

Besides needing to add 1 to the result (to not get a range of 1-20 instead of 0-19) Or does this actual result in the range 0-20?

kojiro
  • 74,557
  • 19
  • 143
  • 201
ThorSummoner
  • 16,657
  • 15
  • 135
  • 147
  • 3
    You should use `int` to convert `float` to `int`, and use `random.randrange` to generate `int`. – Holt Aug 14 '14 at 20:03
  • Like `range`, `random` is *half-open*; it doesn't include `1.0`, so you will never get `20`. If you want random integers, why not `random.choice`, `.randrange` or `.randint`? – jonrsharpe Aug 14 '14 at 20:14
  • The [`//` operator](https://docs.python.org/2/library/operator.html#operator.floordiv) doesn't round to the nearest integer, it does [floor division](http://python-history.blogspot.ch/2010/08/why-pythons-integer-division-floors.html). – Lukas Graf Aug 14 '14 at 20:19

4 Answers4

3

The main reason not to use it would be that there are perfectly good in-built functions int and round that already do this, which are likely to be efficient and will not confuse someone reading your code.

Another reason as pointed out in the comments is that //1 is equivalent to math.floor rather than int or round. -2.5 // 1 returns a float -3.0 whereas int(-2.5) returns an integer -2.

The fact that experienced programmers can be confused about what //1 does, illustrates nicely why it is better to use one of the existing functions designed for this purpose -- they behave in ways that are clearly defined, documented and consistent.

Stuart
  • 9,597
  • 1
  • 21
  • 30
3

The reason not to use // to convert a random float to a random int is because you can skip straight to the random int:

>>> import random
>>> random.random()      # [0.0, 1.0)
0.4399641241469895
>>> random.uniform(0,20) # [0.0, 20.0)
11.494311814130072
>>> random.randint(0,20) # [0, 20) or [0, 19]
7

To answer your question: x // y performs a floor division of x by y, so your result will always round down. To round to the closest integer:

>>> x = 1.7
>>> x // 1
1.0
>>> int(x)
1
>>> (x + 0.5) // 1
2.0
>>> int(x + 0.5)
2
>>> round(x)
2.0
>>> int(round(x))
2

Adding 0.5 (or subtracting for a negative number) before converting to an int does the same thing as round(x) (built-in). It's worth noting that x // 1 rounds down, but int(x) round toward zero.

It is not possible for random.random() * 20 // 1 to return 20 because random is half-open. random.uniform(0,20) // 1, however, can return 20, but the chance of that happening is near-zero.

1

Well, // does not round an integer. Round means to return the closest integer, but check this:

print round(1.9)     # 2.0
print 1.9 // 1       # 1.0
enrico.bacis
  • 30,497
  • 10
  • 86
  • 115
  • So its more approximate to the `floor` function. I may liberally misuse the word round to myself to mean any float to integer conversion. – ThorSummoner Aug 14 '14 at 20:32
0

It gives you a range of 0-19 and // is in fact floor division that still yields a floating point number but I read this is what you meant to say.

A possible reason not to use may be that // 1 is not a very concise syntax for expressing it. Python is highly about readability, and this syntax is not very obvious to what it does. It is like JavaScript's ~~x trick.

If I were to review this code, I would suspect a bug first and a feature second.

Alexander Gessler
  • 45,603
  • 7
  • 82
  • 122