[Numpy-discussion] numpy.floor() is supposed to return an int, but returns a float

Tim Hochberg tim.hochberg at cox.net
Mon Apr 10 09:13:03 CDT 2006

Charles R Harris wrote:

> Tim,
> On 4/9/06, *Tim Hochberg* <tim.hochberg at cox.net 
> <mailto:tim.hochberg at cox.net>> wrote:
>     Let me just add that, since this seems to cause confusion, it would be
>     appropriate to amend the docstring tobe explicit that this always
>     returns an integral floating point value. If someone wants to suggest
>     wording, I can figure out where to put it. One possibility is:
>         "y = floor(x) elementwise largest integer <= x; note that the
>     result
>     is a floating point value"
>     or
>         "y = floor(x) elementwise largest integral float <= x"
> How about, "for each item in x returns the largest integral float <= 
> item."

That seems pretty good. I'll wait a day or so and see what else shows up.

> Chuck
> P.S.
> I too once found the C definition of the floor function annoying, but 
> I got used to it. Sorta like getting used to a broken leg. The main 
> problem is that the result can't be used as an index without 
> conversion to a "real" integer. Integers aren't members of the reals 
> (or rationals): apart from +/- 1, integers don't have inverses.

> There happens to be an injective ring homomorphism of the integers 
> into the reals, but that is not the same thing.

I'm not conversant with the terminology [here I rummage through google 
to try to get the terminology sort of right], but as I understand it 
integers (I) are a subset of reals (R). The ring that you contruct with 
integers consists of the set of integers plus the operations of 
addition/subtraction and multiplication as well as an identity. I've 
seen that specified as  something like (I, +/-, *, 0). Similarly, the 
set of reals (R) and the field that one constructs from them are not 
really the same thing. So while the ring of integers is not a subset of 
the field of reals (the statement doesn't even make sense when put that 
way),the set of integers is a subset of the set of reals. I think that 
most people, outside of computer programmers and perhaps math majors, 
think of the set of integers, not the field of integers, to the extent 
that they think about integers and reals at all. I imagine most people 
would conjure up some Dali like image when confronted with the notion of 
a field of integerse!

(C-int, +/-, *, 0), actually forms a finite field which is not at all 
the same thing the field of integers. Bit twiddlers tend to understand 
and even exploit this, but a lot of people conflate the field of ints 
with the field of integers. This works fine as long as your values are 
small in magnitude, but eventually will rise up and bite you. Floats are 
even worse, since they don't even form a field, I think they're actually 
a semiring because of INF/NAN/IND, but I'm not certain about that. 
Issues with floating point pop up everywhere and if you squint the right 
way, you can blame them on their lack of fieldness. Which is closely 
tied to their finite range and precision, which is what bites people.

Because Python automatically promotes (Python) ints to (Python) longs, 
Python ints map, for most puposes, onto the field of integers. However, 
in numpy wer're stuck using C-ints for performance reasons, so we'd be 
wise to keep the differences between ints and integers in the back of 
our mind.

This is wandering rather far afield (although it's entertaining).

> On the other hand, ints are generally not big enough to hold all of 
> the integral doubles, so as a practical matter the originators made 
> the best choice. Things do get a bit weird for large floats because 
> above a certain threshold floats are already integral values.

Another issue at the moment is that integer division does an implicit 
flooring or truncation (I believe it's implementation dependant in C) in 
both C and Python, so if you aren't using floor to produce an index, 
something I've been known to do, having it return an integer could also 
lead to nasty suprises. For example:

def half_integer(x):
    "return nearest half integer below x"
    return floor(2*x) / 2

Would start failing mysteriously. Of course the above is an overflow 
magnet, so perhaps it's not the best example. Eventually, '/' is going 
to mean true_division and '//' will mean floor_division, so this 
particular issue will go away.




More information about the Numpy-discussion mailing list