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

 

Check out SAS Innovate on-demand content! Watch the main stage sessions, keynotes, and over 20 technical breakout sessions!
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.

sas-innovate-2024.png

Available on demand!

Missed SAS Innovate Las Vegas? Watch all the action for free! View the keynotes, general sessions and 22 breakouts on demand.

 

Register now!

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.

Click image to register for webinarClick image to register for webinar

Classroom Training Available!

Select SAS Training centers are offering in-person courses. View upcoming courses for:

View all other training opportunities.

Discussion stats
  • 6 replies
  • 1169 views
  • 5 likes
  • 5 in conversation