Because they are, for most purposes, more accurate than integers.
Now how is that? "for speed of an object in a game..." this is a good example for such a case. Say you need to have some very fast objects, like bullets. To be able to describe their motion with integer speed variables, you need to make sure the speeds are in the range of the integer variables, that means you cannot have an arbitrarily fine raster.
But then, you might also want to describe some very slow objects, like the hour hand of a clock. As this is about 6 orders of magnitude slower than the bullet objects, the first ld(10⁶) ≈ 20 bits are zero, that rules out short int
types from the start. Ok, today we have long
s everywhere, which leave us with a still-comfortable 12 bits. But even then, the clock speed will be exact to only to four decimal places. That's not a very good clock... but it's certainly ok for a game. Just, you would not want to make the raster much coarser than it already is.
...which leads to problems if some day you should like to introduce a new, even faster type of object. There is no "headroom" left.
What happens if we choose a float type? Same size of 32 bits, but now you have a full 24 bits of precision, for all objects. That means, the clock has enough precision to stay in sync up-to-the-seconds for years. The bullets have no higher precision, but they only "live" for fractions of a second anyway, so it would be utterly useless if they had. And you do not get into any kind of trouble if you want to describe even much faster objects (why not speed of light? No problem) or much slower ones. You certainly won't need such things in a game, but you sometimes do in physics simulations.
And with floating-point numbers, you get this same precision always and without first having to cleverly choose some non-obvious raster. That is perhaps the most important point, as such choice necessities are very error-prone.
The Handbook of Floating-point Arithmetic, while rather expensive, is about as comprehensive a reference as you can get on the subject. It's designed with applicative uses in mind though it may be hard to parse the formal sections of math contained there-in. However, it will give a solution set for division in both hardware and software if you can parse the content which is not particularly mathy unless you delve into the proof sections of the book.
Wikipedia also lists a number of division algorithms, most of which are covered in mind-numbing detail in the above book. The article even links a Javascript simulator to test out various algorithms.
Best Answer
Short answer
It was a bug. Well, not exactly a bug, but the behavior was changed based on a proposal for Python 3. Now,
ceil
andfloor
return integers (see also delnan's comment). Some details are here: http://www.afpy.org/doc/python/2.7/whatsnew/2.6.htmlWhy Python originally returned floats
This question has some nice answers about the behaviour before Python 3. Since the mathematical operators where wrappers around the C mathematical operators, it made sense to follow the convention of that language. Note that in C, the
ceil
function takes and returns adouble
. This makes sense because not all floats can be represented by integers (for values with a big exponent, there is no direct representation with integers).Python was historically not explicitely designed to formally conform to some of the properties of mathematical operations (that would not happen by accident). Guido Von Rossum has acknowledged some early design mistakes and explained the rationale behind the types used in Python, notably why he preferred C types instead of reusing the ones in ABC. See for example:
Early Language Design and Development
The Problem with Integer Division. The division operator used to perform truncation when given integers or long, which was generally unexpected and error-prone: see Changing the Division Operator.
The language is supposed to evolve, though, and people tried to incorporate numeric type systems from other languages. For example, Reworking Python's Numeric Model and A Type Hierarchy for Numbers.
Why it should be an integer
The fact that integer 8 is also a real number does mean that we should return a floating point value after doing
floor(8.2)
, exactly because we would not return a complex value with a zero imaginary part (8 is a complex number too).This has to do with the mathematical definitions of the operations, not the possible machine representations of values: floor and ceiling mathematical functions are defined to return integers, whereas multiplication is a ring where we expect the product of x and y from set A to belong to set A too. Arguably, it would be surprising if
8.2 * 10
returned the integer82
and not a floating point; similarly the are no good reasons forfloor(8.2)
to return8.0
if we want to be conform to the mathematical meaning.By the way, I disagree with some parts of Robert Harvey's answer.
There are legitimate uses to return a value of a different type depending on an input parameter, especially with mathematical operations.
I don't think the return type should be based on a presupposed common usage of the value and I don't see how convenient it would be. And if it was relevant, I'd probably expect to be given an integer: I generally do not combine the result of
floor
with a floating point.Inconvenience of Python 3
Using the operations from C in Python could be seen as a leaky abstraction of mathematical operations, whereas Python generally tries to provide a high-level view of data-structures and functions. It can be argued that people programming in Python expect operations that just work (e.g. arbitrary precision integers) and prefer to avoid dealing with numeric types at the level of C (e.g. undefined behaviour of overflow for
unsignedsigned integers). That's why PEP-3141 was a sensible proposition.However, with the resulting abstraction, there might be some cases where performance might degrade, especially if we want to take the ceiling or floor of big floats without converting them to big integers (see comment from Mark Dickinson). Some may argue that this is not a big deal if a conversion occurs because it does not impact the overall performance of your program (and this is probably true, in most cases). But unfortunately, the problem here is that the programmer cannot choose which behaviour suits the most her needs. Some languages define more expressive functions: for example Common Lisp provides
fflor
andfceiling
, which return floating-point values. It would be preferable if Python could providefceil
too. Alternatively, a sufficiently smart compiler could detectfloat(math.ceil(x))
and do the right thing.