Introduction

I usually build localizable web sites, sometimes I need to store values from different sources. Some metric, others not. A solution can be storing all values as metric, then convert to show them, easy but conversions among most different measurement systems aren’t exact so converted numbers look pretty ugly. This project allows you to store values along with unit information and conversion between different measurement systems. It also provides a hierarchy to create new converters easily.

All conversion constants used are not warranted to be the best, so be careful using results. I will show how to use this library with your own constants.

A Measurement Unit

I needed both to convert a value and knowing which unit a value represents. Then I needed this value to be stored easily on a database without using serialization or SQL User defined types which require assembly registration, not available in some web hostings. The easiest solution I could think of: use 32bit integer for unit description and 32bit for a floating point value, more than enough for all existing measurement units, and I think enough for most actual life values. Values would be stored in databases as 64 bit integers.

Units are represented by their Name, Symbol and Plural form for their name. Also they have a unique identifier within a table, described later. As they are supposed to be stored as integers, they have a property to convert them to and from Int64. Units are bound to tables, this way they only store information about their code and value, no strings no conversions, everything else they get from their tables.

A Unit Table

It is a table holding a set of measurement units and their conversions. Current implementations include XML initialization and resource localization.

Table instances can be used directly in order to get unit name, symbol, plural forms or converters, converters are explained later.

Hello World

Let’s suppose we have a table with the units: Meters, Centimeters, Feet and Inches, and all their conversions: Meters to Centimeters, Meters to Feet, Feet to Inches, and so on.

In this code excerpt, we take a predefined table named LengthTable, which contains some length measurement units and all cross conversions possible. Then we create 2 units, first represents 100 meters (m) the other 120 inches (in). Then we print 100 meters converted to centimeters, feet and inches, and later 120 inches converted to meters, centimeters and feet. You actually need to remember the codes you assigned to units when you first created the table, you could use const or enum to do this task easily. It is up to you.

The output from running previous sample was:

10000cm
328.0839ft
3937in
3.048006m
304.8006cm
10ft

XmlTables

This is a clean and simple way to define units and conversions. Cross conversions can be a nightmare, I’m working on a Windows application to fill these files, but as I’m really bad building these kinds of applications, you should learn to write by yourself.

Looks simple? It is. Let’s explain it anyway. Unit elements define units: code, name, international symbol and plural form. Linear element define a simple y = ax + b conversion, x will be source unit specified on srcCode attribute, y will be destination unit specified on destCode attribute, “a” will be “factor” and “deltha” which is not used on any of these conversions will be “b”. Parameter “deltha” is no very common as most measurement units have a very distinguished zero, some others don’t, take for instance temperature. In case conversions you need are not linear, you might use a Custom element (which is described later) instead. Both “factor” and “deltha” are double so you can use really precise constants.

If we use this excerpt instead of the one we use before, we will get the same result. XmlUnitTable constructor overloads support XmlDocument and Stream also.

A Decibel converter was also implemented, but as I’m not really sure what it can be used on, I won’t risk myself to ridicule and won’t use any sample. The idea is y = 10 log (X / Reference), Inverse is implemented but internal, so you might only use the Logarithmic implementation.

Decibel’s usage on an XML table file:

...
<Conversions><DecibelsrcCode="1"destCode="2"reference="0.1"/>
...

Localized Tables

The main task for me, it would be useless for a web site if it isn’t localizable. This is a XmlUnitTable heir which also takes a ResourceManager and uses the values in name and plural as keys to get the actual one from the manager.

Now unit names and plurals are culture dependant, we could get “meters” in English, “metros” in Spanish and so on, we just need to write a resources file for each language. Unit symbols are not localizable because they are supposed to be international. I’m not completely but pretty sure they write “m” for meter in China, Russia, Israel, Greece or any other country not using the Latin alphabet. A Default resource manager is distributed along with the library, just in case you don’t want to write your own.

Converters

These are the real hard working guys from this library. Converters are formulas that convert from one unit to another one. You should ask a table for the correct formula; once you have it you can convert as many values as you want. You can also ask the Unit to convert itself and it will do the table asking thing for you. Some converters might be invertible, maybe all of them, but as I was writing this program, I didn’t have time to make a whole mathematical demonstration about if there might or not be a non-invertible formula to convert units, so converters have a property to ask them whether they can be or not inverted and a property to get the inverse. This way, if you define a converter from miles to meters, you don’t need to define one for meters to miles. The table will use the first one’s inverse to do the job. Anyway you can define both, explicit converters have priority over implicit ones.

The current implementation includes a linear converter which can be inverted if factor isn’t zero, although it doesn’t make any sense because it would represent a constant conversion. It means factor equal zero is forbidden, don’t worry exceptions will make sure you don’t make the mistake.

Implementing Custom Converters

These classes can be used on the XmlTable and its heirs. They should have a public parameterless constructor and should be able to initialize themselves from a XmlElement.

This table defines a custom converter of type HypotheticalCustomConverter. You should specify its name and as much information as you like in XML attributes. Using the method XmlInitialize, the converter should be able to take information from attributes and initialize itself.

In the following example, we create custom converter, I used an hypothetical situation because I can’t think right now about any actual custom converter.

I used Celsius and PCelsius instead of Degree Celsius and Degrees Fahrenheit to be able to use them as resource keys which cannot contain spaces, it means this file is intended to be used by LocalizedXmlUnitTable instances.

Currency Conversion

By definition they are linear conversions, except they are always changing. I built some classes to be able to download some rates from the internet or from a local XML file. You can always create some program creating an updated table file using linear conversions. This is just another way. There is a problem about using this library on currencies. Values are stored as float, which lose ciphers on rounding, so, NO serious financial applications should rely on my currency conversions. Currency conversion should be done using decimals. Maybe for future releases, I’ll think of a way to do both float and decimal, right now it is only float.

For currencies, it is easier to work with string constants, and as codes are auto assigned, there is no choice. Currencies tables should support creating units and getting unit codes from string constants. This table is a proxy for a rate provider, which actually gets rates from the web or some file, or any other source.

Rate Provider

Based on interface ICurrencyExchangeRatesProvider provides a way to get exchange rates from anywhere. This library contains a cached version and an online one.

Web Rates Provider

My default implementation for an online rates provider. It connects to a web site and applies an XSLT transformation to some XML source data to convert it into a DataSet compliant XML, then reads the DataSet. An XSLT for a default web site is provided.

The DataSet layout must be:

<Rates><Rate><Currency>United States Dollar</Currency><Exchange>1.4482</Exchange><Symbol>USD</Symbol></Rate><Rate><Currency>Euro</Currency><Exchange>1</Exchange><Symbol>EUR</Symbol></Rate></Rates>

To use this class on other than my default provider, you should create an XSLT file and use the following code:

I am at the point where I am starting to use your Unit Conversion Library in my application. My application is a vehicle End Of Line tester that will sample data from an external serial device and display the results on the screen in a linear gauge in whatever units the user chooses to display them in. The rate at which I display the data from the external serial device on the screen is 10 times a second.

I started to use your library in my Windows Universal App and it looks great, but i wonder how to get the number of units in a table. This will be especially usefull if reading an xml file.
I tried to use "IsKnownUnit" but it always returns false. So what is IsKnownUnit intended to do and how can I get the number of Units in a table?

EDIT: Ok, my mistake. I always tried with index 0, but it starts at 1 in your library.

I noticed that UnitTable has by default the predefined tables like LengthTable, etc.
I would add a table of mine, called ForceUnits.xml, but instead of loading it in my program I just want to have it in DLL as built-in. In other words, to have UnitTable.ForceTable.

Once upon a time, I had to do the same stuff, including unit-conversions and some basic math

My approach was to build some ratio classes, and overload the operations, in this way you create a new class
which information is a scalar and a name-collection, each with its exponent.
the rest is only do some math upon the named-exponents.

Then I defined a factory, where all relations are inside, and (imported/collected) over 900 international units relations

This is good!! 900 conversions are impresive. I just have a sugestion on your approach: factor and delta would allow only linear conversions, there could be other conversion funcions: higher degree polinomials, logarithms. Today, if I would rebuild this library I would use a Func<double> or a linq Expression.

You just need to create your very own CustomConverter which would work with expressions. You'll also need a mechanism to deserialize expressions from text....unfortunately there is no automatic way of creating the xml.

Getting a structured&populated class set out from an algebraic-expression is really easy, you can start with any parser, LALR, LR, LL, LL(k)., etc. There is plenty of information about this.

A good start is CUP (Java) there are many ports towards C#, seek VSCUP, a guy in hong hong dod this! (or try the automated conversion from java to C# in Vs2005) it works perfect. then you got a Parser-Generator, capable of creating any compiler you need!

Even in C# there are Vs-CoCo versions, (searh for the LL(k) parser for C#, here in CodeProject).

The simplest included-example, do parse a math expression (numeric); then, just adding literals is piece-of-cake!, functions are a little more complicated, but not impossible. To do that, just search some mathe-parser implementations here in this forum, many are self-explaining, get the idea out of there, then use your parser-generator.

And the result?

- The result is far more efficient and non-error-prone than something you do-by-yourself (by coding)!

From this structured class-netork (Abstract syntax tree) you can apply some simple algorithms to find the inverse, or create a XML to do just the convesion (what was meant impossible obthe comment above). As simple as that!

Just don't fear deep computing & coding... or we all will be doomed and fried!

Hi, I also thought that this would be an issue, to make only linear (ax+b) expression.
but let me take you to the main problem, if you use any other than a 2nd-degre polinomial, or even a text-parsed math-expression. You'll be faced with a far more complicated problem: the inverse conversion!

Once you get the forward conversion, you can program the inverse, but what if the equation has not an algebraic-root, or has more than one?

With linear mapping, you can go from ºF to ºC forward and backward, but if you have a quadratic conversion, foward is as you state x² but backwards means a square root, and this means 2 possible ways, so the conversion function is not biyective (2-way) and the whole thing will fail at concept level.

I did some expression-level to decode the conversions, indeed my library takes only linear-equation formats, stated in text at the conversion definitions, adn parses them into a hardwired reversible-formulae, just that.

You are absolutely right...there is a problem with higher degree polynomials. Though, I think that would all zero if we are talking about actual meassurement units which support inverse in real life. Either way, the choise is there for extensibility purposes. If does not work for a certain case, just don't use it for that case.