Rounding in SAS

There are two rounding functions in SAS.

The round() function in SAS will round to the nearest whole number and ‘away from zero’ or ‘rounding up’ when equidistant meaning that exactly 12.5 rounds to the integer 13.

The rounde() function in SAS will round to the nearest whole number and ‘rounding to the even number’ when equidistant, meaning that exactly 12.5 rounds to the integer 12.

Both functions allow you to specify the number of decimal places you want to round to.

For example (See references for source of the example)

    #Example code
    data XXX;
      my_number=2.2; output;
      my_number=3.99; output;
      my_number=1.2345; output;
      my_number=7.876; output;
      my_number=13.8739;  output;
    run;

    data xxx2;
      set xxx;
        r_1_dec = round(my_number, 0.1);
        r_2_dec = round(my_number, 0.01);
        r_3_dec = round(my_number, 0.001);
        
        re_1_dec = rounde(my_number, 0.1);
        re_2_dec = rounde(my_number, 0.01);
        re_3_dec = rounde(my_number, 0.001);
    run;
my_number r_1_dec r_2_de r_3_dec re_1_dec re_2_dec re_3_dec
2.2 2.2 2.2 2.2 2.2 2.2 2.2
3.99 4 3.99 3.99 4 3.99 3.99
1.2345 1.2 1.23 1.235 1.2 1.23 1.234
7.876 7.9 7.88 7.876 7.9 7.88 7.876
13.8739 13.9 13.87 13.874 13.9 13.87 13.874

In some rare cases, round() does not return result as expected. For example below.

data incorrect_round;
  *rounded=32768.015625, but it should be 32768.015626;
  rounded=round(32768.0156255,1e-6); output;
  *rounded=0.137, but it should be 0.138;
  rounded=round(2048.1375-2048,1e-3); output;
run;

You can find a little more by the code below. It creates dummy numbers with different numbers of decimal digits, and filter incorrect results. Note, the incorrect results are expected when the input number is near or beyond the precision level, i.e. the last decimal of the input number is near or less than the number multiplied by constant('maceps').

data dum1;
  int1=0; output;
  do i=1 to 25;
    int1=2**i; output;
  end;
  keep int1;
run;

data dum2;
  do round_digits=1 to 7;
    *x.xxx5 should be rounded up, or replace 5 to 4.99 which should be rounded down;
    dec1=2**(-round_digits)+10**(-round_digits-1)*5;
    output;
  end;
  keep dec1 round_digits;
run;

proc sql;
  create table incorrect_round2(where=(rounded<num1)) as
  select dum1.*,dum2.*,int1+dec1 as num1,round(calculated num1,10**(-round_digits)) as rounded
  from dum1, dum2;
quit;

Or more by the code below and comparing with results from another language, e.g. R.

data dum1;
  dec1=0; int1=0; output;
  do i=0 to 12;
    dec1=2**(-i);
    dec1=dec1*1.1;
    int1=2**i;
    output;
  end;
run;

proc sql;
  create table dum3 as select dec1+int1 as num1 from dum1(keep=dec1) a, dum1(keep=int1) b
  ;
  create table dat1 as select a.num1,b.num1 as num2 from dum3 a, dum3 b
;quit;

data dat2;
  set dat1;
  operator='+'; num3=num1+num2; output;
  operator='-'; num3=num1-num2; output;
  if num1^=0 and num2^=0 then do;
    operator='*'; num3=num1*num2; output;
    operator='/'; num3=num1/num2; output;
  end;
run;

data dat3;
  set dat2;
  rounded=round(num3,1e-3);
run;

As the incorrect rounding all occur on large number, round() is still reliable in most of cases.

References

How to Round Numbers in SAS - SAS Example Code