floor() function and mathematical integers

Tim Peters tim.one at home.com
Fri May 18 07:02:29 EDT 2001


[Dennis E. Hamilton]
> OK, we are standing in two different worlds here.

Ya, I picked that up <wink>.

> I am completely clear on the implementation of floating-point
> arithmetic.  But floor is not defined, for me, as an implementation,
> it is defined as a mathematical function.

Then don't use floating point:  fixed precision arithmetic, and no matter how
implemented. will eventually violate every rule you want to rely on.  There's
no point *tweaking* fp to "get closer" to what you think it ought to be,
because it's *fundamentally* incompatible with your view of what computer
numerics should be.

> ...
> If I had my druthers, I would have there be a domain-error exception for
> floor(x) when x is outside the range for which consecutive integers are
> exactly representable.  That is, I wouldn't deliver results outside the

754 double arithmetic has 53 bits of precision.  This make 2.**53 the
smallest positive x for which x+1 == x, so you want floor(2.**53) to
complain, and because "x isn't an integer then" (in this imposed sense).

What about floor(2.**53-1)?  Since we've established that 2.**53 "isn't an
integer", then 2.**53-1 can't be either, since 2.**53-1+1 == the non-integer
2.**53.

Then what about floor(2.**53-2)?  Same thing:  if 2.**53-1 isn't an integer,
then neither is one less than it.  Etc.  Inductively, no "float integers"
exist.  Which is the result you should *expect* from this approach, because
Peano's axioms maintain that the integers are closed under successor, and
cutting it off at "well, it's enough just that x+1 > x, once" is as
artificial a limitation as anything the fixed-precision nature of fp foists
on you.  It's philosophically flawed, yes?

If math.floor() were defined to map floats to ints, I'd have a lot more
symapthy with your view.  But it's defined to map floats to floats, and what
it does makes the best sense *for* floats.

> ...
> That is, I wouldn't deliver results outside the domain where the
> mathematical definition of floor() can't be rigorously honored.

The mathematical definition of floor(M * B**E) for non-negative integers M, B
and E is M*B**E, and math.floor() does rigorously honor that.  You want
something floating point doesn't address at all.

> ...
> My concern is with the promise that we make in specifying the library.
> Although the definition for the Standard C Library is accurate and
> precise (though quite subtle), I am not sure that it serves users of
> Python.

The best clue I have is that yours is the first complaint about math.floor()
in 10 years of Python practice <wink>.  A more interesting question is
whether floating-point in general adequately serves Python's users.  Outside
of the Numeric Python users, I suspect it does not, and there are a number of
now-stagnant PEPs seeking alternatives.  Guido has grown fonder of decimal
floating-point (see the REXX discussion from an earlier reply) instead, and I
wouldn't die of surprise if that were added one of these years.

> ...
> By the way, I am not proposing any changes to Python.  I am not concerned
> about that.

It would help clarify if you were:  so long as it's just philosophical
musing, you won't need to face the difficult issues of selling specific
concrete behavior to real people.  And in the absence of that hard work, I'm
afraid that talk about "serving users" rings hollow.

> I am concerned about the low level of things in Python and other
> languages, including Java and C# and the impact that has on users,
> ones led to believe that they are dealing with something higher-level

I don't believe people are being so led; not by Python, anyway; best guess is
that floating point is irrelevant to most of its users (apart from the NumPy
folks), and so we rarely talk about it at all.

> and ones who will likely never consult the Standard C Library
> definition to get the scoop.  These subtleties tend to be below the
> noise level around programming languages and that allows for lots
> of misunderstandings and wasted hours debugging.  I am looking for
> the lesson in this.

There have been hundreds of implementations of "better arithmetics" in many
languages.  The repeated lesson is simply that the fast drives out the good.
This has become seemingly unstoppable now, as floating-point hardware gets
faster and faster, to the point where *any* saner alternative runs 10-200x
slower, and reaching 10 generally requires expert platform-specific assembler
work.

I'm not sure that's a market failure either, much as I'd like to *believe*
that it is.  Floating point is actually well-suited to the scientific piece
of the computing pie, and the only other non-integer arithmetic with a large
constituency is decimal fixed-point arithmetic, driven by business computing.
Everything else is confined to library packages or research languages.
Curiously, nothing about that story has changed in decades, except that the
dominance of binary floating-point has increased.

> ...
> I think the rub for me is that floor() is a number-theoretic function,
> in contrast with sqrt() or cos() where approximations are understood
> differently (and cos(2.0**500) is still problematic).

Ah.  Perhaps you're just confusing math.floor() with the function of the same
name from number theory.  I'm not pulling your leg there!  math.floor() maps
floats to floats deliberately, and it's actually a useful function *as
defined* in floating-point work.  It's not trying to be a number-theoretic
function (whatever that means exactly <wink>).

> ...
> I think when I want to offer implementations of mathematical objects,
> I will stick to the pure stuff (bignums and rationals), and when
> offering popular implementations (i.e., IEEE floats and 32-bit ints),
> I will keep them  distinct.  I can see the desirability of both.  I don't
> think one approach alone will serve the needs of all users.  And users
> deserve to know more clearly when they are relying on arithmetic schemes
> in which a large number of compromises have been made and there are
> boundary cases to be careful about.  I don't think that we do a very
> good of of letting people know when things are not as simple as we
> encourage them to believe through our omissions.

This is a very optimistic view, Dennis.  Most users won't read a word of the
information you're keen to provide them until *after* they suffer bad
problems, and the more options and explanations you offer the more confused
users will become.  Unlike you, they're not *interested* in the abstractions
or the details.  This is just a fact of life -- why should they be?  That's
where the REXX approach shines, in catering to people who've never really
thought about it and never intend to.  But if you're more interested in
catering to knowledgable and involved users, they don't need nearly the
amount of help you're preparing to give them (just like you didn't need any
help to understand Python's math.floor()).

you-can't-help-those-who-won't-help-themselves-ly y'rs  - tim





More information about the Python-list mailing list