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

Hi,

 

I have two hex data.

 

start                              end                             hex diff   decimal diff

00000485576688D7    000004855767176D   8E96       36502

 

how can I use informat to input the data then calculate the difference then print these values with format hex output as above?

 

Thanks David 

1 ACCEPTED SOLUTION

Accepted Solutions
FreelanceReinh
Jade | Level 19

Hi @yuwda01,

 

It's great that all your questions have been answered, but it would help later readers if you marked the most helpful answer as the accepted solution, not your own "thank you" post. Could you please change that?

 

For those later readers who need to compute the exact difference D=X−Y between two non-negative hexadecimal integers X and Y of up to 26 hex digits each, here's an approach splitting the long numbers into two of length <=13 (which enables storage in a numeric variable). The result is given as a right-justified 27-character string in hexadecimal format (26 digits, padded with zeros) with a minus sign for negative numbers and a leading blank for non-negative numbers.

/* Create test data for demonstration */

data have;
length x y $26;
input x char26. +1 y char26.;
cards;
000004855767176D           00000485576688D7          
        004855767176D        485576688D7             
FEDCBA9876543210ABCDEF6789 1234567890ABCDEF0987654321
1234567890ABCDEF0987654321 FEDCBA9876543210ABCDEF6789
 F                              5                    
1                          c                         
b98286da2e88ad80           38b5ccf197e6              
a20529f5cca196DA           a20529f5cca196d8          
0                          a20529f5cca196d8          
a20529f5cca196d8           a20529f5cca196d8
;

/* Compute the differences D=X-Y */

data want(drop=m0 m1 n0 n1 lx ly);
set have;
length d $27;
lx=length(left(x));
ly=length(left(y));
m0=input(substr(right(x),max(1,length(right(x))-12)), hex13.); /* last (up to) 13 hex digits */
n0=input(substr(right(y),max(1,length(right(y))-12)), hex13.);
if lx>13 then m1=input(substr(left(x),1,lx-13), hex13.);  /* remaining (up to 13) hex digits */
else m1=0; 
if ly>13 then n1=input(substr(left(y),1,ly-13), hex13.);
else n1=0; 
if m1>n1 | m1=n1 & m0>=n0 /* i.e. "if x>=y" */
then d=' '||put(m1-n1-(m0<n0), hex13.)||put(16**13*(m0<n0)-n0+m0, hex13.);
else d='-'||put(n1-m1-(n0<m0), hex13.)||put(16**13*(n0<m0)-m0+n0, hex13.);
run;

The examples show that alignment, leading zeros or capitalization don't affect the result.

View solution in original post

13 REPLIES 13
ChrisNZ
Tourmaline | Level 20

From the documentation:

When you specify a [width]] value of 1 through 15, the input hexadecimal value represents an integer binary number. When you specify 16 for the [width] value, the input hexadecimal value represents a floating-point value.

data HAVE;             
  START= '00000485576688D7'; 
  END  = '000004855767176D';
  S16  = input(END  ,hex16.);
  E16  = input(START,hex16.);
  S14  = input(substr(END  ,3),hex14.);
  E14  = input(substr(START,3),hex14.);
  DIFF = E14-S14;
run;

START END S16 E16 S14 E14 DIFF
00000485576688D7 000004855767176D 0.024E-309 0.024E-309 4970743535469 4970743498967 -36502

 

 

[Edit:  To print the value in hex format, use the hex format 🙂  ]

ChrisNZ
Tourmaline | Level 20

If you do have numbers with 16 hexadecimal digits (which exceeds the precision offered by SAS integer values) you can read them like this to get an approximate decimal value:

data WANT;
  HEX    = '11111485576688D7'; 
  DEC15  = input(substr(HEX,2),hex15.);
  DEC1   = input(HEX  ,hex1.);
  NUMBER = DEC1*16**15 + DEC15;
run;

NUMBER=1.2297867E18

 

Patrick
Opal | Level 21

@ChrisNZ 

Because you only need a numerical data type intermediary without the need to store it in a SAS table: Could using Proc DS2 with a BIGINT eventually allow to deal with more than 16 digits with full precision?

ChrisNZ
Tourmaline | Level 20

To go back to the original question, and assuming the first hex digit can be discounted, this works:

data HAVE;             
  START= '00000485576688D7'; 
  END  = '000004855767176D';
  S15  = input(substr(START,2),hex15.);
  E15  = input(substr(END  ,2),hex15.);
  DIFF = E15-S15;
  putlog DIFF= 6. DIFF= hex.;
run;

DIFF=36502 DIFF=00008E96

 

Astounding
PROC Star

You can test what answers you are getting against the logic below, but I would think that 14 hex digits is too many for SAS to accurately store.  Notice however, that you don't need to use them all:

 

00000485576688D7    000004855767176D

 

These strings are the same for the first 11 characters.  You only need to compute:

 

diff = input( substr(end, 12), hex5.) - input(substr(start, 12), hex5.) ;

yuwda01
Calcite | Level 5

here is my code.

 

data log;                                             
   infile 'ZKQMMM9.REPORT(QT9ALOG1)';                 
   input @1 start ymddttm19.                          
         @24 end  ymddttm19.                          
         @46 startrba  hex16.                         
         @65 endrba    hex16.                         
         ;                                            
run;                                                  
data log1; set log;                                   
   time_diff = end-start;                             
   rba_diff = endrba -startrba;                       
run;                                                  
PROC PRINT DATA=log1 SPLIT="*";                       
  var start end time_diff                             
      startrba endrba rba_diff                        
  ;                                                   
format start end E8601DT19.0                          
format time_diff time8.0                              
       startrba endrba hex16. rba_diff hex.           
;                                                     
RUN;                                                  

 

and here is my output

 

                                                         time_                                                        
 Obs    start                  end                        diff            startrba              endrba    rba_diff    
                                                                                                                      
   1    2019-04-17T04:18:22    2019-04-17T06:36:57     2:18:35    00000485576688D7    000004855767176D    00000000    
   2    2019-04-17T02:50:20    2019-04-17T04:18:22     1:28:02    0000048552DD6F2E    0000048552DDFF70    00000000    
   3    2019-04-17T02:39:09    2019-04-17T02:50:20     0:11:11    00000485514BCEF7    00000485514C7A09    00000000    
   4    2019-04-17T01:24:04    2019-04-17T02:39:09     1:15:05    000004854E328DED    000004854E3328DB    00000000    
   5    2019-04-17T01:19:17    2019-04-17T01:24:04     0:04:47    000004854A13562D    000004854A13FB15    00000000    

 

I have two issues I would like to resolve.

 

1) rba_diff is not shown.

2) instead display time with 2019-04-17T04:18:22    I would like to display without T between date and time.  2019-04-17 04:18:22

 

Thanks David    

Astounding
PROC Star

For the first question, note that RBA_DIFF is being displayed.  It is 0 all the time, because SAS isn't able to store the values for STARTRBA and ENDRBA with sufficient precision to tell the difference.  I suggest you apply my earlier suggestion and don't try to store the entire value.  For example:

 

data log;                                             
   infile 'ZKQMMM9.REPORT(QT9ALOG1)';                 
   input @1 start ymddttm19.                          
         @24 end  ymddttm19.                          
         @46 startrba  $16.                         
         @65 endrba    $16.                         
         ;                               
   rba_diff = input( substr(endrba, 11), hex6.) 
   - input( substr(startrba, 11), hex6.) ;             
run;                  

For the datetime variables, SAS supplies many datetime formats.  You chose E8601DT19.0  but you don't have to use that one.  Here are some other choices:

 

http://support.sas.com/documentation/cdl/en/leforinforref/63324/HTML/default/viewer.htm#n0av4h8lmnkt...

 

These days, there are even ways to create your own datetime format using PROC FORMAT.

 

yuwda01
Calcite | Level 5

thank you for the information.  You have answered all my questions.

FreelanceReinh
Jade | Level 19

Hi @yuwda01,

 

It's great that all your questions have been answered, but it would help later readers if you marked the most helpful answer as the accepted solution, not your own "thank you" post. Could you please change that?

 

For those later readers who need to compute the exact difference D=X−Y between two non-negative hexadecimal integers X and Y of up to 26 hex digits each, here's an approach splitting the long numbers into two of length <=13 (which enables storage in a numeric variable). The result is given as a right-justified 27-character string in hexadecimal format (26 digits, padded with zeros) with a minus sign for negative numbers and a leading blank for non-negative numbers.

/* Create test data for demonstration */

data have;
length x y $26;
input x char26. +1 y char26.;
cards;
000004855767176D           00000485576688D7          
        004855767176D        485576688D7             
FEDCBA9876543210ABCDEF6789 1234567890ABCDEF0987654321
1234567890ABCDEF0987654321 FEDCBA9876543210ABCDEF6789
 F                              5                    
1                          c                         
b98286da2e88ad80           38b5ccf197e6              
a20529f5cca196DA           a20529f5cca196d8          
0                          a20529f5cca196d8          
a20529f5cca196d8           a20529f5cca196d8
;

/* Compute the differences D=X-Y */

data want(drop=m0 m1 n0 n1 lx ly);
set have;
length d $27;
lx=length(left(x));
ly=length(left(y));
m0=input(substr(right(x),max(1,length(right(x))-12)), hex13.); /* last (up to) 13 hex digits */
n0=input(substr(right(y),max(1,length(right(y))-12)), hex13.);
if lx>13 then m1=input(substr(left(x),1,lx-13), hex13.);  /* remaining (up to 13) hex digits */
else m1=0; 
if ly>13 then n1=input(substr(left(y),1,ly-13), hex13.);
else n1=0; 
if m1>n1 | m1=n1 & m0>=n0 /* i.e. "if x>=y" */
then d=' '||put(m1-n1-(m0<n0), hex13.)||put(16**13*(m0<n0)-n0+m0, hex13.);
else d='-'||put(n1-m1-(n0<m0), hex13.)||put(16**13*(n0<m0)-m0+n0, hex13.);
run;

The examples show that alignment, leading zeros or capitalization don't affect the result.

yuwda01
Calcite | Level 5

Hi,

 

how can I mark the most helpful answer as the accepted solution?

 

Thanks David

FreelanceReinh
Jade | Level 19

@yuwda01 wrote:

how can I mark the most helpful answer as the accepted solution?


  1. Click on the blue gear icon (shown below) of the currently accepted solution to open the "option menu."
  2. gear_icon.jpg

  3. Select "Not the Solution" from that menu.
  4. Click the "Accept as Solution" button of the real solution (or select "Accept as Solution" from the option menu of that post).
ChrisNZ
Tourmaline | Level 20
Please mark the most relevant reply as the solution.
Dave25
Quartz | Level 8

oops - done

Ready to join fellow brilliant minds for the SAS Hackathon?

Build your skills. Make connections. Enjoy creative freedom. Maybe change the world. Registration is now open through August 30th. Visit the SAS Hackathon homepage.

Register today!
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
  • 13 replies
  • 3550 views
  • 0 likes
  • 6 in conversation