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

 

It's time to register for SAS Innovate! Join your SAS user peers in Las Vegas on April 16-19 2024.
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

Don't miss out on SAS Innovate - Register now for the FREE Livestream!

Can't make it to Vegas? No problem! Watch our general sessions LIVE or on-demand starting April 17th. Hear from SAS execs, best-selling author Adam Grant, Hot Ones host Sean Evans, top tech journalist Kara Swisher, AI expert Cassie Kozyrkov, and the mind-blowing dance crew iLuminate! Plus, get access to over 20 breakout sessions.

 

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
  • 1141 views
  • 5 likes
  • 5 in conversation