你曾经在实际项目中使用过位移吗?

您是否曾经在实际的编程项目中使用过 位移?大多数(如果不是全部的话)高级语言都有 shift 操作符,但是什么时候真正需要使用它们呢?

38075 次浏览

我一直使用它们的一个地方是在跨平台应用程序调换整数的端点时。当对2D 图形进行分块处理时,它们有时也会派上用场(与其他位操作操作符一起)。

我使用过它们几次,但几乎总是用于解析二进制文件格式。

  • 为枚举创建良好的标志值(而不是手动键入1、2、4...)
  • 从位字段解压缩数据(许多网络协议使用它们)
  • Z 曲线遍历
  • 性能黑客

我想不出有多少案例是在使用它们的时候发生的。通常情况是相反的——有一些特定的问题,结果表明使用位操作将产生最好的结果(通常在性能时间和/或空间方面)。

是的,我以前写过加密算法,这个肯定用过。

当使用整数等来跟踪状态时,它们也很有用。

我经常在图像压缩/解压缩中使用它们,位图中的位被压缩。使用 http://en.wikipedia.org/wiki/Huffman_coding,被压缩的内容由不同数量的位组成(它们并不都是字节对齐的) ,因此在编码或解码时需要对它们进行位移。

例如,在 C、 C + + 等语言的加密方法实现中。二进制文件,压缩算法和逻辑列表操作-位操作总是好的 =)

快速傅里叶变换ー FFT 和它的 Cooley-Tukey 技术将需要使用位移操作。

是的,在 MPEG2-2传输流解析器中使用了它们。它更容易,也更容易阅读。

位移不能解决高层次的编程问题,但有时我们必须解决低层次的问题,而且不需要用 C 语言编写单独的库也很方便。我猜那是它最常被使用的时候。

我个人用它来编写 EBCDIC字符集转换器的编码器。

换班很快的。早在除法和模运算出现之前,它们就已经在 CPU 指令集中实现了。我们中的许多人使用位移来进行算术运算,这在铅笔和纸上很简单,但在我们的 CPU 上却不可用。

例如:

  • 我在项目中使用过位移 包括分解大型复合材料 成为他们的主要因素。
  • 我也使用了位移 求根的平方和立方 任意大的整数。

我必须编写一个程序来解析。DVD 光盘上的 ifo 文件。这些文件解释了光盘上有多少标题、章节、菜单等等。它们是由各种大小和排列的填充块组成的。我怀疑许多二进制格式需要类似的位移。

我看到过当多个标志被用作属性参数时使用的按位运算符。例如,数字4 = 100意味着设置了三个标志之一。这不利于公共 API,但在特殊情况下可以加快处理速度,因为检查位很快。

我写的每一个 bitblt-er 都不可能完成左右滑动位的能力。

我曾经在游戏中使用它们将一堆标志打包到一个字节/字符中,以便保存到一个数据卡中。比如存储可解锁的状态等等。现在不需要这么多,但可以节省工作。

是的。 正如你可能怀疑的那样,它最有可能出现在低级编程中,例如开发设备的驱动程序。但是,我在一个 C # 项目中工作,我必须开发一个从医疗设备接收数据的 Web 服务。设备存储的所有二进制数据都被编码到 SOAP 包中,但是二进制数据被压缩和编码。所以要解压缩它,你必须做很多很多的位操作。此外,你必须做大量的位移动来解析出任何有用的信息,例如设备序列号是第二个字节的下半部分,或者类似的东西。 我还看到一些人。NET (C #)世界使用位掩码和标志属性,我个人从来没有这样做的冲动。

我在一个嵌入式系统项目中使用它,该系统必须读取显示器的 EDID 数据。 EDID 中的一些数据是这样编码的:

字节 # 3:
水平下料——低于8位
第四节:
下咬合: 水平下料——上4位
上咬: 别的东西

我仍然为硬件中没有浮点支持的系统编写代码。在这些系统中,几乎所有的算法都需要位移。

另外,您还需要转移来生成散列。多项式算术(CRC,里所码是主流应用)或者也使用移位。

然而,使用移位仅仅是因为它们很方便,并且准确地表达了作者的意图。如果您愿意,可以使用乘法来模拟所有位移,但是这将更难编写,可读性更差,有时速度更慢。

编译器检测乘法可以减少到移位的情况。

是的,我用过很多次。在位掩码非常普遍的嵌入式硬件中,位的微调非常重要。它在游戏编程中也很重要,当你需要最后一点性能的时候。

编辑: 另外,我经常使用它们来操作位图,例如改变颜色深度,或者转换 RGB <-> BGR。

在与“低电平”设备、 eq 数字以太网 IO 盒或 PLC 的通信时,也需要进行位移,这些设备通常将单个输入/输出值包装成字节。

当将数字从 little endian 格式转换为 big endian 格式时,反之亦然

是的,但还是需要。

例如,在我的工作中,我们通过串口 COMx 开发与 PLC 通信的软件。处理字节内的位是必要的,我们使用 shift left/right 和逻辑操作符 OR、 XOR 和 AND。

例如,假设我们需要打开 字节的位3(从右到左) :

0001001-> 00001101

这样做的效率要高得多:

Byte B;


B := B OR 4; //100

而不是:

Byte B = 0;
String s;  // 0 based index


s = ConvertToBinary (B);
s[5] = "1";
B := ConvertToDecimal (s);

问候。

是的,当在 Java 和 C # 应用程序之间执行二进制通信时,一个是大端字节排序,另一个是小端字节排序(不一定是这种排序)。我创建了一个 InputStream 类,它可以读取具有不同字节顺序的数字,它使用字节转换来工作。

有时候,当你想在一个长的4个字节中放入4个短片时,可以使用字节移位。我想我很多年前就这么做了。

当我用汇编语言写代码时,我的代码充满了位移和屏蔽。

也用了不少 C 调。

在 JavaScript 或服务器语言中没有做过很多。

也许最好的现代用法是逐步遍历一个由表示为1和0的布尔值组成的数组。我过去总是向左移动并检查汇编中的符号位,但在较高级别的语言中,您需要与值进行比较。

例如,如果您有8位,您可以用“ if (a > 127){ ... }”检查顶部位。然后你左移(或乘以2) ,做一个“和”与127(或减去256如果最后一位被设置) ,并再做一次。

是的,位移一直被用在低级嵌入式软件中。它也可以作为一个几乎是魔术的把戏,执行极快的数学运算,看看

Http://betterexplained.com/articles/understanding-quakes-fast-inverse-square-root/

是的,一直都是。就像这些用于打包和解包一个3空间坐标到/从一个32位整数的宏:

#define Top_Code(a, b, c)           ((((a) + x) << 20) | (((b) + y) << 10) | ((c) + z))
#define From_Top_Code(a, b, c, f)   (a = (((f) >>> 20) - x), b = ((((f) & 0xffc00) >>> 10) - y), c = (((f) & 0x3ff) - z))

我曾经(很多很多年前)为一个项目编写了一个输出例程,该项目使用 Excel Oper 结构创建了 Excel 电子表格。这是一个二进制文件共振峰,需要大量的位处理。下面的链接给出了一个风味的运算结构 Safari Books

我在一家外部设备制造商工作。我遇到过,并且几乎每天都不得不实现使用位移的代码。

我在 C # 中做了一些移位。该应用程序需要规范化的语音音频输入,这需要在音频样本水平的几个数学操作。

是的。特别是在使用控制和状态字节作为硬件驱动程序的仿真器中。控制字节中的每个位都有特殊的含义,状态字节中的每个位都有特殊的含义。

求给定数字大于等于2的最近幂:

1 << (int)(ceil(log2(given)))

需要的硬件纹理,不支持任意纹理大小。

我用它来计算 CRC。

位变换在解码网络游戏协议中有着广泛的应用。这些协议被设计为尽可能地使用一点带宽,所以不用在 int32中传输服务器上的玩家数量、姓名等等,所有的信息都被打包成尽可能少的字节。现在大多数人都在使用宽带,这并不是必须的,但是当它们最初被设计出来的时候,人们用56K 调制解调器来玩游戏,所以每一个位都很重要。

这方面最突出的例子是 Valve 的多人游戏,尤其是《反恐精英》 ,反恐精英:起源。Quake3协议也是一样的,但是“不真实”并没有那么简单。

下面是一个例子(. NET 1.1)

string data = Encoding.Default.GetString(receive);


if ( data != "" )
{
// If first byte is 254 then we have multiple packets
if ( (byte) data[0] == 254 )
{
// High order contains count, low order index
packetCount = ((byte) data[8]) & 15; // indexed from 0
packetIndex = ((byte) data[8]) >> 4;
packetCount -= 1;


packets[packetIndex] = data.Remove(0,9);
}
else
{
packets[0] = data;


}
}

当然,您是否将其视为一个真正的项目或者仅仅是一个业余爱好(在 C # 中)取决于您自己。

当然可以。处理 亲和力面具需要利用位移。

例如,您可能希望限制一个应用程序使用不超过给定数量的处理器(为了使用每个处理器赚钱)-您将使用位移来计算亲和掩码中的位?

另一个非常常见的事情是在提取字节的高 一点点时做4位移位,即。

#define HIGH_NIBBLE(byte) (((byte) >> 4) & 0x0F)
#define LOW_NIBBLE(byte)  ( (byte)       & 0x0F)

我已经使用新的加密结构做了一些工作,在同态加法器后面隐藏了序列化结构(以及随后对它们的更新)。许多散列也依赖于位操作; 在它们之间移动。

涉及到大量的位移和讨厌的大数运算; 全部在 Java 中(不可否认,这是一个参考/研究实现)。

还完成了压缩项目(GZIP impl。特别是) ,这里需要频繁地打包位; 不能想象没有 < < and > > (或 > > > > ,如果你在 Java 中)。

基本上,如果您正在使用加密或压缩,那么很有可能需要在某一点上进行位移。

我以前在一个网络项目中使用过位移。它是一个电子商务应用程序,其中每个产品都有许多可配置的属性。用户可以选择他们想要的属性,UI 将更新以提供所选选项的定价和 SKU。

与其在数据存储中搜索与用户选项相匹配的 SKU,不如每个选项组合对应一个特定的 hash,它实际上是一个使用位数学创建的数字。我允许每个选项有4位(16个组合) ,最多5个选项,所以总共有20位。为了从用户的选项中计算散列,我将循环遍历添加到散列值中的每个编号属性:

for(var i = 0; i < getSku.arguments.length; i++)
{
index = getAttributeIndex(i, getSku.arguments[i]);
hash += (index+1) << (4*i);
}

这比通过潜在的数百个 SKU 进行循环(每次比较最多5个值)要快得多。

No, I never really have to use them. I think that these binary operation are a bit deprecated for high level language.. As someone said, it can always be emulated with other mathematic expressions, and since those are hardly ever used, they could be built in an external library. Bit shifting in ruby or python sounds really weird to me, kind of like mixing high and low level.

我用它们做过扑克牌评估。

扑克牌表示为一个64位无符号整数,对于手中的每张牌,都有一个 1位。通过移动和掩蔽的组合,你可以问一些问题,比如“给我手上至少有3张牌的所有等级”等等。

它的速度相当快,但我已经学到了更快的方法,其中手被表示为一个字节数组。

大多数数据包仍然是位编码的。如果您使用的是任何类型的低级网络通信,那么您将不得不使用比特。

同时分析包含声音和视频的数据包——我相信即使是 MP3标签也会使用一些比特。

最重要的是,不熟悉位操作意味着您很可能错过实现某些操作的更好方法。我的意思是,如果你正在处理50亿个有序对象的存在,这就是能够很容易地将它们全部放入内存中进行即时查找或者每次都在文件中查找的区别——在这样的任务中,我会说那些自称是软件工程师的人在没有进行位操作的情况下实现了这些对象,他们在他们的工作中是不称职的。

我使用它来实现 UTF-8和 UTF-32之间的转换。

是的。

位移在嵌入式应用程序中非常有用,因为当内存紧张、速度决定一切的时候。

例如,不需要进行昂贵的乘法运算,只需要使用加法和位移就可以执行相同的计算,这样可以大大节省时间:

c := 0
while b != 0
if (b and 1) != 0
c := c + a
shift a left by one
shift b right by one
return c

我是计算机科学专业的毕业生,我已经在使用位移了。

他们很好的存储旗帜,与哈希等工作,人们已经说过。

我曾经使用按位操作来压缩一个小整数(2字节)值和一个整数中的2个字符。与我同事的项目相比,这节省了我很多记忆。

这些操作有时在算术上也非常快,例如,当你必须扩展 double 类型或者使用函数来使用浮点数来操作浮点数据时(参见浮点算术的标准)。