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
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.
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 🙂 ]
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
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?
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
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.) ;
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
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:
These days, there are even ways to create your own datetime format using PROC FORMAT.
thank you for the information. You have answered all my questions.
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.
Hi,
how can I mark the most helpful answer as the accepted solution?
Thanks David
@yuwda01 wrote:how can I mark the most helpful answer as the accepted solution?
oops - done
SAS Innovate 2025 is scheduled for May 6-9 in Orlando, FL. Sign up to be first to learn about the agenda and registration!
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.
Ready to level-up your skills? Choose your own adventure.