如何正确地进行按位运算?

时间:2015-05-12 03:08:52

标签: matlab bit-manipulation octave

我正在对二进制数据进行分析。假设我有两个uint8数据值:

a = uint8(0xAB);
b = uint8(0xCD);

我想从a获取较低的两位,从b获取整个内容,以获得10位值。在C风格,它应该是:

(a[2:1] << 8) | b

我尝试了bitget

bitget(a,2:-1:1)

但这只是给了我单独的[1, 1]逻辑类型值,它不是标量,不能在以后的bitshift操作中使用。

我目前的解决方案是:

  1. 制作a|bab):

    temp1 = bitor(bitshift(uint16(a), 8), uint16(b));

  2. 左移6位以摆脱a的高6位:

    temp2 = bitshift(temp1, 6);

  3. 右移6位以消除前一个结果中的低零:

    temp3 = bitshift(temp2, -6);

  4. 将所有这些放在一行:

    result = bitshift(bitshift(bitor(bitshift(uint16(a), 8), uint16(b)), 6), -6);
    

    这似乎并不高效,对吧?我只想获得(a[2:1] << 8) | b,并且需要很长的表达才能获得该值。

    如果有解决此问题的方法,请告诉我。

3 个答案:

答案 0 :(得分:2)

由于您使用的是Octave,因此您可以使用bitpackbitunpack

octave> a = bitunpack (uint8 (0xAB))
a =

   1   1   0   1   0   1   0   1

octave> B = bitunpack (uint8 (0xCD))
B =

   1   0   1   1   0   0   1   1

一旦你以这种形式获得它们,就很容易做到你想做的事情:

octave> [B A(1:2)]
ans =

   1   0   1   1   0   0   1   1   1   1

然后简单地用零填充并将其打包成一个整数:

octave> postpad ([B A(1:2)], 16, false)
ans =

   1   0   1   1   0   0   1   1   1   1   0   0   0   0   0   0

octave> bitpack (ans, "uint16")
ans = 973

答案 1 :(得分:0)

or相当于处理整数时的加法

result = bitshift(bi2de(bitget(a,1:2)),8) + b;

e.g

a = 01010111
b = 10010010

result =       00000011            100010010
       = a[2]*2^9 + a[1]*2^8   +       b

另一种方法可能是

result = mod(a,2^x)*2^y + b;

其中x是您要从ay中提取的位数,是ab的位数,你的情况:

result = mod(a,4)*256 + b;

接近C解决方案的额外替代解决方案:

result = bitor(bitshift(bitand(a,3), 8), b);

答案 2 :(得分:0)

我认为重要的是要准确解释&#34;(a [2:1]&lt;&lt; 8)| B&#34;正在做。

在汇编中,引用各个位是单个操作。假设所有操作都采用完全相同的时间并且&#34;高效&#34; a [2:1]开始看起来非常低效。

便利声明实际上是(a&amp; 0x03)。

如果您的编译器实际上将uint8转换为uint16,具体取决于它的移位量,那么这不是一个免费的&#39;操作本身。实际上,编译器将要做的是首先清除&#34;内存&#34;大小为uint16,然后复制&#34; a&#34;进入该位置。这需要一个额外的步骤(清除&#34;内存&#34;(注册)),这通常是不需要的。

这意味着你的陈述实际上是(uint16(a&amp; 0x03)&lt;&lt; 8)| UINT16(b)中

现在是的,因为你正在做两个移位的力量,你可以移动到AH,将b移动到AL,并将AH移动到0x03并将其全部移出,但这是编译器优化和不是你的C代码所说的。

关键是直接将该语句翻译成matlab会产生

BITOR(位位移(UINT16(BITAND(A,3)),8),UINT16(b))的

但是,应该注意的是,虽然它不像(a [2:1]&lt;&lt; 8)| TERSE | b,&#34;高级操作的数量&#34;是一样的。

请注意,所有脚本语言在启动每条指令时都会非常慢,但会快速完成所述指令。 Python的简洁本质并不是因为&#34; terse更好&#34;但是要创建语言可以识别的简单结构,以便它可以很容易地进入矢量化操作模式并快速开始执行代码。

这里的要点是你有一个&#34;开销&#34;调用bitand的成本;但是当在阵列上操作时,它将使用SSE和#34;开销&#34;只付一次。 JIT(及时)编译器通过减少开销调用和为当前执行的代码段创建临时机器代码来优化脚本语言可能能够识别出对按位操作链的类型检查只需要在初始输入上进行,因此进一步减少了运行时间。

非常高级的语言与C等高级语言完全不同(并且令人沮丧)。您放弃了对代码执行的大量控制,以便于代码生成;是否matlab实际上已经实现了uint8,或者它是否实际上使用了double并截断它,你不知道。对原生uint8的按位操作非常快,但是要从float转换为uint8,执行按位操作,并且转换回来很慢。 (从历史上看,Matlab一直使用双打,只根据你指定的类型进行四舍五入)

即使是现在,octave 4.0.3也有一个编译后的bitshift函数,对于bitshift(其中一个(&#39; uint32&#39;), - 32)会导致它回退到1. BRILLIANT! VHLL让你受语言的支配,它不是关于你编写代码的简洁程度或冗长程度,而是爆破语言决定如何解释它并执行机器级代码。因此,uint32(floor(ones /(2 ^ 32)))实际上更快,更准确,而不是移位。