BCD data type

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.

Base 2 versus base 10

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.)

Limited size versus unlimited size

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 versus fixed point

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.

Mixing BCD and integer values

You can mix integer variables and BCD variables in mathematical expressions. Thus, you can write:

  process
     local integer quantity
     local bcd     price
     local bcd     total
  
     set total to quantity * price

You can also choose to use the BCD data type for integer values:

  process
     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 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

Supported operators

You can use the following operators with BCD numbers:

Handling BCD errors

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"
        put #log "Error " || error-code || " " || error-message || "%n" || error-location || "%n"
  
     else
        rethrow
     done
  ; Output: Error BCD0002 '-332.33A' is not a legal bcd number.
  ;         On line 9 in file test055.xom.

Related Topics