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.

hackathon24-white-horiz.png

The 2025 SAS Hackathon has begun!

It's finally time to hack! Remember to visit the SAS Hacker's Hub regularly for news and updates.

Latest Updates

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