Rounding in SAS

SAS provides two distinct rounding functions that handle tie-breaking (values exactly halfway between two numbers) differently:

The key difference appears when rounding values that are exactly halfway between two possible results.


data XXX;
    input my_number;
    datalines;
    2.2
    3.99
    1.2345
    7.876
    13.8739
    ;

data xxx2;
    set xxx;
    do decimal_places = 1, 2, 3;
        round_result = round(my_number, 10**(-decimal_places));
        rounde_result = rounde(my_number, decimal_places);
        output;
    end;
run;

proc print data=xxx2;
run;

The round function can produce unexpected results due to floating-point precision limitations. This typically occurs with: - Very large numbers (beyond 15-16 significant digits) - Results of arithmetic operations that introduce small rounding errors - Numbers near the machine epsilon precision threshold

These precision issues are inherent to how computers store decimal numbers, not specific flaws in SAS.


data floating_point_precision;
    /* Example 1: Large number precision loss */
    input_val = 32768.0156255;
    expected =  32768.015626;
    actual = round(input_val, 1e-6);
    difference = actual - expected;
    example = 'Large number';
    output;
    
    /* Example 2: Subtraction then rounding */
    input_val = 2048.1375 - 2048;  /* = 0.1375 */
    expected = 0.138;
    actual = round(input_val, 1e-3);
    difference = actual - expected;
    example = 'After subtraction';
    output;
run;

proc print data=floating_point_precision;
    format input_val expected actual difference 13.8;
    var example input_val expected actual difference;
run;

The following analysis systematically identifies cases where round fails by testing combinations of large integers and decimal fractions. Numbers with trailing digits near machine precision limits are most susceptible to incorrect rounding.


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;
proc print;
quit;

This example demonstrates rounding behavior with results from common arithmetic operations (addition, subtraction, multiplication, division) across different precision levels, showing how accumulated floating-point errors can affect rounding accuracy.


data simple;
    input num1 num2;
    datalines;
    3.14159 2.71828
    1.99999 0.33333
    5.55555 4.44444
    7.87654 1.23456
    0.12345 9.87654
    6.66666 3.33333
    ;
run;

data results;
    set simple;
    operator='+'; num3=num1+num2; output;
    operator='-'; num3=num1-num2; output;
    operator='*'; num3=num1*num2; output;
    operator='/'; num3=num1/num2; output;
run;

data final;
    set results;
    rounded_001 = round(num3, 0.001);  /* Round to nearest 0.001 */
    rounded_01  = round(num3, 0.01);   /* Round to nearest 0.01 */
    rounded_1   = round(num3, 0.1);    /* Round to nearest 0.1 */
    rounded_int = round(num3, 1);      /* Round to nearest integer */
run;

proc print data=final;
    format num1 num2 num3 rounded_001 rounded_01 rounded_1 rounded_int 12.6;
run;

Despite these floating-point precision issues with very large numbers, the round function remains reliable for most practical statistical applications. Users should be aware of potential precision limitations when working with numbers beyond 15-16 significant digits or results from complex arithmetic operations.

References

SAS Documentation: ROUND Function

SAS Documentation: ROUNDE Function

How to Round Numbers in SAS - SAS Example Code