在SAS中将十六进制字符(超过16个字节)转换为十进制数字

时间:2018-11-05 05:25:55

标签: sas hex decimal

您好,我有一个名为Hexchar的SAS字符列,其中包含十六进制字符“ 0x1ba0c56c966ee8b0000”,实际上是十进制数8154350000000000000000。我想将“ 0x1ba0c56c966ee8b0000”转换为8154350000000000000000。如果十六进制数小于16个字节,则以下函数可以完成此工作。

DexNumber=input(substr(Hexchar,3), hex16.); /* The reason why substr() function is to skip "0x" in the front */

但是,十六进制格式仅限于16个字节,不能处理更多字节。您知道将其转换为任何好的逻辑吗?

2 个答案:

答案 0 :(得分:2)

您将无法在SAS数字(64位双精度)中精确存储如此大的整数。

来自https://v8doc.sas.com/sashtml/win/numvar.htm

  

Windows下SAS变量的有效位数和长度最大的整数

| Length  | Largest Integer       | Exponential
| (Bytes) | Represented Exactly   | Notation 
+---------+-----------------------+------------
|    3    |                 8,192 | 2 ^ 13
|    4    |             2,097,152 | 2 ^ 21
|    5    |           536,870,912 | 2 ^ 29
|    6    |       137,438,953,472 | 2 ^ 37
|    7    |    35,184,372,088,832 | 2 ^ 45
|    8    | 9,007,199,254,740,992 | 2 ^ 53

因此,尽管C中的所有16位十六进制值都可以明显地适合于64位整数,但并非所有这些都可以明显地适合于SAS数字(那些> 2**53)。 64位double是IEEE标准,尽管精度有所下降,但可以处理高达10 ** 51的数字。

此代码显示两个不同的大整数分配存储为与分配的值不同的相同SAS数值。

data _null_;
  x = 837886600861902976;
  y = 837886600861902977;
  put x= 20. / y= 20.;
  if x=y then put 'Huh? Ooohhh.';
run;
---------------------
x=837886600861902848
y=837886600861902848
Huh? Ooohhh.

一种方法是将c-hex字符串分成“上”和“下”部分,并用它们的输入执行算术运算。需要注意的是,当实际的十六进制值大于2 ** 53时,将会失去清晰度/精度。

data _null_;
  length H $30;

  input H;

  put h=;

  if H =: '0x' then do;
    HX = substr(H,3); * skip over 0x;

    if (length (HX) > 15) then do;
      HX_lower = substr(HX, length(HX)-14);
      HX_upper = substr(HX, 1, length(HX)-15);
      if length (HX_lower) > 15 then put 'ERROR: ' H= 'too big for two parts';

      H_lower = input (HX_lower,hex15.);
      H_upper = input (HX_upper,hex15.);

      U = H_upper * 16**15;
      L = H_lower;

      put / H;
      put HX_upper $16. ' ->' H_upper 20. ' ->' U 25.;
      put HX_lower $16. ' ->' H_lower 20. ' ->' L 25.;

      H_num = U + L;
    end;
    else do;
      H_num = input (HX, hex15.);
    end;
  end;
  else
    put 'ERROR: ' H= 'is not c hex';

  put H= H_num= comma30.;
datalines;
0x1
0x1b
0x1ba
0x1ba0
0x1ba0c
0x1ba0c5
0x1ba0c56
0x1ba0c56c
0x1ba0c56c9
0x1ba0c56c96
0x1ba0c56c966
0x1ba0c56c966e
0x1ba0c56c966ee
0x1ba0c56c966ee8
0x1ba0c56c966ee8b
0x1ba0c56c966ee8b0
0x1ba0c56c966ee8b00
0x1ba0c56c966ee8b000
0x1ba0c56c966ee8b0000
magic!
run;

答案 1 :(得分:0)

通过了解这些精度问题,以下是我自己的转换逻辑。

data test;
长度为dum_s $ 24。 dum_s =“ 1ba​​0c56c966ee8b0000”;

do while(length(dum_s)<24);
    dum_s="0"||dum_s;
end;
    dum_dec1=input(substr(dum_s,1,8),hex8.);
    dum_dec2=input(substr(dum_s,9,8),hex8.);
    dum_dec3=input(substr(dum_s,17,8),hex8.);

    dum1=dum_dec1*16**16;
    dum2=dum_dec2*16**8;
    dum3=dum_dec3*16**0;
    dum=dum1+dum2+dum3;
    dum_ether=dum/10**18;

放入dum_ether;
运行;

以太坊交易哈希0x57662d92cb24943079dec7d83d3c39fc7a1ae958b22de58ba62c8c4cb425cab3 它的值是基于六进制的“ 0x1ba0c56c966ee8b0000”,我的上述逻辑给了我8154.35以太坊(10 ** 18倍为wei),与该站点相同。 https://etherscan.io/tx/0x57662d92cb24943079dec7d83d3c39fc7a1ae958b22de58ba62c8c4cb425cab3 当值变成浮点数时,我会意识到一些精度问题。

谢谢!