我应该使用什么位移技术?

时间:2009-10-20 13:04:23

标签: bitwise-operators

我很想知道人们为自己建立了哪些使用模式,以便在现代环境中利用位移,例如客户端/服务器,Web,桌面开发。除了设备驱动程序之外,软件开发中的位移是什么用途,asm?

我应该使用什么按位操作/移位技术?我可以重用哪些算法?

8 个答案:

答案 0 :(得分:3)

这实际上取决于语言,应用程序的开发等。话虽如此,我会看Hacker's Delight。我认为它会有你想要的东西。

答案 1 :(得分:3)

最近发现,当找到极大数组的中点时,基本上每个现有的库二进制搜索都会出现溢出错误。在Java中实现的修复使用右移而不是除法。请参阅this article

答案 2 :(得分:2)

这些天按位操作的主要用途必须是标记字。 (或者也许只是我?:-)这允许您使用一个整数变量以紧凑而有效的方式存储多个布尔值。为此,您不使用移位,只使用AND和OR运算来测试和设置不同的位值。这通常可以用来使代码更有效率(传递一个32位整数而不是32个bool数组作为参数;在单个按位运算中设置/清除/切换/测试任意一组标志,等等)< / p>

另一个常见用途是将数据压缩为更紧凑的格式(通常用于通信,文件格式以及内存紧张的嵌入式控制器等应用程序)。例如,如果您的数字介于0到25之间,那么您可以将其存储为5位(足以存储值0..31),而不是使用字节(8位)或int(通常32位或更多)。

在某些体系结构/编译器上,您可以通过使用位移和添加的组合替换乘法/除法运算来加快操作 - 但是大多数现代编译器将在您发现这样做的机会时为您执行此操作。例如如果使用优化编译器,“a * = 2”可能会转换为“a&lt;&lt; = 1”。

然后有一些新颖的用途有时可以派上用场(参见另一个答案中已经提到过的Hackers Delight)。

如果您只是在使用Windows窗体或Web类型应用程序,那么很可能不会非常需要使用按位操作,但即使在这些高级环境中,您在某些情况下也可以使用按位操作使事情更清洁,更有效率。或者至少让自己觉得自己有点像水管工,有点像工匠: - )

答案 3 :(得分:2)

我可以想到进行位移操作的3个理由:

一,作为进行整数乘法和除法的替代方法。左移1位相当于乘以2;右移1个地方相当于除以2.我很少这样做,因为它使代码更难阅读和理解,以获得轻微的性能提升。如果要乘以或除以常数,某些编译器足够聪明,可以为您执行此操作,在这种情况下,增益为零。这些天我唯一一次使用这种技术的是计算密集型的东西。如果我正在编写一个数学库,其中包含对无限系列的许多项的大量评估 - 比如评估日志和正弦 - 我可能会使用这样的东西。否则,在我的拙见中,不值得让下一个程序员混淆的代价。

二,结合AND和OR,作为将多个逻辑字段打包到单个字段中的一种方法。假设您有一个字段,其可能值范围为0-3,另一个字段为0-7。第一个可以容纳2位,第二个可以容纳3个。所以你可以将两者打包成一个字节。您可以使用以下代码将它们放入:

byte b=(f1<<3) | f2;

你可以通过以下方式解决这些问题:

f2=b & 0x07;
f1=(b>>3) & 0x03;

在Good Old Days,当我使用6kB RAM的计算机上工作时,我做了很多事情,把我需要的所有数据都塞进内存中。今天,当我的桌面上有一个千兆字节,服务器上有几千兆字节时,执行此操作的额外复杂性 - 阅读“更多地方犯错” - 使其不值得。如果您正在为手机或其他一些内存受限的环境编写嵌入式代码,那么您可能还需要做这样的事情。我想如果你正在开发一个项目,你需要一些真正大量的内存数据 - 如果你正在分析一个人类基因组或什么 - 这可能是必要的。但是,在大多数情况下,知道如何做到这一点就像知道如何使用幻灯片规则:一个有趣的历史遗迹,今天没什么实用价值。

三,在读取或写入磁盘时在数据类型之间进行转换,或者与具有不同数据存储格式的另一个系统进行通信。例如,假设您要将4字节二进制数写入磁盘。您知道读取此文件的某些计算机首先存储具有最高有效字节的整数,而其他计算机首先存储最低有效字节。要确保两者都能正确读取数据,您必须存储它并以一致的方式检索它。因此,您选择一个字节顺序并强制它以这种方式存储。像:

for (int p=0;p<4;++p)
{
  byte b=i & 0xff;
  out.write(b);
  i=i>>8;
}

这是我现在唯一一次使用比特移位。

答案 4 :(得分:1)

这是我用来操作像素缓冲区的位移和屏蔽的巧妙应用。

bool pBuffer::GetPixel(unsigned int x, unsigned int y)

{

char c = blocks[((y * width) + x) / 8];

return (bool)((c >> (((y * width) + x) % 8) & 1));

}

宽度和高度是所谓的二维数组的已知尺寸。但是,数组(blocks [])只是一维的。 char中的每个位代表一个打开或关闭的像素。

此功能用于我的凸包算法实现,以便允许用户使用最少量的内存在屏幕上绘制2D级别。

关键是,如果您知道位是如何表示数据的,那么您可以通过位移来对该数据进行偷偷摸摸的事情。

答案 5 :(得分:1)

答案 6 :(得分:1)

它们对于位掩码枚举非常有用,例如

  enum flags {
    IMAGE_FLIP_HORIZONTAL   =1 << 0,
    IMAGE_FLIP_VERTICAL     =1 << 1,
    IMAGE_DESATURATE        =1 << 2,
    IMAGE_INVERT            =1 << 3,
    IMAGE_NOALPHA           =1 << 4 
  };

然后您可以提供允许

的API
loadImage("pirate.gif", IMAGE_DESATURATE | IMAGE_FLIP_HORIZONTAL);

如果你曾经使用过libpng,你可能会使用这种类型的枚举。在pngread.c中,文件末尾有一个块,它使用这样的掩码来应用转换:

#if defined(PNG_READ_INVERT_SUPPORTED)
   /* invert monochrome files to have 0 as white and 1 as black
    */
   if (transforms & PNG_TRANSFORM_INVERT_MONO)
       png_set_invert_mono(png_ptr);
#endif

#if defined(PNG_READ_BGR_SUPPORTED)
   /* flip the RGB pixels to BGR (or RGBA to BGRA)
    */
   if (transforms & PNG_TRANSFORM_BGR)
       png_set_bgr(png_ptr);
#endif

#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED)
   /* swap the RGBA or GA data to ARGB or AG (or BGRA to ABGR)
    */
   if (transforms & PNG_TRANSFORM_SWAP_ALPHA)
       png_set_swap_alpha(png_ptr);
#endif

#if defined(PNG_READ_SWAP_SUPPORTED)
   /* swap bytes of 16 bit files to least significant byte first
    */
   if (transforms & PNG_TRANSFORM_SWAP_ENDIAN)
       png_set_swap(png_ptr);
#endif

答案 7 :(得分:0)

从“现代”的角度来看?不...除非您使用C或需要非常优化您的应用程序 首先,位移可以用于两件事:

  • 作为乘法/除法的快速替代方案,或者无法乘法/除法的架构(请参阅下面的示例)
  • 作为获取位域值( EVIL
  • 的实用程序

1的位移相当于除以2或乘以2并且更快。亲自检查一下:64>>1==3264<<1==128。实际上,软件乘法/除法实现通常基于移位。

PS。 行。 只是我的意见。我知道bitfields是你童年时代的事,但是,请问,这只是一个意见。