如何在C语言中移除所有的奇数位?

3
我有一个 int 类型的数值 136970250 (1000 0010 1010 0000 0000 0000 1010),需要去除所有奇数位 (1, 3, 5, 7...)。
1000 0010 1010 0000 0000 0000 1010 -> 10 0111 0000 0011 (9987) - 因为这些位没有信息。
如何实现呢?

3
展示你的尝试,并指出问题所在。 - Jacek Cz
2
应该使用“与”运算符来获取所有偶数位。 - JeffRSon
3
不仅需要屏蔽位,而且需要实际缩短位数?您想解决的实际问题是什么?为什么要这样做(实际上是删除位,将它们移动以适应较小的数据类型)?使用案例是什么? - Some programmer dude
3
为什么不为每个字节创建一个0xAA的掩码(例如32位数字的0xAAAAAAAA),然后与原始数字进行AND操作?(或者如果您实际上想要的是偶数位,则对于每个字节使用0x55 - David C. Rankin
4
为什么这个问题被认为是“过于宽泛”的?它其实非常具体明确。 - harold
显示剩余4条评论
3个回答

5
我该如何移除所有奇数位......?我需要移除所有的奇数位(1、3、5、7...)。
原帖中的单个示例似乎是保留奇数位,因为通常最低有效位是位0。
这个答案假设代码需要保留偶数位并丢弃奇数位。轻松调整算法以保留其他位。
不需要32次迭代的循环,而是按组移位。首先成对处理所需位,然后是每4位一组,然后是每8位一组,等等。
假设我们要保留位0b .a.b .c.d .e.f .g.h .i.j .k.l .m.n .o.p
uint16_t IK_RemoveOddBits(uint32_t x) {
  // x = 0b .a.b .c.d .e.f .g.h .i.j .k.l .m.n .o.p

  x = ((x & 0x44444444) >> 1) | ((x & 0x11111111) >> 0);
  // x = 0b ..ab ..cd ..ef ..gh ..ij ..kl ..mn ..op

  x = ((x & 0x30303030) >> 2) | ((x & 0x03030303) >> 0);
  // x = 0b .... abcd .... efgh .... ijkl .... mnop

  x = ((x & 0x0F000F00) >> 4) | ((x & 0x000F000F) >> 0);
  // x = 0b .... .... abcd efgh .... .... ijkl mnop

  x = ((x & 0x00FF0000) >> 8) | ((x & 0x000000FF) >> 0);
  // x = 0b .... .... .... .... abcd efgh ijkl mnop

  return x;
}

为了去掉偶数位,修改上面的代码加上 x >>= 1 或者简单地写成

uint16_t IK_RemoveEvenBits(uint32_t x) {
  return IK_RemoveOddBits(x >> 1);
}

提示:在编写这些移位类型问题时,最好使用无符号类型。不需要扩展有符号整数的符号位。

4
  1. 创建一个新的整数,将其初始化为0
  2. 使用for循环迭代从0到原始整数位数的一半(不包括)
  3. 对于每次循环,将原始整数与(1 << (i * 2))进行AND运算。如果它不为零,则将新整数与(1 << i)进行OR运算
  4. 完成

编辑:再次查看示例,看起来您实际上想要删除所有偶数位,而不是奇数位。所以在第3步中,只需将原始整数与(1 << (i * 2 + 1))进行AND运算。

编辑2:从您的示例中看来,似乎您正在使用32位整数,但为了涵盖所有情况,我将在第3步中添加,如果您的整数实际上是64位,则应将1替换为1ULL


3
奇数位可以在几个位逆序步骤中被删除(假设它们已经清零),例如下面这个:
x = bit_permute_step(x, 0x22222222, 1);  // Bit index swap 0,1
x = bit_permute_step(x, 0x0c0c0c0c, 2);  // Bit index swap 1,2
x = bit_permute_step(x, 0x00f000f0, 4);  // Bit index swap 2,3
x = bit_permute_step(x, 0x0000ff00, 8);  // Bit index swap 3,4

calcperm 生成
这可以通过扩展常量并添加一个额外的步骤轻松地扩展到64位。如果您想要移除偶数位,您可以先右移1位。 bit_permute_step 的定义为:
t_bits bit_permute_step(t_bits x, t_bits m, t_uint shift) {
  t_bits t;
  t = ((x >> shift) ^ x) & m;
  x = (x ^ t) ^ (t << shift);
  return x;
}

使用适当的类型。
对于现代英特尔处理器(以及Ryzen,但在那里速度较慢),更内置的解决方案是使用_pext_u32和一个包含您想要保留所有位的掩码。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接