Skip to main content

$DECIMAL (ObjectScript)

Returns a number converted to an InterSystems IRIS floating point value.

Synopsis

$DECIMAL(num,n)

Arguments

Argument Description
num The numeric value to be converted. Commonly this is an IEEE Binary floating point number.
n Optional — An integer that specifies the number of significant digits to return. $DECIMAL rounds the value to that number of significant digits and returns a canonical numeric string. Valid values are 1 through 38, and 0. See below for details on 0 value. If n is greater than 38, an <ILLEGAL VALUE> error is generated.

Description

$DECIMAL returns a number converted to the InterSystems IRIS decimal floating-point data type. This function is used to convert a number in IEEE double-precision (64-bit) binary floating-point format to the corresponding number in InterSystems IRIS decimal floating-point format. This is the inverse of the operation performed by the $DOUBLE function.

IEEE floating point numbers are represented internally using binary bits. Because most fractional decimal numbers have no exact binary representation, a fractional number in IEEE Binary ($DOUBLE) format will usually differ slightly from its $DECIMAL conversion. InterSystems Decimal numbers have greater precision than IEEE Binary numbers. IEEE Binary numbers can represent more digits than Decimal numbers. Because most systems can perform binary arithmetic using IEEE numbers, this numeric format is preferred for rapid calculations. For details on the internal representation and precision of these numeric formats, refer to Floating Point Numbers.

The InterSystems IRIS SQL data types DOUBLE and DOUBLE PRECISION represent IEEE Binary floating point numbers; the NUMERIC data type represents standard InterSystems IRIS Decimal floating point numbers.

The num value can be specified as a number or a numeric string. If the num value is outside of the range of values that can be converted to an InterSystems Decimal number, $DECIMAL generates a <MAXNUMBER> error.

$DECIMAL returns a numeric value in canonical form.

Rounding

Specifying $DECIMAL(num,n) where n is between 1 and 38 (inclusive) returns a canonical numeric string with no more than n significant digits. When num is an ObjectScript Decimal it returns at most 19 significant decimal digits. When num is an IEEE Binary the input can have more than 1000 significant decimal digits, although $DECIMAL(num,n) will not display more than 38 significant digits.

Note that a canonical numeric string will not have leading zeroes before the decimal point or trailing zeroes after the decimal point.

Although $DECIMAL(num,n) never displays more than 38 significant digits, the $FNUMBER function can be used to display more significant digits on an IEEE Binary value. The $DOUBLE function will only look at the first 38 significant digits when given a string with a long sequence of significant digits.

Rounding is done as follows:

  • If n is not specified and num has more than 19 significant digits, $DECIMAL rounds the number and returns an InterSystems Decimal number with either 18 or 19 significant digits. $DECIMAL always rounds to the greater absolute value. There is an exception when the value to be converted to ObjectScript Decimal falls between the range of 18-digit precision and 19-digit precision. In this case, the result is the larger 18 digit value. The following example shows a number with 20 significant digits which $DECIMAL(num) rounds to 19 significant digits:

    USER>w $DOUBLE(12345678901234567890123456789)
    12345678901234568227000000000
    USER>w $DECIMAL($DOUBLE(12345678901234567890123456789))
    12345678901234568230000000000
  • If n is a positive integer, rounding is done using the IEEE rounding standard. $DECIMAL returns a Decimal number as a numeric string in canonical form. If num has more than 38 significant digits (and n=38) $DECIMAL rounds the fractional portion of the number at the 38th digit and represents all of the following num digits with zeros.

  • If n=0, $DECIMAL returns a Decimal number as a numeric string in canonical form as follows:

    • If n=0 and the Decimal value corresponding to num is 20 digits or less, $DECIMAL returns that value.

    • If n=0 and the Decimal value corresponding to num is more than 20 digits, special rounding (not IEEE rounding) is performed, as follows: The decimal string value is truncated to 20 significant digits. If the 20th digit is not a "5" or "0" then that truncated number with 20 significant digits is the result. If the 20th digit is a "5" or "0", the 20th digit is replaced with a "6" or "1" respectively, and that 20 digit numeric string is the result. This special rounding prevents “double rounding” errors if the result is later rounded to less than 20 digits. This is shown in the following example:

      USER>WRITE $DECIMAL($DOUBLE(123456789012345678901234567),20)
      123456789012345678150000000
      USER>WRITE $DECIMAL($DOUBLE(123456789012345678901234567),0)
      123456789012345678160000000

Integer Divide

With certain values, InterSystems IRIS decimal floating-point and IEEE double numbers yield a different integer divide product. For example:

  WRITE !,"Integer divide operations:"
  WRITE !,"IRIS  \: ",$DECIMAL(4.1)\.01  // 410
  WRITE !,"Double \: ",$DOUBLE(4.1)\.01   // 409

For further details on arithmetic operations involving IEEE double numbers, see the appendix “Numeric Computing in InterSystems Applications” in the Orientation Guide for Server-Side Programming.

INF and NAN

If num is INF, a <MAXNUMBER> error is generated. If num is NAN, an <ILLEGAL VALUE> error is generated. These invalid values are shown in the following example:

  SET i=$DOUBLE("INF")
  SET n=$DOUBLE("NAN")
  WRITE $DECIMAL(i),!
  WRITE $DECIMAL(n)

Examples

The following example demonstrates that $DECIMAL has no effect when applied to a fractional number that is already in InterSystems IRIS format:

  SET x=$DECIMAL($ZPI)
  SET y=$ZPI
    IF x=y { WRITE !,"Identical:"
             WRITE !,"IRIS $DECIMAL: ",x
             WRITE !,"Native IRIS:   ",y }
   ELSE { WRITE !,"Different:"
          WRITE !,"IRIS $DECIMAL: ",x
          WRITE !,"Native IRIS:   ",y }

The following example returns the value of pi as a $DOUBLE value and as a standard InterSystems IRIS numeric value. This example shows that equality operations should not be attempted between $DOUBLE and standard InterSystems IRIS numbers, and that equivalence cannot be restored by using $DECIMAL to convert IEEE back to InterSystems IRIS:

  SET x=$DECIMAL($ZPI)
  SET y=$DOUBLE($ZPI)
  SET z=$DECIMAL(y)
  IF x=y { WRITE !,"IRIS & IEEE Same" }
  ELSEIF x=z { WRITE !,"IRIS & IEEE-to-IRIS same" }
  ELSE { WRITE !,"All three different"
         WRITE !,"IRIS decimal: ",x
         WRITE !,"IEEE float:    ",y
         WRITE !,"IEEE to IRIS: ",z }

The following example returns the $DECIMAL conversion of pi as a $DOUBLE value. These conversions are rounded by different n argument values:

  SET x=$DOUBLE($ZPI)
  WRITE !,$DECIMAL(x)
   /* returns 3.141592653589793116 (19 digits) */
  WRITE !,$DECIMAL(x,1)
   /* returns 3 */
  WRITE !,$DECIMAL(x,8)
   /* returns 3.1415927 (note rounding) */
  WRITE !,$DECIMAL(x,12)
   /* returns 3.14159265359 (note rounding) */
  WRITE !,$DECIMAL(x,18)
   /* returns 3.14159265358979312 */
  WRITE !,$DECIMAL(x,19)
   /* returns 3.141592653589793116 (19 digits) */
  WRITE !,$DECIMAL(x,20)
   /* returns 3.141592653589793116 (19 digits) */
  WRITE !,$DECIMAL(x,21)
   /* returns 3.141592653589793116 (19 digits) */
  WRITE !,$DECIMAL(x,0)
   /* returns 3.1415926535897931159 (20 digits) */

See Also

Feedback