BookmarkSubscribeRSS Feed
🔒 This topic is solved and locked. Need further help from the community? Please sign in and ask a new question.
SaraMed
Calcite | Level 5

Hi!

I have a problem with a decimal variable that is the result of an arithmetic operation.

Suppose this:

 

data dataout;

	format var_c commax20.16;

	var_a = 556.52;
	var_b = 617.78000;

	var_c = var_a / var_b - 1;

run;

The value of var_c in the output dataset is -0,0991615138075000, but it should actually be -0,0991615138075043
How can I make sure that the precision reaches the 16th decimal?

 

Thank to all.

Sara

1 ACCEPTED SOLUTION

Accepted Solutions
FreelanceReinh
Jade | Level 19

Hi @SaraMed and welcome to the SAS Support Communities!

 

From the documentation (see link in Tom's reply) you will learn: Neither 556.52 nor 617.78 have an exact internal binary representation, which means that they are stored already with rounding errors. Since both numbers are between 2**9=512 and 2**10=1024 the least significant bit in the internal binary representation (which can be inspected by means of the BINARY64. or HEX16. formats) corresponds to 2**-(52-9)=2**-43, leaving a rounding error of up to 2**-44=5.68...E-14. As it turns out, the actual rounding errors of these particular numbers are approx. 2E-14 and 3E-14, respectively, i.e., the value corresponding to the internal representation differs from the true value in the 14th decimal place.

 

In the course of calculations with such rounded values the rounding errors easily accumulate, as you know from calculations with rounded decimal values. Indeed, the result in var_c differs from the theoretical exact value by almost 2**-55, which (is smaller in absolute terms, but) means a larger relative error than what is present in var_a and var_b:

data _null_;
var_a = 556.52;
var_b = 617.78000;
var_c= var_a / var_b - 1;
x=-9.91615138075043e-2;
put x hex16.;
put var_c hex16.;
put var_c e20.;
run;

Results in the log:

BFB962A622D338AA
BFB962A622D338A8
-9.9161513807504E-02

(The theoretical exact representation would read ...338A9C...)

 

Finally, most numeric SAS formats (including the standard w.d format and also COMMAXw.d) perform a little bit of rounding, i.e., they don't show everything what could be extracted from the internal representation (including rounding errors, hence often useless digits). Your result in var_c is a case in point: The decimal equivalents of the two internal representations shown above (ending in "...338AA" and "...338A8") and the exact value are

-0.09916151380750429233...
-0.09916151380750426458...
-0.09916151380750428955...

So, you're right that even the calculated result could be displayed as -0,0991615138075043 if there was a suitable format, but there isn't (as far as I know, at least outside of DS2). As you see above, you can get one more significant digit (in this case) with the E20. format than with COMMAX20.16: -9.9161513807504E-02.

 

(Edit: All of the above applies to Windows and Unix platforms.)

View solution in original post

5 REPLIES 5
Tom
Super User Tom
Super User

SAS stores all numbers as 8 byte floating point. You cannot have more digits of precision than that format allows.

The FORMAT in SAS is just instructions for how to display the value.

https://documentation.sas.com/?docsetId=lrcon&docsetTarget=p0ji1unv6thm0dn1gp4t01a1u0g6.htm&docsetVe...

 

FreelanceReinh
Jade | Level 19

Hi @SaraMed and welcome to the SAS Support Communities!

 

From the documentation (see link in Tom's reply) you will learn: Neither 556.52 nor 617.78 have an exact internal binary representation, which means that they are stored already with rounding errors. Since both numbers are between 2**9=512 and 2**10=1024 the least significant bit in the internal binary representation (which can be inspected by means of the BINARY64. or HEX16. formats) corresponds to 2**-(52-9)=2**-43, leaving a rounding error of up to 2**-44=5.68...E-14. As it turns out, the actual rounding errors of these particular numbers are approx. 2E-14 and 3E-14, respectively, i.e., the value corresponding to the internal representation differs from the true value in the 14th decimal place.

 

In the course of calculations with such rounded values the rounding errors easily accumulate, as you know from calculations with rounded decimal values. Indeed, the result in var_c differs from the theoretical exact value by almost 2**-55, which (is smaller in absolute terms, but) means a larger relative error than what is present in var_a and var_b:

data _null_;
var_a = 556.52;
var_b = 617.78000;
var_c= var_a / var_b - 1;
x=-9.91615138075043e-2;
put x hex16.;
put var_c hex16.;
put var_c e20.;
run;

Results in the log:

BFB962A622D338AA
BFB962A622D338A8
-9.9161513807504E-02

(The theoretical exact representation would read ...338A9C...)

 

Finally, most numeric SAS formats (including the standard w.d format and also COMMAXw.d) perform a little bit of rounding, i.e., they don't show everything what could be extracted from the internal representation (including rounding errors, hence often useless digits). Your result in var_c is a case in point: The decimal equivalents of the two internal representations shown above (ending in "...338AA" and "...338A8") and the exact value are

-0.09916151380750429233...
-0.09916151380750426458...
-0.09916151380750428955...

So, you're right that even the calculated result could be displayed as -0,0991615138075043 if there was a suitable format, but there isn't (as far as I know, at least outside of DS2). As you see above, you can get one more significant digit (in this case) with the E20. format than with COMMAX20.16: -9.9161513807504E-02.

 

(Edit: All of the above applies to Windows and Unix platforms.)

SaraMed
Calcite | Level 5

Well, I think I will use the e20 format. to have the greatest possible precision, also because this rounding creates problems for the subsequent derivative calculations, so to have the smallest gap I have to be as precise as possible.

 

Thank you so much for your perfect answer!

Sara

FreelanceReinh
Jade | Level 19

@SaraMed wrote:

Well, I think I will use the e20 format. to have the greatest possible precision, also because this rounding creates problems for the subsequent derivative calculations, so to have the smallest gap I have to be as precise as possible.


As long as these subsequent calculations are done in SAS, I would use the internal value (and not a formatted value), i.e., use a SAS dataset to transfer the result. The display format and the accompanying rounding are then irrelevant.

hackathon24-white-horiz.png

The 2025 SAS Hackathon has begun!

It's finally time to hack! Remember to visit the SAS Hacker's Hub regularly for news and updates.

Latest Updates

Mastering the WHERE Clause in PROC SQL

SAS' Charu Shankar shares her PROC SQL expertise by showing you how to master the WHERE clause using real winter weather data.

Find more tutorials on the SAS Users YouTube channel.

Discussion stats
  • 5 replies
  • 8013 views
  • 0 likes
  • 4 in conversation