BookmarkSubscribeRSS Feed
novinosrin
Tourmaline | Level 20

 

Can somebody who has used both R and SAS provide some insights

 

Scully, Jim 
 
Feb 4 at 10:34 AM
Hey Nav,

 

# In R, the round function rounds floats.
# A first example rounds 1234.15 to the 1st decimal place, and returns 1234.2
round(1234.15, 1)
# A second example rounds 12345.15 to the 1st decimal place, and returns 12345.1
round(12345.15, 1)
# Why does the first example round up, and the second example round down?
# I suspect round-off error in the second example
# 12345.15 is not actually stored as 12345.15
# Rather, it is stored as 12345.15 plus or minus 0.00000000000001 (large finite number of zeros)
# So, 12345.15 is actually stored as 12345.149999999999999, which does round to 12345.1
 
Can you do a comparative reasoning with SAS?
9 REPLIES 9
mkeintz
PROC Star

SAS numeric are 8-bytes floats.  On my windows machine, the largest consecutive integer in SAS is

9,007,199,254,740,992.   (=   constant('exactint',8).

 

Call it  X.

 

Then, given that data are stored as binary mantissa and binary exponent.

  1.  The only numbers available from X to 2X  are the even numbers
  2.  The only number from 2X to 4X  are 0mod4.
  3.  etc.

Similarly:

  1.  Only integers are available from  X down to X/2
  2.  Only integers and halves from X/2  to X/4
  3.  etc.

You can work your way down to any base-2 level of precision to show this asymmetry of precision surrounding X times some power of 2.

 

 

 

But back to your problem as stated - rounding to the tenth does not produced expected value:

 

filename values temp;

data _null_; /* Write out starting and expected round */
  file values;
  put 'datalines;';
  length value  expect  $15;
  do ndigits=1 to 10;
    value=cats(repeat('9',ndigits),.15);
	expect=cats(repeat('9',ndigits),.2);
	put value= expect=;
  end;
  put 'run;';
run;

data oops; /* Read starting and expected value, calculate round and check */
  input value= expect=;
  check=round(value,.1);
  format value expect check comma22.2;
  if check^=expect then flag='OOPS';
  %include values;
run;
proc print;
run;

 

Notice OOPS flag  is on for a couple numbers generated above.

--------------------------
The hash OUTPUT method will overwrite a SAS data set, but not append. That can be costly. Consider voting for Add a HASH object method which would append a hash object to an existing SAS data set

Would enabling PROC SORT to simultaneously output multiple datasets be useful? Then vote for
Allow PROC SORT to output multiple datasets

--------------------------
Rick_SAS
SAS Super FREQ

I think your friend's assumption about representable numbers is incorrect.

 

I think you are seeing that R (and more recently, Python) adopted the engineering convention of “round to even” when rounding off a 5.  See the documentation for the round function in r: ?round

 

SAS rounds 5 away from 0. See Rounding up, rounding down

mkeintz
PROC Star

I suspect the "round to even"  approach is a  way to eliminate bias in rounding for samples with well-behaved distributions at the larger order of magnitude.  Ceteris paribus, it would round up and down about the same number of times.

 

But over here in the academic financial analysis world, our users would be mighty surprised, and often annoyed, if 5 were not rounded up.

 

I suppose you could work around each of these behaviors to produce the other,

--------------------------
The hash OUTPUT method will overwrite a SAS data set, but not append. That can be costly. Consider voting for Add a HASH object method which would append a hash object to an existing SAS data set

Would enabling PROC SORT to simultaneously output multiple datasets be useful? Then vote for
Allow PROC SORT to output multiple datasets

--------------------------
Patrick
Opal | Level 21

@Rick_SAS 

I can't find "round half to even" in the blog you've posted. I guess it would need some formula along the line of below.

data test;
  input have expected;
  even=mod(int(have)+1,2);
  dot5=abs(mod(have,1))=0.5;
  calculated=round(have) - (even * dot5);
  calculated2= round(have) - mod(int(have)+1,2) * (abs(mod(have,1))=0.5);
  correct= expected=calculated;
  datalines;
23.49 23
23.50 24
23.51 24
23.99 24
24.00 24
24.01 24
24.49 24
24.50 24
24.51 25
-23.49 -23
-23.50 -24
-23.51 -24
-23.99 -24
-24.00 -24
-24.01 -24
-24.49 -24
-24.50 -24
-24.51 -25
;

proc print;
run;

Capture.JPG

Rick_SAS
SAS Super FREQ

No, it's much easier. Just use the ROUNDE function. The 'E' in the name is for "round to Even".

 

For more information about the round-to-even method, including examples of using the ROUNDE function in SAS, see the article "Round to even."

ballardw
Super User

Does R support rounding to values like 0.7?

 

Such as:

data example;
 do i= 1 to 2 by 0.01;
   y= round(i,0.7);
   output;
 end;
run;
Rick_SAS
SAS Super FREQ

Not via the standard round() function. It rounds to powers of 10.

Here is the round() doc in R.

novinosrin
Tourmaline | Level 20

Thank you gentlemen @Rick_SAS . @mkeintz  and @ballardw  for your responses. I am basically writing to acknowledge and value your time. I am yet to sit with my friend, dig in on the very subject. I will honor the help and will come back with some substance soon as I can. Cheers!

Ready to join fellow brilliant minds for the SAS Hackathon?

Build your skills. Make connections. Enjoy creative freedom. Maybe change the world. Registration is now open through August 30th. Visit the SAS Hackathon homepage.

Register today!
How to connect to databases in SAS Viya

Need to connect to databases in SAS Viya? SAS’ David Ghan shows you two methods – via SAS/ACCESS LIBNAME and SAS Data Connector SASLIBS – in this video.

Find more tutorials on the SAS Users YouTube channel.

Discussion stats
  • 9 replies
  • 3897 views
  • 4 likes
  • 6 in conversation