Handling Value Unit data

We have some data that is strongly bound to each other and we are using it for calculations. Its a value with a unit type and an optional relation. E.g. 1500 meter above sea level. The unit type should be replaceable (meter to foot). But the value should be converted accordingly.

I am currently thinking of two approaches:

Approach 1 saves the value in a fixed unit to the database without an conversion. The conversion would be made on the fly after loading the value with its prefered unit type. e.g. always saved in meter, but will be displayed in foot if the unit was changed + This prohibits problems from converting the value back and forth while causing rounding errors. + Calculations with the data can be done without converting it, since the saved value is always in meter - If you enter a value in foot but save it as meter and reload it, it could show not the value you entered because of a rounding error.

Approach 2 saves the value in the selected unit. But that switches the advantages with the disadvantages. And it would make it probably hard to choose a good databasetype for saving it since the unit is not always the same.

I tried to find how other people work with this kind of relation but since "unit" is a pretty strong word i can't find anything related to my problem. But I think this value/unit data structure is not so rare.

• How should I approach this kind of data?
• How should I save and load it?
• When should I convert the data?
• Am I missing some problems that could influence my decision?

This can get tricky because repeatedly converting between units can accumulate rounding errors.

For example, taking a value in meters, converting to feet, and back to meters might show a slight error such as 1 meter and 0.9999 meters. Or, for a less obvious example, 4.587 meters converting to feet and back might give 4.585 meters.

The more you change values, the more inaccurate they may be. Since Computer Science often looks at minimizing the worst case, we need to assume the worst in order to show the value can never deviate more than a certain amount.

To achieve this goal, you should always store the value in the most precise way possible, and convert on the fly as needed and never more than once.

I would store `amount` and `unit` fields representing e.g. "4.5 meters" and always use that as a base. If I need feet, then convert it to feet: if I need miles, convert meters to miles, not meters to feet to miles.

Approach two may be more computationally-intensive in the long run, but it is more accurate. Given these computations are not exactly complex or expensive to begin with and that modern computers are extremely powerful, I would sacrifice efficiency for accuracy.

I also recommend setting up a conversion table using as much precision as possible. This will never change unless new units are added, so a static, high-precision table is a safe bet and will help ensure consistency and accuracy.

• "...you should always store the value in the most precise way possible, and convert on the fly as needed and never more than once." i totally agree with Snow about this. it appears that the original data is measured once, and thus should be stored once and never written over again. conversion to the user's preference is done on the fly from the original value and is thus limited in number of roundoff operations to 1. i presume that the data is stored in floating-point format, so it should not matter which units are used. use Planck Units if you like. :-) – robert bristow-johnson Dec 16 '15 at 22:54
• while the storage and conversion should be as precise as possible, the display to the user should be reduced to a number of digits that is meaningful to the user regarding the number of significant digits in the measurement. so the original value stored in the database has many more digits than the number of significant digits. scaling that to the user's preferred unit will affect the precision only at the very end. but when displayed, any value of "0.9999999" will be displayed as the rounded "1.000" if 4 significant digits accurately reflects the precision of the original data. – robert bristow-johnson Dec 16 '15 at 22:59

I believe the term you're looking for is "unit of measure" as that more clearly conveys the concept of a value and some sort of units associated with the value.

And as you're starting to see, there are quite a few approaches to handling the challenges you're running into.

For runtime operations, the solutions range from just using "implied" units, having the units built into the variable name, having a separate property for the units, to using an object or class that presents as an actual unit of measure (e.g. value and unit combined). There's a trade-off here between level of effort to implement, convert, and use against the risks of failure within your code.

Database operations are a bit more difficult to categorize with the primary challenge being the inability to represent an actual unit of measure. I have seen solutions using implied" units and units attached to the column name.

I have also seen using a second column to represent the units. Depending upon how you structure that, that column could be a simple string representation or it could be a foreign key index into another fixed table indicating unit type.

The first thing you need to do is assess how much of an impact this has upon your codebase. If you're using a lot of units and doing a lot of conversions, then you'll likely want a more robust solution. Vice versa, if this only crops up every now and then, you may be able to get away with a simpler solution.

I would avoid performing a lot of unnecessary conversions, if possible. As you noted, it does introduce error which can throw off calculations. Generally, pick the most commonly used form and use that as your "base unit" to work from. But temper that advice based upon the particulars of what you're doing and realize that you don't have to strictly follow normalization rules if it simplifies your initial design and long term maintenance.

Store the unit and the value separately, do not perform conversion unless it is necessary (eg. calculating weight for shipping, the user requests it, etc.).

Not all units can be converted from one to another

Consider an database for a grocery store. All of the products they sell have a specific measurement, but not the same type of measurement.

• Most goods are labeled by weight (2 lb)
• Liquids are labeled by volume (500 ml)
• Cookware is labeled in length (9x9x3 inches for a jellyroll pan, but 9 inches in diameter for a skillet)

Google won't even try to convert between weight and volume units (at least not in a general way, you'd need a conversion table for every type of product).

Users may prefer one type of unit over another in specific contexts

Even in cases where all of your units can be converted from one to another, there are plenty of cases where specific units are customary for certain types of data. For smaller quantities, a smaller unit is usually preferred. The same is true for larger quantities and larger units.

• At the fabric store, I'll buy fabric by the yard (Imperial) or meter (Metric), but I expect my buttons to be labeled in fractions of an inch or millimeters (the same is true for lumber and nails at the hardware store)
• Even in countries that are fully metric or fully Imperial, you'll find edge cases like 2L bottles of pop in the U.S. or recipes in Canada that use cups and tablespoons
• The deli counters here in Canada usually label their products by 100 grams (I guess the hectogram never caught on?) while other products within the same store that are measured by weight will use kilograms
• I think this answers a slightly different question than the one asked. A volume and a mass are two distinct physical quantities and cannot be converted to/from each other as you explained. But an elevation in meters and an elevation in feet both represent the physical quantity length. And while you wouldn't ask “Is this toothpaste more than this these potatoes?” it is perfectly reasonable to ask “Is Las Vegas (610 m above sea level) at greater altitude than Chicago (594 ft above sea level)?”. – 5gon12eder Dec 16 '15 at 21:36
• @5gon12eder Which the other part of the answer addresses? – cimmanon Dec 16 '15 at 21:52