2

我有一个文件(tmp1),它是一个数字列表,格式如下:

4373610497
4416339969
4426498049
4435738625

这里的每个 64 位数字实际上由多个 16 位字段组成,这些字段具有我感兴趣的数字。

例如(这里只显示重要的 48 位):

4435738625 = 0000000000000001 0000100001100100 0000000000000001

我想要的数字是:

a= 0000000000000001 = 1
b= 0000100001100100 = 2148
c= 0000000000000001 = 1

这是我现在用来执行此操作的代码 - 但它非常缓慢。输入文件包含 500K 到 100 万行,因此我正在尝试寻找更快或更有效地执行此操作的方法。

while read line; do
  a=$((((line >> 32)) & 65535));
  b=$((((line >> 16)) & 65535));
  c=$((line & 65535));
  printf "$a $b $c\n" >>tmp2
done <tmp1

我需要在 FreeBSD 机器上运行它——所以我不能使用 gawk。而且 awk 似乎不允许按位操作。

4

3 回答 3

3

有一个解决方案,可以满足您的需求。但如果它比你的工作得更快,我不能说。你可以测试。

在这里,我只是在您的示例中使用一个数字进行测试,您可以将其包装在一个循环中。

kent$  printf "%064s\n" "$(bc <<< "obase=2;4435738625")"|sed -r 's/.{16}/ibase=2;&\n/g'|bc
1
2148
1
于 2013-10-16T13:53:35.863 回答
2

你真的不需要位操作来做到这一点。例如:

awk '{val = $1;
      c = val%65536; val = (val-c)/65536;
      b = val%65536; val = (val-b)/65536;
      a = val%65536;
      print a, b, c}'

但是,awk 值不是 64 位整数;它们是双精度数,只有 53 位精度。因此,只有当您的数字都不大于 9007199254740992 (2 53 ) 时,这才有效。

您可能会考虑使用不同的工具,例如bcpython。如果你有 GNUbc可用(这是可能的,即使在 BSD 系统上也是如此),以下非常相似的程序应该可以工作:

bc <(echo 'define s(val) {
             c = val%65536; val = (val-c)/65536
             b = val%65536; val = (val-b)/65536
             a = val%65536;
             print a," ",b," ",c,"\n";
           }
           while(1){v=read(); if (v==0) break; v=s(v);}') \
   < datafile

请注意:bc读取函数不检查文件结尾,因此您需要放入某种显式终止符。我0在上面的脚本中使用过,但在您的情况下这可能是一个有效的输入。您可能希望将其更改为-1或其他一些特殊值。无论如何,请确保您的数据文件实际上以该值终止。

于 2013-10-16T15:46:39.610 回答
0

bcobaseset一起使用,并记录其行为

对于大于 16 的基数,bc 使用多字符数字方法打印数字,其中每个较高的基数都打印为以 10 为基数的数字。多字符数字由空格分隔。

$ bc -q <(echo "obase=65536") tmp1 <(echo "halt")
00001 01200 00001
00001 01852 00001
00001 02007 00001
00001 02148 00001

如果您需要稍微awk调整输出,例如删除前导零或处理可变数量的列(如果 ≥ 2 48则为 4 列,如果 ≥ 2 32则为 3等):

| nawk '{printf("%i %i %i\n",(NF>2)?$(NF-2):0,(NF>1)?$(NF-1):0,$NF)}'

这些<(echo ...)部分允许bcecho输出作为文件读取,这是将这些行添加到每个输入文件的顶部和底部的快速替代方法。

于 2013-10-17T14:48:27.127 回答