Project 2a: Python-powered Unit Converter

Dan Garcia, 2006-02-12
10 millipedes = 1 centipede
106 phones = 1 megaphone
10 cards = 1 decacards
2000 mockingbirds = 2 kilomockingbirds
10-12 boos = 1 picoboo
-- Funny Internet Metric Chart

Historical Background

Let's take a trip back down memory lane. Imagine you're a high-paid engineer for NASA, and the date is late September, 1999. The entire agency is all abuzz with the prospect of the Mars Climate Orbiter (MCO), launched more than nine months ago, reaching a stable orbit around our neighboring red planet and sending back important weather data.

Figure 1. Illustration of the Mars Climate Orbiter

On September 23, 1999, your team loses the signal to this multi-million dollar orbiter. In November, after a lengthy investigation, you inform the press of the reasons for the crash:

Data in a software file for calculating trajectory forces was in English units of pound-seconds (lbf-s), but the thruster was expecting the data to be in metric units of Newton-seconds (N-s).

History records the experience as one of the most egregious and expensive bugs of all time. Engineers and computer scientists the world over vow to be diligent to check, double-check and triple-check the units in their calculations.

The Challenge

For this project, you'll write a Python program to do unit conversion -- provide the translation of a quantity specified by a certain amount in one source unit and a destination unit. That is, your program should be able to answer the common question (and many more like it): How many meters in 10 miles? (answer: 10 miles = 16,093.44 m)

To make the input easy, you'll specify your queries in a simplified format:

AMOUNT SOURCE_UNIT in DESTINATION_UNIT

...which will make the understanding, or parsing of the input much easier. As an example, this is the way you would specify your earlier request:

10 mi in m

to which your program should respond:

10 mi = 16093.440000 m

What units do you need to support?

We would like you to support units in three categories: distances, volumes, and weights with at least the following units in each category:

Unit categories Units within that category you must support
distances m (meters), cm (centimeters), mm (millimeters), km (kilometers), in (inches), ft (feet), yd (yards), mi (miles)
volumes L (liters), mL (millileters), floz (fluid ounces), cup (cups), pint (pints), qt (quarts), gal (gallons)
weights g (grams), kg (kilograms), mg (milligrams), oz (ounces), lb (pounds)

You should be able to convert any amount of a unit in any category to any other unit in the same category.

Where to find the conversion constants

There are many websites and books with conversion constants listed, so feel free to get this data any way you wish. One great source is Google, who provides a very handy calculator that happens to have the exact same format for specifying these conversions. So, if you type into the Google search field:

10 mi in m

it will respond with:

10 mi = 16 093.44 m

which is the same thing we returned. They separate their thousands with a space and truncate trailing zeros; you don't have to do that if you don't want to. You can use Google to find out how many source units are in a destination unit by typing "1 source_unit in destination_unit" and build internal tables to store these answers. You could also consult the online Dictionary of Units. See the hints section below to see how we suggest you approach the internal details of storing the information.

At this point, you might wonder why we're doing all this work if Google can do it for us. The answer is threefold: first, we don't always have access to the Internet. Second, it's a valuable beginning programming activity. Finally, Google does not permit offline searches (e.g., using a Python program to call it) so we couldn't use them as our "brains".

What interface to the users do you need to provide

Your text interface doesn't have to be fancy, but it does have to have a few key features:

For example, here is our interface. Note that your program doesn't have to look exactly like ours, it only needs to adhere to the checklist above (and the final checklist below)

computer% python project2a.py
Welcome to our Python-powered Unit Converter v1.0 by Dan Garcia!
You can convert Distances , Weights , Volumes & Times to one another, but only
within units of the same category, which are shown below. E.g.: 1 mi in ft

 Distances: ft cm mm mi m yd km in
   Weights: lb mg kg oz g
   Volumes: floz qt cup mL L gal pint

Convert [AMT SOURCE_UNIT in DEST_UNIT, or (q)uit]: 10 mi in m
10 mi = 16093.440000 m

Convert (AMT SOURCE_UNIT in DEST_UNIT, or (q)uit): 1 lb in oz
1 lb = 16.000000 oz

Convert [AMT SOURCE_UNIT in DEST_UNIT, or (q)uit]: 123.456789 kg in mg
123.456789 kg = 123456789.000000 mg

Convert (AMT SOURCE_UNIT in DEST_UNIT, or (q)uit): q
Thanks for converting with us. Y'all come back now, y'hear?
computer%

Hints

How should you store all of the multiplying factors between units? There's the hard way and the easy way to think about it. The particular Python data type you should use is something you should consider on your own.

The hard way

The hard way is to build an internal two-dimensional table of the conversion of every unit to every other unit for every category. This is really painful. Imagine how many translators the United Nations would need if they had 1,000 people speaking different languages and they used this model...a million people!

The easy way

The easy way is to find a common, base unit (e.g., meters for distances) and then just store the constant (e.g., 1000 for kilometers) that is used to convert from the base unit to that unit. To convert from two units in the same category (neither of which are the base unit), you simply convert from your SOURCE_UNIT to the base unit, then from that to the DESTINATION_UNIT. Using the previous analogy you'd only need to hire 1,000 translators at the UN -- as long as each could translate to and from their language to a common language, like one of the click languages. For the math-minded among you, the reason this works is that the conversion among all of our units is a Linear, Transitive relation.

Testing

Test each function in your program with enough different inputs to show that it works. When testing a function, print out the input, the expected result, and the actual result.

Extra for Experts

There are a couple of cool features you can add to make your program sing:

If you really had fun with this project, you might want to think about what is involved in translating one human language to another and how you'd go about writing a program to do that. Enjoy!

Checklist

These are the requirements to meet for project completion.