A correction: Interpters as calculators

14Oct08

In my last post, I said that using Python and Ruby were great alternatives to a calculator. I even provided some examples of how you could do nested calculations in the interpreters.

What I failed to both notice and remember is how Python (and apparently Ruby) handle integer arithmetic. Even in my examples, the answer comes out differently for Python and Perl, and I failed to notice. I also used a different example for Ruby, which I shouldn’t have done for consistency’s sake.

Here’s the problem — try this in either Python or Ruby, and you’ll see what happened:

>>> (5 + (2 * 80))/2
82

The answer, of course, should be 82.5. Why is it giving us the wrong answer? It’s not because Python can’t do the math, it’s because we’re telling it to do the math wrong.

Consider:

cranleigh:~ kschwen$ irb
>> (5.0 + (2 * 80))/2
=> 82.5


cranleigh:~ kschwen$ python
>>> (5.0 + (2 * 80))/2
82.5

So, what changed? Before, we were telling Python and Ruby to take an integer and divide it by another integer (in this case, 165 was being divided by 2). These languages take their cues from C, an older programming language that makes a distinction between integer math and decimal/floating-point math.

The code that I originally posted comes out roughly to this in C:

#include <stdio.h>
int main (void) {
   int x = 165/2;
   printf("%i", x);
   return 0;
}

This will output 82 just like Python did, because we’re telling it to do the math with integers. If we change it to this, however, things change:

#include <stdio.h>
int main (void) {
   float x = 165.0 / 2;
   printf("%f", x);
   return 0;
}

Here, we’re explicitly telling the compiler to use floating-point math, which will provide us with a more accurate answer.

This digs down to the foundations of the languages. In Python, you don’t have to explicitly give your variables a type as you do in C. If you’ll notice in the C code, when we were doing division of integers, we stored it in an “int,” which means a variable meant to hold an integer. In the code with the correct answer, we had to tell it we wanted floating-point math.

Python takes care of this for us, but sometimes it can burn you. It takes a look at your numbers — 165 and 2 — and figures that if you’re using two integers, you want an integer in return.

If you add a decimal point to even one of the numbers, you’ve turn it into a float, and Python will return a decimal number — even if there’s just a zero after the decimal:

>>> 80.0 + 5
85.0

Searching for answer, I stumbled across a blog with a good look at reasonable output of floating-point numbers. If you’re still confused and want another perspective, I suggest you take a look.

Not having to type your variables can often save you a headache, but you have to make sure you’re not introducing a new one in the process. Sorry if I confused you with the last post.

If you’re wondering why Perl gives the correct answer, it’s because Perl uses more advanced context cues to figure out what to do with your variables in this and other situations. In this case, it will automatically use floating-point math to return a proper answer. This takes slightly longer to execute, which is why C — a language meant to be lean and fast — doesn’t do it, and languages that follow C’s lead will have the same quirks.

Advertisements


3 Responses to “A correction: Interpters as calculators”

  1. This will change in the soon to be released Python 3.0, so that 3/2 will return 1.5 rather than 1. You can get the same behaviour now by writing:

    from __future__ import division
    print 3/2

    will return 1.5. In Python 3.0 you’ll have to write 3//2 to get 1 instead of 1.5.

  2. 2 schwanksta

    You’re right. I should do a post on the upcoming changes to the language soon. Thanks for pointing that out! I need to start playing with __future__.


  1. 1 Interpreters as calculators « Everyday Scripting

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s


%d bloggers like this: