Show Me The Money!
For eons, MultiValue programmers have used the "MR2" and "MD2" conversions for formatting money values. While this conversion is perfect for converting a stored money amount to something human-readable — for those of us with a decimal currency, that is — there are a surprising number of developers unaware that this code can do much more.
Whether formatting a money, decimal, date, time, alphanumeric, or other type of value, all of the conversion features of the MultiValue platform are worthy of continued study. In UniData, conversion codes are documented with the ICONV(..) and OCONV(..) functions in the BASIC Reference, but with conversions being a crucial feature of dictionaries and the query language you may find more information about conversions just about anywhere in a documentation bundle.
Today let's take a brief glance at the "MR2" conversion code. Years ago it was explained to me that the "M" and "R" mean "mask" and "right justified" and the following "2" means "show two decimal places". While accurate, it missed a very important detail: There's a digit missing!
The "MR" conversion code — as well as its kissing cousin "MD" (Mask Decimal) and even "ML" (Mask Left) — can be followed by two separate number parameters. The first number is the number of decimals to show, and the second is the number of positions to scale (move) the decimal point. For example, a conversion of "MR2" is really an abbreviation of "MR22", which means to show two decimal points after scaling the decimal by two positions. Similarly "MD4" will show four decimal places after scaling the number by four decimal places. (In an OCONV the decimal moves to the left; in an ICONV the decimal moves to the right.)
So what's the big deal? If not typing that second digit saves you a keystroke and it just works, why should you care? On the other hand, what if you want to show a certain number of decimals but scale the number differently?
Let's say for instance we're building a report program that's reading a list of payment amounts from a text file. As we look at the text file we instantly notice that the payment amounts are unpredictably formatted, like this:
23 5.2 325.46 6432.236
To output these on our report we need to convert these values so that each payment amount has two decimal places, no more, no less. Throughout the years I've seen a number of ways to achieve this in code, the most common being to input convert the raw value by two decimal places, and then output convert that result by two decimals, like this:
VALUE = OCONV(ICONV(IN.VALUE,'MR2'),'MR2')
While this does the trick, wouldn't it be cool if we could do it all with a single conversion? With separate show and scale numbers in our "MR" conversion, we can do exactly that:
VALUE = OCONV(IN.VALUE,'MR20')
In this example, the "MR20" says to mask the number, right justified (though the justification doesn't matter, see sidebar), show two decimal places, but scale the decimal by zero places. In other words, the decimal won't move and we'll still get our two decimal places in the human-readable output.
Looking at this from a different perspective, what if we want to take a number that is stored with two decimal places and show it in thousands with no decimal places? For our example, let's say the stored value is "12345678" which represents "123456.78". For our report, we want to show this value simply as 123. We certainly could OCONV the input value using the "MR5" conversion to format the number as "123.45678" and then use an "MR0" conversion to scale this to "123", but why do it with two conversions when we can do it with a single "MR05"?
While this is just one of many options available with of the MR, MD, and ML conversion codes, it's a significant detail that can simplify the transformation of numbers from one base and format to another in a single operation. There are many other options for adding commas, dollar signs, asterisks, and padding, so if you're interested, dig into the manual and see all that these conversion codes have to offer.
Did You Know?
As an output conversion, MR2, ML2, and MD2 are nearly, if not entirely, identical depending on the MultiValue platform in use. The justification code (R, L, or D) means nothing unless the number has fill and width parameters, such as MR2%10 or ML2#10, where the "%" represents "fill with zeroes" and the "#" represents "fill with spaces," both in a field of 10 characters.