Losing precision

Accepted Solution Solved
Reply
Respected Advisor
Posts: 3,908
Accepted Solution

Losing precision

[ Edited ]

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;

Accepted Solutions
Solution
‎01-08-2017 04:24 PM
Regular Contributor
Posts: 244

Re: Losing precision

[ Edited ]

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


All Replies
Community Manager
Posts: 2,772

Re: Losing precision

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

 

Valued Guide
Posts: 505

Re: Losing precision

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

 

Respected Advisor
Posts: 3,777

Re: Losing precision

[ Edited ]

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

 

Regular Contributor
Posts: 244

Re: Losing precision

[ Edited ]

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.

Solution
‎01-08-2017 04:24 PM
Regular Contributor
Posts: 244

Re: Losing precision

[ Edited ]

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).

Respected Advisor
Posts: 3,908

Re: Losing precision

[ Edited ]

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.

☑ This topic is solved.

Need further help from the community? Please ask a new question.

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