I am trying to understand how floating-point numbers are added in SAS. I have the following code:
data data1;
format b c d binary64.;
b=0.5; c=0.3; d=b+c;
if d=0.8 then flag=1;
RUN;
And flag is really set to 1.
In binary64:
b=0011111111100000000000000000000000000000000000000000000000000000
c=0011111111010011001100110011001100110011001100110011001100110011
d=0011111111101001100110011001100110011001100110011001100110011010
and 0.8 is represented the same as d. My problem is that when I try to add b and c, normalize the mantissas and add bit by bit I get a number that differs from d. I checked all my calculations and this is not the case. Does anyone know why this can happen?
Keep in mind that 52 bits are stored, but the precision is actually 53 bits (there's always a "hidden" 1 at the beginning of the mantissa) and the math unit in the CPU can probably use all it's 64 integer bits for adding.
So your CPU adds
10000000000000000000000000000000000000000000000000000
+ 010011001100110011001100110011001100110011001100110011 = 110011001100110011001100110011001100110011001100110011
Before you store that back, the leading 1 is eliminated, the exponent once again set to -1, and the 53rd bit from the remaining number is rounded to the 52nd, which is also 1, so the 51st is set to 1 and the 52nd to 0.
You should use round() around calculated floating point. There is a quirk in machines - can't remember the exact term, where a number can have a very small amount on the end of the number, e.g. 0.80000000000000001, but SAS does not display that. If you apply the round() to this it will return exactly the number:
if round(d,.1)=0.8 then flag=1;
you will see this a fair bit in proc sompare ouputs, where it shows differences in numbers which you cant see. Just make sure to round your values to the correct decimal places.
Thanks for the tip. When I perform the comparison 0.5+0.3 does equal 0.8, however when I actually try to repeat what SAS does in the way I understand it I can't. I get a different value, not 0011111111101001100110011001100110011001100110011001100110011010
There is a thorough discussion on the topic in the SAS online docs called Numerical Accuracy in SAS Software. In my view a must-read for every SAS user.
Regards,
- Jan.
Keep in mind that 52 bits are stored, but the precision is actually 53 bits (there's always a "hidden" 1 at the beginning of the mantissa) and the math unit in the CPU can probably use all it's 64 integer bits for adding.
So your CPU adds
10000000000000000000000000000000000000000000000000000
+ 010011001100110011001100110011001100110011001100110011 = 110011001100110011001100110011001100110011001100110011
Before you store that back, the leading 1 is eliminated, the exponent once again set to -1, and the 53rd bit from the remaining number is rounded to the 52nd, which is also 1, so the 51st is set to 1 and the 52nd to 0.
Thanks so much! I forgot about the rounding. Now everything is pretty clear.
Are you ready for the spotlight? We're accepting content ideas for SAS Innovate 2025 to be held May 6-9 in Orlando, FL. The call is open until September 25. Read more here about why you should contribute and what is in it for you!
Learn how use the CAT functions in SAS to join values from multiple variables into a single value.
Find more tutorials on the SAS Users YouTube channel.