DECIMAL(p,s)

The DECIMAL data type is provided to handle large numeric values with exact decimal storage.

Syntax

DECIMAL [ ( precision[,scale]) ]
  1. precision defines the number of significant digits (limit is 32, default is 16).
  2. scale defines the number of digits to the right of the decimal point.
  3. When no scale is specified, the data type defines a floating point number.
  4. When no (precision, scale) is specified, it defaults to DECIMAL(16).

Usage

Use the DECIMAL data type when you need to store values that have a fixed number of digits on the right and left of the decimal point (DECIMAL(p,s)), or to store a floating point decimal with an exact number of significant digits (DECIMAL(p)).

DEC, DECIMAL and NUMERIC are synonyms.

DECIMAL variables are initialized to NULL in functions, modules and globals.

When using DECIMAL(p,s) with a precision and scale, you define a decimal for fixed point arithmetic, with p significant digits and s digits on the right of the decimal point. For example, DECIMAL(8,2) can hold the value 123456.78 (8 (p) = 6 digits on the left + 2 (s) digits on the right of the decimal point).

When using DECIMAL(p) with a precision but no scale, you define a floating-point number with p significant digits. For example, DECIMAL(8) can store 12345678, as well as 0.12345678.
Note:

In most database implementations, the decimal data type always has a fixed number of decimal digits. Use DECIMAL types with precision and scale to implement portable code, and avoid mistakes if default sizes apply when precisions and/or scale are omitted in SQL statements. For example, with Oracle®, a NUMBER(p) is equivalent to a DECIMAL(p,0) in BDL, not DECIMAL(p).

When using DECIMAL without a precision and scale, it defaults to DECIMAL(16), a floating-point number with a precision of 16 digits.

MAIN
  DEFINE d1 DECIMAL(10,4)
  DEFINE d2 DECIMAL(10,3)
  LET d1 = 1234.4567
  LET d2 = d1 / 3 -- Rounds decimals to 3 digits 
  DISPLAY d1, d2
END MAIN

DECIMAL values can be converted to strings based on the DBFORMAT (or DBMONEY) environment variable (defines the decimal separator) setting.

Value ranges

The largest absolute value that a DECIMAL(p,s) can store without errors is 10p-s - 10s. The stored value can have up to 30 significant decimal digits in its fractional part, or up to 32 digits to the left of the decimal point.

When using DECIMAL(p,s) the range of values is defined by the p, the number of significant digits. For example, a variable defined as DECIMAL(5,3) can store values in the range -99.999 to 99.999. The smallest positive non zero value is 0.001.

When using DECIMAL(p) the magnitude can range from -N*10-124 to N*10124, where N can have up to p significant digits and be 0<N<10. For example, a variable defined as DECIMAL(5) can store values in the range -9.9999e-124 to 9.9999e+124. The smallest positive non zero value is 9.9999e-130.

Exceptions

When the default exception handler is used, if you try to assign a value larger than the decimal definition (for example, 12345.45 into DECIMAL(4,2) ), no out of range error occurs, and the variable is assigned with NULL. If WHENEVER ANY ERROR is used, it raises error -1226. If you do not use WHENEVER ANY ERROR, the status variable is not set to -1226.

Data type conversion can be controlled by catching the runtime exceptions. For more details, see Handling type conversion errors.

Computation and rounding rules

When computing or converting decimal values, the "round half away from zero" rule will apply: If the fraction of the value v is exactly 0.5, then r = v + 0.5 if v is positive, and r = v - 0.5 if v is negative. For example, when the result must be rounded to a whole number, 23.5 gets rounded to 24, and -23.5 gets rounded to -24.

In the next example, the division result of 11 / 3 gives the infinite decimal value 3.666666... (with an infinite decimal part). However, this value cannot be stored in a fixed point decimal type. When stored in a DECIMAL(10,2), the value will be rounded to 3.67, and when multiplying 3.67 by 3, the result will be 11.01, instead of 11:

MAIN
    DEFINE v DECIMAL(10,2)
    LET v = 11 / 3
    DISPLAY "1. v = ", v USING "---&.&&&&&&&&"
    LET v = v * 3
    DISPLAY "2. v = ", v USING "---&.&&&&&&&&"
END MAIN
Output:
1. v =    3.67000000
2. v =   11.01000000

High-precision math functions

A couple of precision math functions are available, to be used with DECIMAL values. These functions have a higher precision as the standard C library functions based on C double data type, which is equivalent to FLOAT: