Hi All,
We noticed an issue with our SAS installation recently. We are running Windows 32bit SAS 9.3TS Level 1M0. Calculation on change from baseline were not consistent between the divide function and the divide operator.
We replicated the issue with the following code:
data _null_;
do i=1 to 50;
base = ranuni(1234)*10;
aval = ranuni(2345)*10;
chg1 = divide(aval-base,base)*100;
chg2 = (aval-base)/base*100;
if chg1 ne chg2 then do;
put (base aval chg1 chg2) (=best16.);
put (chg1 chg2) (=hex16.) /;
end;
else put "They are equal!";
end;
run;
base=2.43811160439538 aval=0.8947511347452 chg1=-63.301469336672 chg2=-63.301469336672 chg1=C04FA6968C16E063 chg2=C04FA6968C16E062 They are equal! They are equal! They are equal! They are equal! They are equal! They are equal! base=9.67440287101753 aval=7.3735176154289 chg1=-23.783227618953 chg2=-23.783227618953 chg1=C037C8819AF0BA3B chg2=C037C8819AF0BA3A base=4.02947708220662 aval=3.73164565941861 chg1=-7.3913169553235 chg2=-7.3913169553235 chg1=C01D90B56455F04B chg2=C01D90B56455F048 They are equal! base=2.83903048971623 aval=3.50611041928926 chg1=23.4967511616866 chg2=23.4967511616866 chg1=40377F2B1589B19C chg2=40377F2B1589B19D base=2.5577507878457 aval=4.36403616534734 chg1=70.6200692454097 chg2=70.6200692454097 chg1=4051A7AF36EA9290 chg2=4051A7AF36EA9291 base=1.24002424592153 aval=7.1392959762082 chg1=475.738417993801 chg2=475.738417993801 chg1=407DBBD08F62E270 chg2=407DBBD08F62E271 base=0.02762168181484 aval=5.10001865453088 chg1=18363.8237769844 chg2=18363.8237769844 chg1=40D1EEF4B8C319D0 chg2=40D1EEF4B8C319D1 They are equal! They are equal! They are equal! base=6.40857011843872 aval=7.72992366353512 chg1=20.618539247852 chg2=20.618539247852 chg1=40349E589690D118 chg2=40349E589690D117 They are equal! base=5.34773293200309 aval=4.21025120383606 chg1=-21.270354047785 chg2=-21.270354047785 chg1=C0354535EC419384 chg2=C0354535EC419386 base=4.93211107092542 aval=9.43430182032022 chg1=91.283239259047 chg2=91.283239259047 chg1=4056D220978EA332 chg2=4056D220978EA333 base=7.06284289577177 aval=3.47936205262289 chg1=-50.737088393884 chg2=-50.737088393884 chg1=C0495E58E998FF24 chg2=C0495E58E998FF23 base=1.8100535458932 aval=8.78799389060028 chg1=385.510161317561 chg2=385.510161317561 chg1=407818299EE9E9B5 chg2=407818299EE9E9B6 base=1.39341779583759 aval=3.15914520675277 chg1=126.719166081398 chg2=126.719166081398 chg1=405FAE06D12BFFB4 chg2=405FAE06D12BFFB5 They are equal! They are equal! base=5.46229686376746 aval=6.93179405151484 chg1=26.902550783991 chg2=26.902550783991 chg1=403AE70D9174386E chg2=403AE70D9174386C base=6.02654237115129 aval=2.48575991135359 chg1=-58.753133085851 chg2=-58.753133085851 chg1=C04D6066AA3AA1DB chg2=C04D6066AA3AA1DA base=3.49072226020076 aval=2.76867309248479 chg1=-20.68480715147 chg2=-20.68480715147 chg1=C034AF4F857FA1A2 chg2=C034AF4F857FA1A1 base=7.28259827349456 aval=9.18937070723128 chg1=26.1825843212653 chg2=26.1825843212653 chg1=403A2EBDD89898BD chg2=403A2EBDD89898BC base=6.19594010812973 aval=7.12793015741181 chg1=15.0419473561278 chg2=15.0419473561278 chg1=402E157A1FB5720A chg2=402E157A1FB5720B They are equal! base=3.37719455518629 aval=3.55450391003606 chg1=5.25019663369642 chg2=5.25019663369643 chg1=401500338BDD2E83 chg2=401500338BDD2E8A base=5.20533108394841 aval=7.16976712326043 chg1=37.7389258748538 chg2=37.7389258748538 chg1=4042DE951F815526 chg2=4042DE951F815525 base=4.38564417622315 aval=1.62309248075965 chg1=-62.990785035428 chg2=-62.990785035428 chg1=C04F7ED20B4643EF chg2=C04F7ED20B4643F1 base=8.29834726559853 aval=7.32943984089859 chg1=-11.675908391019 chg2=-11.675908391019 chg1=C0275A10AA250A24 chg2=C0275A10AA250A21 base=1.5316278820539 aval=5.23635912930423 chg1=241.881940819875 chg2=241.881940819875 chg1=406E3C38DBF44BEB chg2=406E3C38DBF44BEA base=3.81391693084218 aval=9.10642663906628 chg1=138.768352960835 chg2=138.768352960835 chg1=4061589658F2D23C chg2=4061589658F2D23B base=2.74778533854884 aval=5.90477663367278 chg1=114.89220976742 chg2=114.89220976742 chg1=405CB919F6FF0F44 chg2=405CB919F6FF0F45 base=3.05036562171316 aval=3.14132258907953 chg1=2.98183820060527 chg2=2.98183820060527 chg1=4007DACDFC8C8149 chg2=4007DACDFC8C8148 base=2.95707058764858 aval=3.66100074893842 chg1=23.8049833585337 chg2=23.8049833585337 chg1=4037CE1363AEB9F4 chg2=4037CE1363AEB9F6 base=5.61540480964603 aval=9.85869430930293 chg1=75.5651576956279 chg2=75.565157695628 chg1=4052E42B8B2EF37F chg2=4052E42B8B2EF380 base=1.14962568560132 aval=8.88840151433293 chg1=673.156134701686 chg2=673.156134701686 chg1=4085093FC38CEC18 chg2=4085093FC38CEC17 They are equal! base=7.88632248895537 aval=9.2173436373553 chg1=16.8775896530226 chg2=16.8775896530226 chg1=4030E0A9B72B0A3E chg2=4030E0A9B72B0A3D They are equal! base=0.08909457367337 aval=9.41624740577128 chg1=10468.8225640903 chg2=10468.8225640903 chg1=40C4726949C7B571 chg2=40C4726949C7B570 base=9.68923215739859 aval=0.63517195202185 chg1=-93.444558436585 chg2=-93.444558436585 chg1=C0575C73A53A92DB chg2=C0575C73A53A92DA base=9.73705197672223 aval=8.64485994383919 chg1=-11.216865592318 chg2=-11.216865592318 chg1=C0266F0901C5436A chg2=C0266F0901C5436B base=1.74953654489924 aval=8.23659310035249 chg1=370.787142135797 chg2=370.787142135797 chg1=40772C98225A28CA chg2=40772C98225A28CB NOTE: DATA statement used (Total process time): real time 0.04 seconds cpu time 0.03 seconds
Running on RedHat Linux I only found differences with SAS version 9.1 (TS1M3)
No differences using 9.2 (TS2M3), 9.3 (TS1M2), or 9.4 (TS1M5).
Check your maintenance release level.
Also note how long ago these older versions of SAS were released (or better supplanted).
Just to add: I ran your code on 9.4M5 on AIX and got 50 "equal" messages, no differences.
The function was introduced in 9.1, so it might be some "immaturity" that was fixed "under the hood" between 9.3 and 9.4.
Like you, I could not find a note in the knowledge base.
The differences are rather small, I think the reason they are there is this:
SAS uses 8-byte real numbers. The Intel/AMD numeric processor works with 10-byte real numbers. When you call DIVIDE, the division is performed in 10-byte reals, the result is returned as an 8-byte real, and that is again converted to a 10-byte real before the division with 100. When you it with the divide operator, the whole thing, including the division by 100, is done in 10-byte reals before the result is returned to SAS as an 8-byte number.
My guess is therefore that what you get with the divide function call is the same as you would get with
chg2=(aval-base)/base;
chg2=chg2/100;
If you dropped the division by 100, the two values would probably also be the same.
If by "other environments" you mean mainframes, they process 8-byte reals in the numeric processor, so there should not be any differences.
Thanks for the reply s_lassen.
I tried testing the proposed scenarios you mentioned with the following, and the issue persists
data _null_;
do i=1 to 50;
base = ranuni(1234)*10;
aval = ranuni(2345)*10;
chg1 = divide(aval-base,base)*100;
chg2=(aval-base)/base;
chg2=chg2*100;
if chg1 ne chg2 then do;
put (base aval chg1 chg2) (=best16.);
put (chg1 chg2) (=hex16.) /;
end;
else put "They are equal!";
end;
run;
Same is true if I drop the multiplication by 100 😞
Thanks
When I submit any of your programs, I get all "equal" messages. I am running on a Windows 64 bits platform, SAS 9.4 TS Level 1M4.
Thanks for confirming. Can someone with a 9.1-9.3 installation please post their results?
I'm trying to gather some evidence to go back to the SAS Technical Support, but they keep sending me to the same numeric precision documents
@himalayan wrote:
but they keep sending me to the same numeric precision documents
Because the differences are due to numeric precision as explained in the documents. Round percent change from baseline to a reasonable number of decimal places and move on.
Master @data_null__ Salute you always
data _null_;
do i=1 to 50;
base = ranuni(1234)*10;
aval = ranuni(2345)*10;
chg1 = round(divide((aval-base),base)*100,.01);
chg2=(aval-base)/base;
chg2=round(chg2*100,.01);
k=chg1=chg2;
if chg1 ne chg2 then do;
put (base aval chg1 chg2) (=best16.);
put (chg1 chg2) (=hex16.) /;
end;
else put "They are equal!";
end;
run;
@himalayan wrote:
, but they keep sending me to the same numeric precision documents
That is because, at the core, it is always necessary to round numbers before making checks for equality. Any mathematical operation with numbers stored in binary real format is bound to create those small binary artifacts that need to be filtered out.
While the difference here has obviously been fixed (and was fixable!) between 9.3 and 9.4, other differences WILL happen, and you need to take care of that proactively. These differences are no errors, they happen by nature and cannot be fixed.
This documentation might some what be useful
Division is not nice in general. You may want to consider controlling the number of decimals involved before the division and afterwards by rounding if this is an issue.
Running on RedHat Linux I only found differences with SAS version 9.1 (TS1M3)
No differences using 9.2 (TS2M3), 9.3 (TS1M2), or 9.4 (TS1M5).
Check your maintenance release level.
Also note how long ago these older versions of SAS were released (or better supplanted).
Thanks Tom and everyone else who replied. For the time-being it looks like we will have to change the legacy code to include rounding and put it our programming specs.
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.