繁体   English   中英

区分整数的位

[英]Diffing the bits of an integer

我有一个 32 位整数,我通过将各个位映射到各种类型的数据来填充数据。

例如,一个部分用于氧气水平。 这是一个从 0 到 128 的值,所以我使用 7 位。

另一部分用于对象的旋转。 旋转始终围绕 x、y 和 z 三个轴旋转 0、90、180 或 270 度。 每个角度都用值 0、1、2 和 3 进行索引,所以我只需要 6 位。 围绕 x、y 和 z 旋转 90 度时,旋转存储为 010101,或围绕 x 旋转 180 度时存储为 100000。

一些部分存储为整数值,如氧气水平,但在我需要使用它们时转换为枚举。

每个部分在数据整数中彼此相邻排列,从右到左填充位。

Type :    ... | Oxygen  | Rotation |
          --------------------------
Bits:     ... | 0000000 | 000000   |
          --------------------------
Position: ... | 19-25   | 26-31    |
          --------------------------

问题

我想比较两个整数,看看有什么变化。

当一个int的氧含量为16,另一个为20时,相差增加了4个单位。 当一个旋转在所有轴上为 0,另一个旋转为围绕 x 90 度时,差异是围绕 x 旋转 90 度。

我在数据对象上有扩展方法,允许我将氧气水平作为 int 值,并将旋转作为四元数。 在 delta 数据对象上使用这些时,我想获得氧气水平的值 4,以及围绕 x 旋转 90 度的四元数。

获得两个整数值差异的最有效方法是什么?

可能的方法

我想过几种不同的方法来解决这个问题。

整数比较

由于数据是一个整数,我试图简单地从另一个中减去一个。 我从一个值为 0 的 int 开始,并将氧气水平的位设置为 16。我创建了一个新的 int,将其氧气水平设置为 20,并从最后一个减去第一个,delta 的氧气水平为 4 . 但是当我将旋转和其他数据添加到整数时,减法后的结果改变了所得的氧气水平和旋转。

我需要验证我的所有扩展方法都按预期工作。 所有单元测试都成功了,但测试可能不够好。

按位比较

另一种方法是使用各种按位运算符分别比较整个整数中的每个位。 我使用了一个 int,旋转位设置为围绕 x 90 度(位 01)。 另一个 int 将 x 旋转设置为 180 度(位 10)。 我正在寻找的 delta 值是 90 度(位 01),但我找不到任何合适的运算符来产生该结果。

这个测试让我相信我不能单独比较位。 在旋转索引的情况下,我需要将一对位视为单个值。

位数组

我阅读了 .net 的 BitArray 的文档,但无法立即看到使用它会有什么不同。

比较每个部分

比较每个位部分会产生我正在寻找的结果。 在计算差值之前,旋转位将转换为四元数,然后在将它们设置为数据整数之前转换回位。

这是我希望找到替代方法的方法。 我不希望比较器知道数据的结构,我希望找到一个更有效的解决方案。

编辑

我现在看到,在阅读了评论并进行了更多测试之后,我的案例只获取位部分的新值而不是它们更改了多少对我来说更有益。 任何保持不变的部分都应该归零。 据我所知,我唯一的选择是逐段比较数据。

再次编辑

我不确定选择哪个答案作为正确答案。 我认为我的问题不够具体,对此我深表歉意。

@harold 给出的方法在逐位比较时起作用,并且与数据结构无关。

@Pikoh 的答案逐节比较,并且可以动态化,以便该方法不需要了解数据结构。

我不确定你想要什么,但肯定可以使用典型的SWAR 技术计算所有字段的模数差异:

z = ((x | H) - (y &~H)) ^ ((x ^~y) & H)

这是 SWAP 减法的通用公式。 对于 2 位字段, H = 0xAAAAAAAA

由于只有两个位并且 SWAR 通常以不同的方式处理最高位(以防止泄漏到下一个字段),因此这些位实际上是完全分开的。


有了新要求,也没有必要对字段进行丑陋的拆分,例如:(未测试)

m = x ^ y;
m = (m | (m >> 1)) & 0x55555555;
m *= 3;
z = y & m; // maybe

这里的想法是,如果它发生了变化,xor 将在字段中的某处产生 1,然后对该字段的所有位进行 OR 并将其放入该字段的最低位,乘以 3 将其广播到该字段的所有位. & 使用新值在其他地方获取更改的字段和零,但这意味着您无法区分“更改为 0”和“未更改”。 使用m你仍然可以区分它们。

让我们看看这样的事情是否对您有帮助:

int data1 = Convert.ToInt32("00000000000000000000000000011100", 2); //sample data
int data2 = Convert.ToInt32("00000000000000000000000000101000", 2);
int xrotationposition = 26; //start positions of data
int yrotationposition = 28;

string xrotationmask = new string('0', xrotationposition) + "11" + 
                   new string('0',30 - xrotationposition); //mask to extract the data
string yrotationmask = new string('0', yrotationposition) + "11" + 
                   new string('0', 30 - yrotationposition);

int xrotation1 = data1 & Convert.ToInt32(xrotationmask, 2); //bit AND
int xrotation2 = data2 & Convert.ToInt32(xrotationmask, 2);

int yrotation1 = data1 & Convert.ToInt32(yrotationmask, 2);
int yrotation2 = data2 & Convert.ToInt32(yrotationmask, 2);

xrotation1 = (xrotation1 >> 30 - xrotationposition); //shift the bits 
                                                     to the lowest part of byte
xrotation2 = (xrotation2 >> 30 - xrotationposition);

yrotation1 = (yrotation1 >> 30 - yrotationposition);
yrotation2 = (yrotation2 >> 30 - yrotationposition);

在此执行结束时,您将获得xrotation1=1xrotation2=2yrotation1=3yrotation2=2 ,这些值似乎很容易比较。

希望这可以帮助

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM