BookmarkSubscribeRSS Feed
SwissC
Obsidian | Level 7

Hi all,

 

Sorry it took me so long to come back to this, ended up with a job change and life turned a little hectic.

 

You are all right the original code was terrible and in completely the wrong direction.  I learnt my lesson not to grab random code from the internet and start to hack it to pieces late on a Friday afternoon

 

To those of you who mentioned using the E format, thank you very much, using this did not even cross my mind (not sure I have ever used this format before).  Your various suggestions were most helpful.  
I recreated the function as below.

 

data test;
a=9999999.76403; OUTPUT;
a=2981248.76403; OUTPUT;
a=981248.76403; OUTPUT; 
a=81248.76403; OUTPUT;
a=0.9999999999; OUTPUT; 
a=9.98999; OUTPUT;
a=9.99999; OUTPUT; 
a=12.76; OUTPUT; 
a=2.76; OUTPUT; 
a=12.7602; OUTPUT; 
a=1248.76403; OUTPUT; 
a=248.76403; OUTPUT;
a=48.76403; output; 
a=8.76403; OUTPUT;
a=0.76403; OUTPUT;
a=0.76003; OUTPUT;
a=0.076403; OUTPUT;
a=0.0076403; OUTPUT;
a=0.00076403; OUTPUT;
a=0.000076403; OUTPUT;
a=0.00007640387106801; OUTPUT;
RUN; 
DATA test;
 SET test;
 OUTPUT;
 a=a*-1;
 OUTPUT;
RUN;
PROC SORT data=test; BY descending a; RUN;

proc fcmp outlib=WORK.FUNCS.TEST;
function sigdigz(val, sig, len) $200;
  
  LENGTH as_e as_t  rhs wd outval $200;                                         /* Set lengths for variables */
  %LET ING=ING;
  
  as_e = putn(val, cats('E', SIG+6, '.'));                                      /* Print value using E notation */
  as_t = put(val, best32.);                                                     /* Print value in full */

  rhs=scan(as_e, 2, "E");                                                       /* Get text from right hand side of E notation */
  e=input(rhs, best.);                                                          /* And convert to numeric */
  maxd=length(scan(as_t, 2, "."));                                              /* Find maximum number of decimal places in original value */

  IF e+1<sig THEN d=min(sig-e-1, maxd);                                         /* d will be number of values to display after decimal point, but cannot be more than original value */
   else d=0;
  IF d=0 THEN w=len;                                                            /* w is width of format, based on len and expanded for decimal values */
    ELSE w=len+2+d;
  wd=compress(put(w, best.)||"."||put(d, best.));                               /* create format for printing value */
 
  as_n=input(as_e, E32.);                                                       /* Input E text value as numeric */ 
  outval=putn(as_n, wd);                                                        /* and print to text using format created above */
  
  lx=len-length(scan(compress(outval), 1, "."));                                /* Get length of integer part of value to check against planned len, issue warn if too great */          
  
  IF lx>len THEN PUT "WARN&ING: LENGTH value too small to correctly print value";

  return(outval);
endsub;
run;
options cmplib=WORK.FUNCS;  

DATA test6;
   SET test;
   c=sigdigz(a, 3, 9);       
   d=sigdigz(a, 4, 9);       
   e=sigdigz(a, 5, 9);       
   f=sigdigz(a, 6, 9);       
   g=sigdigz(a, 7, 9);       
   h=sigdigz(a, 8, 9);
RUN;

proc print data=test6; format a best32.;run;

 

 

The function now works as intended such that,

- All numbers are decimal aligned according the len value (characters prior to the decimal point)

- Trailing zeros are correctly kept (e.g. 0.76003 to 4s.f. is 0.7600, the trailing zero are shown as we know the value was captured with this precision)

- Values are not over ?signified? (e.g. 2.76 to 4s.f is still 2.76, we cannot assign this to 2.760 as that would be presenting to a higher precision than we actually know).

 

ChrisNZ
Tourmaline | Level 20

This is never true?

IF lx>len THEN PUT "WARN&ING: LENGTH value too small to correctly print value"; /* Get length of integer part of value to check against planned len, issue warn if too great */

sig=3 lx=8 len=9

a=123456789012.34 b=1.23E11

 

SwissC
Obsidian | Level 7

You are right I think it should be

 

  lx=length(scan(compress(outval), 1, "."));                                /* Get length of integer part of value to check against planned len, issue warn if too great */          
  
  IF lx>len THEN PUT "WARN&ING: LENGTH value too small to correctly print value";

  

sas-innovate-white.png

Special offer for SAS Communities members

Save $250 on SAS Innovate and get a free advance copy of the new SAS For Dummies book! Use the code "SASforDummies" to register. Don't miss out, May 6-9, in Orlando, Florida.

 

View the full agenda.

Register now!

What is Bayesian Analysis?

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.

SAS Training: Just a Click Away

 Ready to level-up your skills? Choose your own adventure.

Browse our catalog!

Discussion stats
  • 17 replies
  • 5170 views
  • 4 likes
  • 7 in conversation