Live data from Hacker News

Why Python's integer division floors (2010)

python-history.blogspot.com

81–90 of 102 posts

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

#81
post #62

I confess I have grown increasingly in favor of how common lisp does this. The basic `/` creates rationals. And "floor" is a multiple value return where the first value is the floor and the second is the remainder. Granted, getting used to multiple value calls takes getting used to. I think I like it, but I also think I emphatically did not like it initially.

To be fair, Python's `/` creates floats, and this article is about a second operator `//`.

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

#82

Earlier quoted context omitted.

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.

Exactly. Modulo is not an operator, but a term for an equivalence class of differing by a multiple of a number fixed in advance.

(mod N) is an operator which indicates that the arithmetic in the preceding formula or equation is understood as taking place in a modulo N congruence.

A triple equal sign is usually used for modular equations. That triple equal sign, together with the (mod N) out to the right, constitute an operator.

-1 ≡ 9 (mod 10)

Since it is written as part of the syntax of a formula or equation, and modifies its semantics, it is an operator. Just like d/dx, sigma notation and whatever not.

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

#83

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.

That's not any clearer. Both "modulo" and "remainder" can be defined in ways (yeah, more than one) that include or exclude negative numbers.

You have to memorize the full definition. There's no mnemonic shortcut.

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

#84

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.

One thing that is still "implementation-defined" in C and C++ is the result of a right shift of a negative integer. On pretty much all platforms, the >> operator shifts in the sign bit and does not round the result — which makes it equivalent to flooring division by a power of two. It is consistent with the division operator only when the left-hand value is positive.

However, the oposite shift is undefined if a 1 goes into the sign bit.

More precisely, regarding E1 "If E1 has a signed type and nonnegative value, and E1 × 2ᴱ² is representable in the result type, then that is the resulting value; otherwise, the behavior is undefined."

Thus if E1 is negative, or if the result overflows, UB.

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

#85

Earlier quoted context omitted.

One thing that is still "implementation-defined" in C and C++ is the result of a right shift of a negative integer. On pretty much all platforms, the >> operator shifts in the sign bit and does not round the result — which makes it equivalent to flooring division by a power of two. It is consistent with the division operator only when the left-hand value is positive.

However, the oposite shift is undefined if a 1 goes into the sign bit. More precisely, regarding E1 "If E1 has a signed type and nonnegative value, and E1 × 2ᴱ² is representable in the result type, then that is the resulting value; otherwise, the behavior is undefined." Thus if E1 is negative, or if the result overflows, UB.

Didn't they specify two's complement signed integers somewhat recently? What's the rationale for leaving these behaviours undefined?

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

#86

Earlier quoted context omitted.

Inf is not incorrect. Division by the two almost zero numbers will also give "unexpected" results, if inf is unexpected.

You're right about the unexpected results in that case, but I'd bet good money that accidentally dividing by zero in code like `avg=sum(lst)/len(lst)` is far more common in standard Python code than dividing very small numbers.

totally agreed, and its so common that some places like snowflake give you div0 and div0null to opt into just returning 0 or null in those cases

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

#87

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.

Neither of them is wrong. Languages (like python) which only return a positive number are returning the least positive residue of division under the modulus. That is the most common interpretation of it in number theory at least far as I know.

C generally does return negative numbers when you use the % operator.

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

#88
post #62

I confess I have grown increasingly in favor of how common lisp does this. The basic `/` creates rationals. And "floor" is a multiple value return where the first value is the floor and the second is the remainder. Granted, getting used to multiple value calls takes getting used to. I think I like it, but I also think I emphatically did not like it initially.

To be fair, Python's `/` creates floats, and this article is about a second operator `//`.

Continuing in fairness, lisp is a bit more involved, here. If you do `(/ 1.0 3)`, you do not get a rational. Similarly, any division that is not integer/rational there will get treated mostly as expected.

Basically, it seems as soon as you introduce a floating point number, it stays there. Which is roughly what I would expect.

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

#89
post #79
post #62

I confess I have grown increasingly in favor of how common lisp does this. The basic `/` creates rationals. And "floor" is a multiple value return where the first value is the floor and the second is the remainder. Granted, getting used to multiple value calls takes getting used to. I think I like it, but I also think I emphatically did not like it initially.

It's nice for general numerical methods but somewhat annoying for implementing integer-arithmetic algorithms.

Yeah, I think this is what I really didn't like about it at the start. Learning that you probably want `floor` if you want things to be integer took more time to learn than feels natural.

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

#90
post #62

I confess I have grown increasingly in favor of how common lisp does this. The basic `/` creates rationals. And "floor" is a multiple value return where the first value is the floor and the second is the remainder. Granted, getting used to multiple value calls takes getting used to. I think I like it, but I also think I emphatically did not like it initially.

Scheme in the form of R7RS does something similar, though since failure to capture all returned values is an error (unlike in Common Lisp), there's more functions involved. It also offers a choice between truncation and floor behavior, so there's `truncate-quotient`, `truncate-remainder`, `floor-` versions and for both values `truncate/` and `floor/`.
Post reply on HN