I wasted some time today tracking down a bug in one of my programs. It turned out to be “unexpected behavior” rather than a bug. I was aware of this aspect of the language, but I made an assumption and got bit. Read on for a valuable lesson.
Python handles integer math differently than floating point math. If you type a number without a decimal point, Python treats it as an integer. All math performed only with integers results in integers. For example, 1/2 evaluates to 0 while 1./2. evaluates to 0.5. If you mix integers and floats, Python will produce a floating point result (1/2.=0.5), but you must be very careful. For example, you might expect the expression 4/3*3.14159 to yield a floating point result. It does yield a floating point number, but not the one you were expecting! 4/3*3.14159 yields 3.14159. What happened? Python works from left to right. 4/3 evaluates to the integer “1”. 1*3.14159 evaluates to 3.14159. For comparison, 4./3.*3.14159 evaluates to 4.1887866. Here’s the problem with this particular aspect of Python: according to the rules of math, 4/3*3.14159 is exactly the same expression as 4*3.14159/3, but in Python they yield different results if you forget the decimal points! 4*3.14159 evaluates to a floating point, so (4*3.14159)/3 yields the “correct” floating point value.
Lesson Learned: be explicit about specifying all floats if you are doing floating-point math! Sometimes I get lazy and leave a trailing decimal point off of a number when doing a floating point calculation, knowing that the results are “upcast” into floats. Not any more!
Note: this unexpected behavior goes away in Python 3.0