The BCD (binary coded decimal) data type allows you to store numbers in binary coded decimal form. This means that the numbers behave exactly like the decimal numbers you learned about in grade school and that decimal fractions behave exactly like the decimal fractions you learned about in grade eight.
BCD numbers are unlimited in size. They have an accuracy of 16 places past the decimal point. Fractional results of BCD calculations which result in more than 16 digits past the decimal point are truncated to 16 digits.
BCD numbers are particularly appropriate for commerce applications. They eliminate the problems of rounding errors inherent in using floating point numbers for financial calculations.
BCD numbers are generally superior to floating point numbers for most applications. Why should you use BCD numbers rather than floating point numbers? There are three principal differences.
BCD data type formatting lets you display prices with dollar signs or British pound signs, and lets you control how decimals are displayed and whether large numbers are separated every three digits by commas or spaces or left unchanged.
Floating point numbers are represented internally as binary (base 2) numbers. They provide accurate representation of fractional numbers that are powers of 2 (1/2, 1/4, 1/8, 1/16, and so forth), but they do not provide accurate representation of fractions that are powers of 10 (1/10, 1/100, 1/1000). Any fraction that can be precisely represented in base 2 can be precisely represented in base 10, but not vice versa. (There are, of course, many fractions that cannot be precisely represented in either base 2 or base 10—1/3 for example.)
Floating point numbers are of a limited size and are represented by a fixed number of bytes of memory. BCD numbers, as implemented by the OmniMark BCD library, are of unlimited size.
Floating point numbers, as their name implies, have a floating decimal point. That is, floating point numbers have a fixed number of significant bits which are distributed between the whole number portion and the fractional portion of the number. The larger the whole number portion of the number, the fewer bits are available for the fractional part.
BCD numbers, as implemented by the OmniMark BCD library, have a fixed number of digits past the decimal point. The limit is 16 digits. Thus, BCD numbers give you unlimited digits to the left of the decimal point and 16 digits to the right of the decimal point.
You can mix integer variables and BCD variables in mathematical expressions. Thus, you can write:
process local bcd price local bcd total local integer quantity set total to quantity * price
You can also choose to use the BCD data type for integer values:
local bcd price local bcd quantity local bcd total set total to quantity * price
Note that if you perform an operation on two integers and assign the result to a BCD, the operation will be done as an integer operation and the result will be coerced to a BCD. Thus the following code will fail, even though a BCD can hold the result of 1000000 * 2000000:
process local integer large initial {1000000} local integer larger initial {2000000} local bcd largest set largest to bcd (large * larger)
In this case, the result of the integer operation large * larger
will overflow before the coercion to BCD. The correct way to code this operation is to force one of the operands to BCD before the operation is performed. This causes the operation to be performed as a BCD operation, returning a BCD value:
process local integer large initial {1000000} local integer larger initial {2000000} local bcd largest set largest to bcd large * larger
You can use the following operators with BCD numbers:
In the event of an error in a calculation, the BCD library will throw a #external-exception
. You can catch external exceptions and take the appropriate action:
import "ombcd.xmd" unprefixed global bcd total initial {111.03} process submit "-332.33A" find ("-"? (digit+ ".")? digit+ letter?) => decimal-number set total to total + bcd decimal-number output "Total = " || "<$,NNZ.ZZ>" % total catch #external-exception identity error-code message error-message location error-location do scan error-code match "BCD" log-message ("Error " || error-code || " " || error-message || " at " || error-location || ".%n") else rethrow done ; Output: "Error BCD0002 '-332.33A' is not a legal bcd number. at On line 7 in file ; C:\omprogs\bcdcatch.xom.."