Hello,
I need to create a format which formats to 2 decimal places whilst rounding to the nearest even number i.e. it will print the number 8.665 as 8.66 rather than 8.67.
I have begun by following the advice in this thread and created a custom format which uses a function to do the format. What I have so far is this..
proc fcmp outlib=work.func.sample;
function nre(value);
return( rounde(value, 0.01) );
endsub;
run;
* make function available;
options cmplib=work.func;
* create a format that uses the function;
proc format;
value rex
low - high = [nre()]
;
run;
The problem I have is that my custom format rex will round correctly but will not display to two decimal places i.e. it drops trailing zeroes and prints 4.00 as 4. Any help in getting to the final step would be much appreciated.
Also, right now I only need to perform this to two decimal places but often need to round to an arbitrary number of places. Is there a way to generalise this code to allow me to select the number of places to round to without having to create a newformat
Thanks,
Steve
How about something like this, which gives you more control over the formatted value as a displayed value.
proc fcmp outlib=work.func.sample;
function nre(value) $;
return( put(rounde(value, 0.01),5.2) );
endsub;
run;
* make function available;
options cmplib=work.func;
* create a format that uses the function;
proc format;
value rex
low - high = [nre()]
;
run;
data n;
length x 8 y 8 z 8;
x = 4.00;
y = 4.536;
z = 1.625;
format x rex. y rex. z rex.;
run;
Obs x y z 1 4.00 4.54 1.62
Why not use the round function?
Try round( variable, 0.02);
If you really want a format check the SAS docs about creating a format based on a function. There's an example in the docs.
Use the appropriate function to manipulate your data. Formats are for changing how a variable is displayed, whilst retaining the real value underneath. The two ways are different. Sending data which is hidden behind a format like this would to me, be quite bad practice. If the value is to be round, use round, if it is not, then show the full value. Otherwise your just obfuscating your data.
The bigger picture is that I'm trying to format values as they come out of a PROC TABULATE procedure without having to put them through another data step. Normally this is something I would do in the data step but constraints on this particular project means I'd like to do to this with format.
Also I'm not sure I agree that this constitutes bad practice or obfuscating the data underneath. After all, SAS is already rounding the value it presents when using the w.d format I would normally use. All I'm trying to do is make SAS use a different rounding method.
Hi,
Rounding is a different concept to formatting, maybe the terminology you use means something different? To round a number, you take the value and physically change that value in the dataset. Formatting a variable does not physically change the value, only the way it is displayed. So:
Actual value = 1.36
Rounded value = 1.4
Formatted value (as shown in table view) = 1.3
Actual value if format is removed = 1.36
I rarely use tabulate if at all any more, so can't really help much with syntax there, but you get a table out from your statement do you not, or does that goto an output file directly?
Seems to me like your saving on a couple of lines of data step code after the effect, but vastly expanding your code to encompass formats, and functions etc.
Hi,
I think you are right that we are talking about different types of rounding.
What I might call "data rounding" is when you change the value of the underlying value using a round function. So for example if x = 1.625, then rounde(x,0.01) = 1.620.
What I might call "format rounding" is the rounding that SAS applies to the value it displays whilst keeping the underlying value the same.
So if I have a value of 1.625 and apply the 6.2 (the w.d format), then SAS will display this as 1.63 whilst the underlying value of 1.625 is retained. So SAS has "Format rounded" the formatted value of 1.625 to 1.63.
What I want to do is choose the type of rounding SAS does to the formatted value. By default SAS rounds up (1.625 -> 1.63) but I want it to round to even (1.625 -> 1.62).
The benefit of this is I could present the data in the way I need without changing the underlying value. Otherwise I would need to
1) Use Proc tabulate to create the table and output it as a data set.
2) Use a data step to round all the values using the rounde function
3)Use Proc report to output this dataset to a PDF.
What I want to do is
1) Use proc tabulate to create the PDF directly with the values already rounded the correct way.
Hope this clarifies what I am trying to do. Thanks for your input so far.
Mmm, sorry, I don't know on that. My preferred approach is to always go 1), 2) (these two could be combined), 3) proc report. I have never come across a procedure which generates exactly theright output for what I want. Maybe you can emulate the tabulate code in proc report (or just emulate it in a datastep, i.e. datastep does processing, then proc report - this is what I tend to do as never found a procedure which produces exactly the output I require).
How about something like this, which gives you more control over the formatted value as a displayed value.
proc fcmp outlib=work.func.sample;
function nre(value) $;
return( put(rounde(value, 0.01),5.2) );
endsub;
run;
* make function available;
options cmplib=work.func;
* create a format that uses the function;
proc format;
value rex
low - high = [nre()]
;
run;
data n;
length x 8 y 8 z 8;
x = 4.00;
y = 4.536;
z = 1.625;
format x rex. y rex. z rex.;
run;
Obs x y z 1 4.00 4.54 1.62
My point exactly Chris. How is all that code a saving against a simple datastep after the effect? Its basically hiding the rounding in a compiled procedure behind a format?
Thanks!
I've been able to use this code as a basis to create a set of formats rounding evenly to different decimal places, which should save me a lot of time in the future.
In answer to some of the other questions, rounding to even only applies in the case of tie breakers e.g. the third decimal place is 5 when your rounding to 2d.p.
Therefore 1.615-> 1.62, 1.625->1.62. All other cases would be rounded as you would normally expect, so 1.633->1.63.
From what I know, rounding to even is the statistically safer way of rounding. It is also the way R rounds by default which is why I need to achieve the same in SAS.
What you gonna do with odd number like : 1.633 ?
proc format;
picture rex
other='009.99' ;
run;
data n;
length x 8 y 8 z 8;
x = 4.00;
y = 4.536;
z = 1.625;
format x y z rex.;
run;
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 the difference between classical and Bayesian statistical approaches and see a few PROC examples to perform Bayesian analysis in this video.
Find more tutorials on the SAS Users YouTube channel.