BookmarkSubscribeRSS Feed
🔒 This topic is solved and locked. Need further help from the community? Please sign in and ask a new question.
Patrick
Opal | Level 21

Does anyone have an explanation why in version 1 in the code below I'm losing precision but things work for version 2?

 

 

/* version 1 */
%Let date1= "05JAN2017:09:58:57.822"dt;
%let date2=%sysfunc(sum(&date1,-10),datetime26.3);
%put &=date1;
%put Losing precision:  &=date2;

/* version 2 */
%Let date1= 1799229537.822;
%let date2=%sysfunc(sum(&date1,-10),datetime26.3);
%put &=date1;
%put Full precision:  &=date2;
1 ACCEPTED SOLUTION

Accepted Solutions
snoopy369
Barite | Level 11

Actually - I think that is the pointer to the real problem...

 


data _null_;
 date1a= "05JAN2017:09:58:57.822"dt;
 date1b= 1799229537.822;

 put date1a=;
 put date1b=;

 put date1a= best32.;
 put date1b= best32.;

 put date1a=  binary64.;
 put date1b=  binary64.;

 date2a = sum(date1a,-10);
 date2b = sum(date1b,-10);

 put date2a=  binary64.;
 put date2b=  binary64.;

run;

Somewhere in the macro variable assignment, BEST12. is being used.  BEST12. will yield a rounded value to 1 place.

 

I don't see a way to get SAS to not do that; for example, even this won't listen:

%Let date1= %sysfunc(sum("05JAN2017:09:58:57.862342"dt),best32.);
%put &=date1;

Presumably because the conversion happens immediately seeing the constant and resolving it and bringing it into the macro facility.  So you'll have to do a workaround like data _null_ says, or perhaps a bit simpler,

%Let date1= 05JAN2017:09:58:57.822;
%let date2= %sysfunc(inputn(&date1.,datetime,26));
%put &=date2;

(easier if you leave off all the other stuff and just store the date-as-text in date1).

View solution in original post

6 REPLIES 6
ChrisHemedinger
Community Manager

I don't know the answer, but guessing it has to do with the macro processor as you're assigning the values in %LET.

 

 

%Let date1= "05JAN2017:09:58:57.822"dt;
%let date1bin = %sysfunc(putn(&date1.,binary64.));
%Let date2= 1799229537.822;
%let date2bin = %sysfunc(putn(&date2.,binary64.));

%put &=date1;
%put &=date1bin;
%put &=date2;
%put &=date2bin;

 

 

Yields two different values:

 

 

36         %put &=date1;
DATE1="05JAN2017:09:58:57.822"dt
37         %put &=date1bin;
DATE1BIN=0100000111011010110011111000010000011000011100110011001100110011
38         %put &=date2;
DATE2=1799229537.822
39         %put &=date2bin;
DATE2BIN=0100000111011010110011111000010000011000011101001001101110100110

 

 

Compare to DATA step:

 

data _null_;
 date1a= "05JAN2017:09:58:57.822"dt;
 date1b= 1799229537.822;

 put date1a=  binary64.;
 put date1b=  binary64.;

 date2a = sum(date1a,-10);
 date2b = sum(date1b,-10);

 put date2a=  binary64.;
 put date2b=  binary64.;

run;

 

Output (two pairs of identical values, initial values then the sum values):

 

date1a=0100000111011010110011111000010000011000011101001001101110100110
date1b=0100000111011010110011111000010000011000011101001001101110100110
date2a=0100000111011010110011111000010000010101111101001001101110100110 date2b=0100000111011010110011111000010000010101111101001001101110100110

 

SAS For Dummies 3rd Edition! Check out the new edition, covering SAS 9.4, SAS Viya, and all of the modern ways to use SAS!
rogerjdeangelis
Barite | Level 11

A good question like this one is worth a thousand answers

 

Thanks Chris

 

I get the same result when using the same input.

Computers are not decimal machines.
Decimal to Binary to Decimal is not reversible.

 

/* version 1 */
%Let date1= 41DACF8418749BA6;
%let date2=%sysfunc(sum(%sysfunc(inputn(41DACF8418749BA6,hex16.)),-10),datetime26.3);
%put &=date1;
%put Loosing precision: &=date2;

/* version 2 */
%Let date1= 41DACF8418749BA6;
%let date2=%sysfunc(sum(%sysfunc(inputn(41DACF8418749BA6,hex16.)),-10),datetime26.3);
%put &=date1;
%put Full precision: &=date2;

 

LOG

108 /* version 1 */
109 %Let date1= 41DACF8418749BA6;
110 %let date2=%sysfunc(sum(%sysfunc(inputn(41DACF8418749BA6,hex16.)),-10),datetime26.3);
111 %put &=date1;
DATE1=41DACF8418749BA6
112 %put Loosing precision: &=date2;
Loosing precision: DATE2=05JAN2017:09:58:47.822
113 /* version 2 */
114 %Let date1= 41DACF8418749BA6;
115 %let date2=%sysfunc(sum(%sysfunc(inputn(41DACF8418749BA6,hex16.)),-10),datetime26.3);
116 %put &=date1;
DATE1=41DACF8418749BA6
117 %put Full precision: &=date2;
Full precision: DATE2=05JAN2017:09:58:47.822

 

data_null__
Jade | Level 19

I don't know the reason but this rather SYSFUNC heavy expression does produce the correct result.

 

 

%let date3=%sysfunc(sum(%sysfunc(inputn(%sysfunc(dequote(&date1)),datetime,26)),-10),datetime26.3);

NOTE: DATE3=05JAN2017:09:58:47.822

 

snoopy369
Barite | Level 11

It's in the conversion of the datetime constant I think:

 


%Let date1= %sysevalf("05JAN2017:09:58:57.822"dt);

 

That already loses the extra characters.  Probably a question for SAS tech support as to why it happens - however the datetime constant is resolved must only take one decimal place for some reason.

 

Interestingly, it's not truly losing precision: look at this.

 


%Let date1= %sysevalf("05JAN2017:09:58:57.862342"dt+0);

 

That rounds up - meaning SAS is doing this on purpose, this isn't a loss of precision situation.

 

Even more interestingly, I do not get the same results Chris does in the data step - at least, not when I go through CALL SYMPUTX:

 

 


data _null_;
  call symputx('date1',"05JAN2017:09:58:57.822"dt);
run;
%put &=date1;

Or even:

 


data _null_;
  x = "05JAN2017:09:58:57.822"dt;
  put x=;
  call symputx('date3',x);
run;
%put &=date3;

Both `x` and `&date3` have the rounded value.

snoopy369
Barite | Level 11

Actually - I think that is the pointer to the real problem...

 


data _null_;
 date1a= "05JAN2017:09:58:57.822"dt;
 date1b= 1799229537.822;

 put date1a=;
 put date1b=;

 put date1a= best32.;
 put date1b= best32.;

 put date1a=  binary64.;
 put date1b=  binary64.;

 date2a = sum(date1a,-10);
 date2b = sum(date1b,-10);

 put date2a=  binary64.;
 put date2b=  binary64.;

run;

Somewhere in the macro variable assignment, BEST12. is being used.  BEST12. will yield a rounded value to 1 place.

 

I don't see a way to get SAS to not do that; for example, even this won't listen:

%Let date1= %sysfunc(sum("05JAN2017:09:58:57.862342"dt),best32.);
%put &=date1;

Presumably because the conversion happens immediately seeing the constant and resolving it and bringing it into the macro facility.  So you'll have to do a workaround like data _null_ says, or perhaps a bit simpler,

%Let date1= 05JAN2017:09:58:57.822;
%let date2= %sysfunc(inputn(&date1.,datetime,26));
%put &=date2;

(easier if you leave off all the other stuff and just store the date-as-text in date1).

Patrick
Opal | Level 21

Thank you all for your valuable input. ...and also thank you @ChrisHemedinger for fixing my spelling.

 

Even though I have very rarely to use fractional seconds in real life situations and there are multiple ways to code around this implicit rounding, I'm still going to raise a TechSupport track for this one. I'll keep you posted once I've got a "final" answer.

How to Concatenate Values

Learn how use the CAT functions in SAS to join values from multiple variables into a single value.

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
  • 6 replies
  • 2263 views
  • 5 likes
  • 5 in conversation