$DOUBLE (ObjectScript)
Synopsis
$DOUBLE(num)
Argument
Argument | Description |
---|---|
num | The numeric value to be converted. You can also specify the strings “NAN” and “INF” (and their variants). |
Description
$DOUBLE returns a number converted to the IEEE double-precision (64-bit) binary floating-point data type (also known as the InterSystems $DOUBLE format, which corresponds to the DOUBLE and DOUBLE PRECISION SQL data types). This is the inverse of the operation performed by the $DECIMAL function
A $DOUBLE format number can contain up to 20 digits. If num has more than 20 digits, $DOUBLE rounds the fractional portion to the appropriate number of digits. If the integer portion of num is more than 20 digits, $DOUBLE rounds the integer to 20 significant digits and represents the additional digits with zeros.
A fractional number in $DOUBLE format usually differs slightly from its decimal conversion. See Numeric Computing in InterSystems Applications.
An InterSystems IRIS numeric string literal that exceeds the min/max range supported by InterSystems IRIS floating-point data types (for example, “1E128”) is automatically converted to an IEEE double-precision floating-point number. This conversion is only performed on numeric literals; it is not performed on the results of mathematical operations. This automatic conversion can be controlled on a per-process basis using the TruncateOverflow()Opens in a new tab method of the %SYSTEM.ProcessOpens in a new tab class. The system-wide default behavior can be established by setting the TruncateOverflowOpens in a new tab property of the Config.MiscellaneousOpens in a new tab class.
The num value can be specified as a number or a numeric string. It is resolved to canonical form (leading and trailing zeros removed, multiple plus and minus signs resolved, etc.) before $DOUBLE conversion. Specifying a nonnumeric string to num returns 0. Specifying a mixed-numeric string (for example "7dwarves" or "7.5.4") to num truncates the input value at the first nonnumeric character then converts the numeric portion. A $DOUBLE numeric value supplied to a JSON array or JSON object follows different validation and conversion rules.
Equality Comparisons and Mixed Arithmetic
Because numbers generated by $DOUBLE are converted to a binary representation that does not correspond exactly to decimal digits, equality comparisons between $DOUBLE values and decimal values may yield unexpected results and should generally be avoided. See Numeric Computing in InterSystems Applications.
Integer Divide
With certain values, decimal and $DOUBLE numbers yield a different integer divide product. For example:
WRITE !,"Divide operations:"
WRITE !,"IRIS /: ",4.1/.01 // 410
WRITE !,"Double /: ",$DOUBLE(4.1)/.01 // 410
WRITE !,"Integer divide operations:"
WRITE !,"IRIS \: ",4.1\.01 // 410
WRITE !,"Double \: ",$DOUBLE(4.1)\.01 // 409
List Compression
ListFormat controls whether $DOUBLE numbers should be compressed when stored in a $LIST encoded string. The default is to not compress. Compressed format is automatically handled by InterSystems IRIS. Do not pass compressed lists to external clients, such as Java or C#, without verifying that they support the compressed format.
The per-process behavior can be controlled using the ListFormat()Opens in a new tab method of the %SYSTEM.ProcessOpens in a new tab class.
The system-wide default behavior can be established by setting the ListFormatOpens in a new tab property of the Config.MiscellaneousOpens in a new tab class or the InterSystems IRIS Management Portal, as follows: from System Administration, select Configuration, Additional Settings, Compatibility.
INF and NAN
Following the IEEE standard, $DOUBLE can return the strings INF (infinity) and NAN (not a number). INF can be positive or negative (INF and -INF); NAN is always unsigned. While these are valid IEEE return values, they are not actual numbers.
INF and NAN as Input Values
One way to cause $DOUBLE to return INF and NAN is to specify the corresponding string as the num input value. These input strings are not case-sensitive, and can take leading plus and minus signs (INF resolves signs, NAN ignores signs). To return NAN, specify “NAN”, “sNAN”, “+NAN”, “-NAN”. To return INF, specify “INF”, “+INF”, “Infinity”. To return -INF, specify “-INF”, “+-INF”.
IEEEError
IEEEError controls how $DOUBLE responds to a numeric conversion that cannot be resolved. If IEEEError is set to 0, $DOUBLE returns INF and NAN when it cannot resolve a conversion. If IEEEError is set to 1, $DOUBLE generates standard InterSystems IRIS error codes when it cannot resolve a conversion. The default is 1.
The per-process behavior can be controlled using the IEEEError()Opens in a new tab method of the %SYSTEM.ProcessOpens in a new tab class.
The system-wide default behavior can be established by setting the IEEEErrorOpens in a new tab property of the Config.MiscellaneousOpens in a new tab class or the InterSystems IRIS Management Portal, as follows: from System Administration, select Configuration, Additional Settings, Compatibility.
Returning INF and NAN
$DOUBLE can return INF and NAN when you specify an extremely large number, or when you specify an unresolvable arithmetic operation. These values are only returned when IEEEError is set to return INF and NAN.
Extremely large floating-point numbers are not supported. The maximum supported value for a $DOUBLE binary floating-point number is 1.7976931348623158079e308. The minimum supported value for a $DOUBLE binary floating-point number is 1.0E-323. A num value smaller than this returns 0.
The maximum supported value for an InterSystems IRIS decimal floating-point number is 9.223372036854775807e145. The minimum supported value for an InterSystems IRIS decimal floating-point number is either 2.2250738585072013831e-308 (normal) or 4.9406564584124654417e-324 (denormalized).
The following table shows the value returned or error generated by unresolvable arithmetic operations:
Input Value | IEEEError=0 | IEEEError=1 |
---|---|---|
> 1.0E308 | INF | <MAXNUMBER> |
< 1.0E-323 | 0 | 0 |
1/$DOUBLE(0) | INF | <DIVIDE> |
1/$DOUBLE(–0) | –INF | <DIVIDE> |
$DOUBLE(1)/0 | INF | <DIVIDE> |
$DOUBLE(0)/0 | NAN | <ILLEGAL VALUE> |
$ZLOG($DOUBLE(0)) | –INF | <DIVIDE> |
Comparing INF and NAN
INF can be compared as if it were a numerical value. Thus INF = INF, INF '= –INF, –INF = –INF, and INF > –INF.
NAN cannot be compared as if it were a numerical value. Because NAN (Not A Number) cannot be meaningfully compared using numerical operators, InterSystems IRIS operations (such as equal to, less than, or greater than) that attempt to compare $DOUBLE(“NAN”) to another $DOUBLE(“NAN”) fail. Comparisons with NAN <= or >= are a special case, which is described in Numeric Computing in InterSystems Applications.
$LISTSAME does consider a $DOUBLE(“NAN”) list element to be identical to another $DOUBLE(“NAN”) list element.
InterSystems IRIS does not distinguish between different NAN representations (NAN, sNAN, etc.). InterSystems IRIS considers all NANs to be the same, regardless of their binary representation.
$ISVALIDNUM, $INUMBER, and $FNUMBER
These ObjectScript functions provide support for $DOUBLE numbers.
$ISVALIDNUM supports INF and NAN. Although these strings are not numbers, $ISVALIDNUM returns 1 for these values, just as if they were numbers. When $DOUBLE is specified with a nonnumeric string, for example $DOUBLE(""), InterSystems IRIS returns a value of 0. For this reason, $ISVALIDNUM($DOUBLE("")) returns 1, because 0 is a number.
$INUMBER and $FNUMBER provide a “D” format option that supports $DOUBLE values. $INUMBER converts a numeric to a IEEE floating-point number. $FNUMBER “D” support includes case conversion of INF and NAN, and choosing whether $DOUBLE(-0) should return 0 or -0.
INF and NAN with Operators
You can perform arithmetic and logical operations on INF and NAN. Use of operators with INF and NAN is not recommended; if such an operation is performed, the following are the results:
Arithmetic operators:
Addition | Subtraction | Multiplication | Division (/, \, or # operators) |
---|---|---|---|
NAN+NAN=NAN | NAN-NAN=NAN | NAN*NAN=NAN | NAN/NAN=NAN |
NAN+INF=NAN | NAN-INF=NAN | NAN*INF=NAN | NAN/INF=NAN |
INF-NAN=NAN | INF/NAN=NAN | ||
INF+INF=INF | INF-INF=NAN | INF*INF=INF | INF/INF=NAN |
Logical operators:
Equality (=) | NAN | INF |
---|---|---|
NAN | 0 | 0 |
INF | 0 | 1 |
Less Than (<) or Greater Than (>) | NAN | INF |
---|---|---|
NAN | 0 | 0 |
INF | 0 | 0 |
Other operators, such as pattern matching and concatenation, treat NAN and INF as three-character alphabetic strings.
For further details, see Numeric Computing in InterSystems Applications.
INF and NAN Examples
$DOUBLE returns an INF value (or a -INF for negative numbers) when the numeric value exceeds the available precision, as shown in the following example:
SET rtn=##class(%SYSTEM.Process).IEEEError(0)
SET x=$DOUBLE(1.2e300)
WRITE !,"Double: ",x
WRITE !,"Is number? ",$ISVALIDNUM(x)
SET y= $DOUBLE(x*x)
WRITE !,"Double squared: ",y
WRITE !,"Is number? ",$ISVALIDNUM(y)
$DOUBLE returns a NAN (not a number) value when the numeric value is invalid. For example, when an arithmetic expression involves two INF values, as shown in the following example. (An arithmetic expression involving a single INF value returns INF.)
SET rtn=##class(%SYSTEM.Process).IEEEError(0)
SET x=$DOUBLE(1.2e500)
WRITE !,"Double: ",x
WRITE !,"Is number? ",$ISVALIDNUM(x)
SET y= $DOUBLE(x-x)
WRITE !,"Double INF minus INF: ",y
WRITE !,"Is number? ",$ISVALIDNUM(y)
JSON Numeric Literals
JSON validation of numeric literals is described in the SET command. $DOUBLE numeric literals specified in a JSON array or JSON object are subject to the following additional rules:
-
INF, -INF, and NAN values can be stored in JSON structures, but cannot be returned by %ToJSON(). Attempting to do so results in an <ILLEGAL VALUE> error, as shown in the following example:
SET jary=[123,($DOUBLE("INF"))] // executes successfully WRITE jary.%ToJSON() // fails with <ILLEGAL VALUE> error
-
$DOUBLE(-0) is stored in a JSON structure as -0.0. $DOUBLE(0) or $DOUBLE(+0) is stored in a JSON structure as 0.0. This is shown in the following example:
SET jary=[0,-0,($DOUBLE(0)),($DOUBLE(-0))] WRITE jary.%ToJSON() // returns [0,-0,0.0,-0.0]
Examples
The following example returns floating-point numbers of 20 digits:
WRITE !,$DOUBLE(999.12345678987654321)
WRITE !,$DOUBLE(.99912345678987654321)
WRITE !,$DOUBLE(999123456789.87654321)
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 the number of digits returned is greater for standard InterSystems IRIS numbers:
SET x=$ZPI
SET y=$DOUBLE($ZPI)
IF x=y { WRITE !,"Same" }
ELSE { WRITE !,"Different"
WRITE !,"standard: ",x
WRITE !,"IEEE float: ",y }
The following examples show that a floating-point number is not necessarily equivalent to a numeric string of the same value:
SET x=123.4567891234560
SET y=123.4567891234567
IF x=$DOUBLE(x) { WRITE !,"Same" }
ELSE { WRITE !,"Different" }
IF y=$DOUBLE(y) { WRITE !,"Same" }
ELSE { WRITE !,"Different" }
SET x=1234567891234560
SET y=1234567891234567
IF x=$DOUBLE(x) { WRITE !,"Same" }
ELSE { WRITE !,"Different" }
IF y=$DOUBLE(y) { WRITE !,"Same" }
ELSE { WRITE !,"Different" }