Live data from Hacker News

Why Python's integer division floors (2010)

python-history.blogspot.com

31–40 of 102 posts

Re: Why Python's integer division floors (2010)

#31
post #26

Earlier quoted context omitted.

to people who use floating-point math seriously, it's very important for floating-point results to be predictably inexact; if they aren't, floating point is at best useless and usually harmful i also didn't know python supported // on floats

> i also didn't know python supported // on floats Like most surprising features in python, it would be terribly annoying if it didn't. Especially since you couldn't make sure the argument to the function you're writing wasn't a float. At that time, anyway.

int(x) // int(y)

Re: Why Python's integer division floors (2010)

#32

It should be noted that in C89, both behaviors of division and modulo are allowed and it's implementation-defined whether division results are truncated or rounded towards negative infinity. This has changed in C99 which only allows truncation towards zero.

I've always considered it a mistake to refer to "%" as a "modulo" operator in C because of its ability to return negative numbers. That's not how modulo arithmetic works. C's "%" is a remainder operator.

Re: Why Python's integer division floors (2010)

#33

Yes that makes perfect sense. So why is int(-1.5) == -1? It should be -2.

The same reason int(-1.999) is -1; The operation is different to integer division. I think of it as taking the "integer" part of the float.

As the article mentions, this is called truncation. It truncates (cuts off) the value at the decimal point.

Re: Why Python's integer division floors (2010)

#34
post #31

Earlier quoted context omitted.

> i also didn't know python supported // on floats Like most surprising features in python, it would be terribly annoying if it didn't. Especially since you couldn't make sure the argument to the function you're writing wasn't a float. At that time, anyway.

int(x) // int(y)

This does something different. a // b tries to "fit" b into a as many times as possible. For example, 1.0 // 0.4 == 2.0 because 0.4 fits twice into 1.0 (with a remainder of 0.2). Though as the result should always be an integer, I'd argue that the result should actually be 2, not 2.0. But alas, it's not.

With your change, you calculate 1 // 0 instead, which crashes.

That said, I think checking isinstance(x, float) was always possible. (And nowadays, you can put a type annotation.)

Re: Why Python's integer division floors (2010)

#35
post #26
post #14

Earlier quoted context omitted.

I mean "inexact results" is essentially float's life motto. That said, I don't really see why you would necessarily want float and integer division to behave the same. They're completely different types used for completely different things. Pick the one that is appropriate for your use case. (It seems like abs(a % b) <= abs(b / 2) might be the right choice for floats which is pretty clearly not what you want for inte…

to people who use floating-point math seriously, it's very important for floating-point results to be predictably inexact; if they aren't, floating point is at best useless and usually harmful i also didn't know python supported // on floats

Sure, but the inexactness of this modulus operation would not be any more unpredictable than all other kinds of float inexactness. Unless you're talking about the case where you don't know whether your operands are ints or floats. But in that case, there are tons of other unpredictabilities. For example, a + b will round when adding (sufficiently large) integers-represented-as-floats while it will never round for integers. So if you take floating-point math seriously, knowing that you're actually dealing with floats is the first step.

Re: Why Python's integer division floors (2010)

#36
post #4

Earlier quoted context omitted.

I strongly disagree. I would estimate that in 90% of cases where I use modulo in languages that truncate (instead of flooring), I write (a % b + b) % b, or something similar, just to get the right behaviour. The exceptional cases are those where I can convince myself that negative numbers simply won't come up. (It's never because I actually want the other behaviour for negative numbers.) - When using modulo to access…

> I have never seen a case where truncation was the right thing to do. Splitting a quantity into units of differing orders of magnitude. For example, −144 minutes is −2 hours and −24 minutes, not −3 hours and 36 minutes. This is about the only case I know of, though.

Oh, that's a somewhat reasonable one. (Though I would expect that you actually want −(2 hours and 24 minutes) in many cases instead, thus needing to handle the negative case separately anyway.)

Re: Why Python's integer division floors (2010)

#37
post #25
post #5

Note the top comment by “ark” - there’s really no perfect solution here. In the floating-point case, you have to choose between negative remainders or potentially inexact results. And you definitely want integer division to work the same as float division.

Python's floating point flooring division operator also has a pitfall: it gives a correctly rounded result as if you computed (a / b) with infinite precision before flooring. This can lead to the following: >>> 1 / 0.1 10.0 >>> 1 // 0.1 9.0 This is because 0.1 is in actuality the floating point value value 0.1000000000000000055511151231257827021181583404541015625, and thus 1 divided by it is ever so slightly smaller…

[deleted]

Re: Why Python's integer division floors (2010)

#38
Forth-83 beat C99 by 16 years!

>Python, unlike C, has the mod operator always return a positive number (twitter.com/id_aa_carmack):

https://news.ycombinator.com/item?id=29729890

https://twitter.com/ID_AA_Carmack/status/1476294133975240712

tzs on Dec 30, 2021 | next [–]

>The submission is a tweet which doesn't really have a title, so the submitter was forced to make up one. Unfortunately the assertion in the chosen title is not correct. In Python the mod operator returns a number with the same sign as the second argument:

  >>> 10%3
  1
  >>> (-10)%3
  2
  >>> 10%(-3)
  -2
  >>> (-10)%(-3)
  -1
https://news.ycombinator.com/item?id=29732335

DonHopkins on Dec 30, 2021 | parent | context | favorite | on: Python, unlike C, has the mod operator always retu...

The FORTH-83 standard adopted floored division.

Signed Integer Division, by Robert L. Smith. Originally appearing in Dr. Dobb's Journal September 1983:

https://wiki.forth-ev.de/doku.php/projects:signed_integer_di...

Lots of other languages got it wrong:

https://en.wikipedia.org/wiki/Modulo_operation#In_programmin...

Symmetric division is the kind of thing that causes rockets ships to explode unexpectedly.

Symmetric division considered harmful:

https://www.nimblemachines.com/symmetric-division-considered...

>Since its 1983 standard (Forth-83), Forth has implemented floored division as standard. Interestingly, almost all processor architectures natively implement symmetric division.

>What is the difference between the two types? In floored division, the quotient is truncated toward minus infinity (remember, this is integer division we’re talking about). In symmetric division, the quotient is truncated toward zero, which means that depending on the sign of the dividend, the quotient can be truncated in different directions. This is the source of its evil.

>I’ve thought about this a lot and have come to the conclusion that symmetric division should be considered harmful.

>There are two reasons that I think this: symmetric division yields results different from arithmetic right shifts (which floor), and both the quotient and remainder have singularities around zero.

>If you’re interested in the (gory) details, read on. [...]

Re: Why Python's integer division floors (2010)

#39
post #35
post #26

Earlier quoted context omitted.

to people who use floating-point math seriously, it's very important for floating-point results to be predictably inexact; if they aren't, floating point is at best useless and usually harmful i also didn't know python supported // on floats

Sure, but the inexactness of this modulus operation would not be any more unpredictable than all other kinds of float inexactness. Unless you're talking about the case where you don't know whether your operands are ints or floats. But in that case, there are tons of other unpredictabilities. For example, a + b will round when adding (sufficiently large) integers-represented-as-floats while it will never round for int…

it's true that it would be deterministic, but it would behave differently from the ieee 754 standard, which is at least surprising, which is another sense of the word 'unpredictable'. admittedly, floating-point math that is inexact in a surprising way is not necessarily useless, and to someone who isn't deep into numerical analysis, all floating-point math is inexact in surprising ways

still, it would have real pitfalls if numerical algorithms that give right answers in every other programming language gave subtly wrong answers in python (raising a division-by-zero exception is less troublesome)

Re: Why Python's integer division floors (2010)

#40
post #34
post #31

Earlier quoted context omitted.

int(x) // int(y)

This does something different. a // b tries to "fit" b into a as many times as possible. For example, 1.0 // 0.4 == 2.0 because 0.4 fits twice into 1.0 (with a remainder of 0.2). Though as the result should always be an integer, I'd argue that the result should actually be 2, not 2.0. But alas, it's not. With your change, you calculate 1 // 0 instead, which crashes. That said, I think checking isinstance(x, float) wa…

yes, agreed
Post reply on HN