Proof that both camps are wrong (was: Pinecones multiply like rabbits around here...)

Bruce Sass bsass at freenet.edmonton.ab.ca
Wed Jul 25 02:46:06 EDT 2001


Ya, I know, putting equations in a post is a good way to lose readers,
fast... but it is kind of hard to avoid given the circumstances,
and it is grade school stuff.

---
On Tue, 24 Jul 2001, Skip Montanaro wrote:
I was on a walk with my wife and dog yesterday.  Out of the blue I
asked her "what's the result of five divided by two?"  After a little
back-and-forth where she tried to figure out how I was trying to trick
her and make her look foolish she answered, "two-and-a-half".  I then
posed, "Suppose you have five pinecones and you want to clump them
into groups of two.  What would you do?".  Her answer was, "Put two in
the first group, two in the second group, and break the last pinecone
in two so the third group would have two as well."

<...and in a followup...>

...based upon my wife's statement.  (She wound up with three groups...)
---

Yes, because you did not explicitly specify whether it is necessary
for the groups to contain pinecones, just that there should be "groups
of two" (i.e., 2 * group**-1).

Interesting, there seems to be three answers to this problem.  I'll do
it with units (because a number without a qualifier is meaningless)...

  5 * pinecone**1       5
 -----------------  =  --- * pinecone**1 * group**1
   2 * group**-1        2

  =  ???  (read as "<quantity> groups of pinecones" in english)

I suppose the pro-PEP 238 camp wants to say the answer is...

     4                     1
  ((--- * pinecone**1) + (--- * pinecone**1)) * group**1
     2                     2

  = (2 * pinecone**1 * group**1) + (0.5 * pinecone**1 * group**1)

  = 2.5 * pinecone**1 * group**1


The anti-PEP 238 camp would stop short of the last step,
for a couple of (good) reasons, and end up with...

 = (2 * pinecones**1 * group**1) + inconsequential remainder


But, Skip, I think your wife got it right...

     4                     1
  ((--- * pinecone**1) + (--- * pinecone**1)) * group**1
     2                     2

                              1
 = ((2 * pinecone**1) + (1 * ---pinecone**1)) * group**1
                              2

                       1
 = 3 * (pinecone**1 + ---pinecone**1) * group**1
                       2


Questions:
Which of the above three answers has lost information?
Which of the first two can be made to not lose any information?


I have been sitting on the fence on this issue (PEP 238), simply
because there did not appear to be a correct answer.  I can now
explain why... both the pro and anti PEP 238 camps are wrong,
because both of their answers lose information.

int/int->float   may lose type-of-thing information
int/int->int     may lose quantity information


Consider these excerpts
(and read Stephen Horne's posts, once you get past the panic there is
 good stuff ;-)...
---
>From Paul Svensson <paul at svensson.org>:
There are two common ways to do division.
A) x / y = z such that z * y = x,
B) x / y = z and x % y = r such that z = int(z), 0 <= r < x, z * y + r = x
---
and Guido van Rossum <guido at python.org> writes:
Reiterating why the current definition of '/' is evil: int and float
together aren't really two distinct types: they are at most a
type-and-a-half, and the integers are embedded in the space of floats
for most practical purposes. ...
---

What Paul has revealed is that there is _d_ivision as it occurs
in nature, B); and _D_ivision as a mathematical concept, A).

I missed the significance of what Guido wrote the first time I read
it, and still do not understand what is meant by "type-and-a-half";
but now think the last bit reveals Guido is using Division.

I understand why Division is preferable in a high level programming
language, and how losing type-of-thing information can be missing from
the discussion;  but am not sure why losing one piece of information
is better or worse than losing the other.


It is too bad that an operator can't just return what is appropriate
given the inputs (i.e., int, float, rational, <some weird mathematical
object>), because that is what is required of a complete Division
implementation.  I would call both Division and Multiplication,
operators-and-a-half, simply because they are invented and can handle
things beyond that which exists in the real world.  Perhaps it is
appropriate for * and / to have more complex behaviour than + and -.

Maybe having, "a,b,c = x/y" not generate an exception when there are
no additional results, would work.  That way x and y can be any
mathematical object, and it is up to programmers to ensure they
provide enough `slots' for the result tuple to unpack into for the
amount of polymorphism they want to support.  The rest of the visible
portion of the implementation seems to be in place... namely:
coercion to a more complex type when necessary, and "a = 1,2" being
OK (for backwards compatibility).

Python's learning curve would end up being a little steeper closer to
the origin, but it would definitely get new users off on the right
foot with respect to Division and numerical types.


- Bruce

p.s. - If you do not know what the properties of pinecones are, feel
free to substitute "pinecone" with anything whose properties you think
you understand... beans, molecules, quarks, quantum strings,
<whatever>.












More information about the Python-list mailing list