Different factors affect numeric precision. This issue is common for many people, including SAS users. Though computers and software can help, you are limited in how precisely you can calculate, compare, and represent data. Therefore, only those people who generate and use data can determine the exact degree of precision that meets their enterprise needs.
As you decide the degree of precision that you want, you need to consider that these system factors can cause calculation differences:
These factors can also cause differences:
You also need to consider how conversions are performed on, between, or across any of these system or calculation factors.
Depending on the degree of precision that you want, calculating the value of r can result in a tiny residual in a floating-point unit. When you compare the value of r to 0.0, you might find that r≠0.0. The numbers are very close but not equal. This type of discrepancy in results can stem from problems in representing, rounding, displaying, and selectively extracting data.
Some numbers can be represented exactly, but others cannot. As shown in this example, the number 10.25, which terminates in binary, can be represented exactly.
data x;
x=10.25;
put x hex16.;
run;
The output from this DATA step is an exact number: 4024800000000000. However, the number 10.1 cannot be represented exactly, as this example shows.
data x; x=10.1; put x hex16.; run;
The output from this DATA step is an inexact number: 4024333333333333.
As this example shows, rounding errors can result from platform-specific differences. No solution exists for such situations.
data x;
x=10.1;
put x hex16.;
y=100000;
newx=(x+y)-y;
put newx hex16.;
run;
In Linux environments, the output from this DATA step is 4024333333333333 (8/10-byte hardware double).
For certain numbers such as x.5, the precision of displayed data depends on whether you round up or down. Low-precision formatting (rounding down) can produce different results on different platforms. In this example, the same high-precision (rounding up) result occurs for X=8.3, X=8.5, or X=hex16. However, a different result occurs for X=8.1 because this number does not yield the same level of precision.
data;
x=input('C047DFFFFFFFFFFF', hex16.);
put x= 8.1 x= 8.3 x= 8.5 x= hex16.;
run;
Here is the output under Linux (high-precision formatting).
x=-47.8 x=-47.750 x=-47.7500 x=C047DFFFFFFFFFFF
To fix the problem that this example illustrates, you must select a number that yields the next precision level—in this case, 8.2.
After you determine the degree of precision that your enterprise needs, you can refine your software. You can use macros, sensitivity analyses, or fuzzy comparisons such as extractions or filters to extract data from databases or from different versions of SAS. For example, you can use this EQFUZZ macro.
*****************************************************************************/
/* This macro defines an EQFUZZ operator. The subsequent DATA step shows */
/* how to use this operator to test for equality within a certain tolerance. */
/*****************************************************************************/
%macro eqfuzz(var1, var2, fuzz=1e-12);
abs((&var1 - &var2) / &var1) < &fuzz
%mend;
data _null_;
x=0;
y=1;
do i=1 to 10;
x+0.1;
end;
if x=y then put 'x exactly equal to y';
else if %eqfuzz(x,y) then put 'x close to y';
else put 'x nowhere close to y';
run;
When you read numbers in from an external DBMS that supports precision beyond 15 digits, you can lose that precision. You cannot do anything about this for existing databases. However, when you design new databases, you can set constraints to limit precision to about 15 digits. Alternatively, you can select a numeric DBMS data type to match the numeric SAS data type. For example, select the DOUBLE type in Hadoop (precise up to 15 digits) or the INT type instead of the BIGINT type (precise up to 38 digits).
When you read numbers in from an external DBMS for noncomputational purposes, use the DBSASTYPE= data set option, as shown in this example.
libname x hadoop user=myusr1 password=mypwd1 database=db;
data sasdata;
set ora.catalina2(dbsastype= (c1='char(20)'));
run;
This option retrieves numbers as character strings and preserves precision beyond 15 digits. For details, see the DBSASTYPE= data set option.
See these resources for more detail about numeric precision, including variables that can affect precision.
SAS/ACCESS provides National Language Support (NLS) in a variety of ways.
These LIBNAME or SQL pass-through options allow for byte and character conversion and length calculation.
These data types allow for more flexible adjustment of column lengths.
For more NLS information, see these resources.
http://support.sas.com/resources/papers/92unicodesrvr.pdf.