按位运算的实际应用 [英] practical applications of bitwise operations

查看:146
本文介绍了按位运算的实际应用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述


  1. 你使用什么样的位操作呢?

  2. 他们为什么这么方便?

  3. 可以有人请推荐一个很简单的教程?


解决方案

虽然每个人似乎都迷上了用例的标志,这不是位运算符的唯一的应用程序(虽然可能是最常见)。另外C#是一个足够高的水平语言,其他的技术可能会被很少使用,但它仍然是值得了解他们。这是我能想到的:


<< >> 运营商能迅速繁殖以2的幂当然,.NET JIT优化器可能会为你做这个(和另一种语言的任何像样的编译器也一样),但如果你每微秒真的心乱了,你就可以写这是肯定的。

对于这些运营商的另一个常见用途是东西两个16位整数到一个32位整数。这样的:

  INT结果=(shortIntA<< 16)| shortIntB;

这是直接连接的Win32函数,有时用这一招遗留原因常见的。

和,当然,这些操作符的时候你想混淆的初出茅庐,到一门功课的问题提供一个答案的时候就像是有用的。 :)

在任何实际code,虽然你会好得多用乘法来代替,因为它有一个更好的可读性和JIT它优化到 SHL SHR 指令反正所以没有性能损失。


不少好奇的招数对付 ^ 操作符(XOR)。这实际上是一个非常强大的运营商,因为以下属性:


  • A ^ B ==乙^ A

  • A ^ B ^ A ==乙

  • 如果您知道 A ^ B 那么它是不可能告诉什么 A B 的,但如果你知道他们中的一个,就可以计算出其他。

  • 运营商不一样,从乘法/除法/加法/减法任何溢出遭殃。

一对夫妇的招数我一直在使用这个操作符看出:

交换两个整型变量,而中介变量:

  A = A ^ B //一个是现在A和B的XOR
B = A ^ B // B现在是原厂A
A = A ^ B // A现在的正本提单

双向链表,每个项目只有一个额外的变量。这将在C#中很少使用,但它可能会派上用场的嵌入式系统的底层编程,每一个字节计数。

我们的想法是,你跟踪指针的第一个项目的;该指针的最后一个项目;并为每一个项目你追踪 pointer_to_ $ P $ ^ pvious pointer_to_next 的。这种方式可以从任何一端,但开销遍历列表只是一个传统的链表的一半。这里的C ++ code遍历:

  ItemStruct * CURRENTITEM =与firstItem,* previousItem = NULL;
而(CURRENTITEM!= NULL)
{
    //与CurrentItem-&GT工作;数据    ItemStruct * NextItem = CURRENTITEM ^ previousItem;
    previousItem = CURRENTITEM;
    CURRENTITEM = NextItem;
}

要从你只需要从与firstItem 的第一行更改为 LastItem 结束遍历。这是另一个存储器中保存在那里。

在这里我使用了的另一个地方^ 在C#定期操作员时,我有来计算我的类型的哈希code这是一个复合型。这样的:

 类Person
{
    字符串名字;
    字符串姓氏;
    INT年龄;    公众诠释覆盖GetHash code()
    {
        返回(名字== NULL?0:FirstName.GetHash code())^
            (姓氏== NULL?0:LastName.GetHash code())^
            Age.GetHash code();
    }
}

  1. What have you used bitwise operations for?
  2. why are they so handy?
  3. can someone please recommend a VERY simple tutorial?

解决方案

Although everyone seems to be hooked on the flags usecase, that isn't the only application of bitwise operators (although probably the most common). Also C# is a high enough level language that other techniques will probably be rarely used, but it's still worth knowing them. Here's what I can think of:


The << and >> operators can quickly multiply by a power of 2. Of course, the .NET JIT optimizer will probably do this for you (and any decent compiler of another language as well), but if you're really fretting over every microsecond, you just might write this to be sure.

Another common use for these operators is to stuff two 16-bit integers into one 32-bit integer. Like:

int Result = (shortIntA << 16 ) | shortIntB;

This is common for direct interfacing with Win32 functions, which sometimes use this trick for legacy reasons.

And, of course, these operators are useful when you want to confuse the inexperienced, like when providing an answer to a homework question. :)

In any real code though you'll be far better off by using multiplication instead, because it's got a much better readability and the JIT optimizes it to shl and shr instructions anyway so there is no performance penalty.


Quite a few curious tricks deal with the ^ operator (XOR). This is actually a very powerful operator, because of the following properties:

  • A^B == B^A
  • A^B^A == B
  • If you know A^B then it's impossible to tell what A and B are, but if you know one of them, you can calculate the other.
  • The operator doesn't suffer from any overflows like multiplication/division/addition/subtraction.

A couple of tricks I have seen using this operator:

Swapping two integer variables without an intermediary variable:

A = A^B // A is now XOR of A and B
B = A^B // B is now the original A
A = A^B // A is now the original B

Doubly-linked list with just one extra variable per item. This will have little use in C#, but it might come in handy for low level programming of embedded systems where every byte counts.

The idea is that you keep track of the pointer for the first item; the pointer for the last item; and for every item you keep track of pointer_to_previous ^ pointer_to_next. This way you can traverse the list from either end, yet the overhead is just half that of a traditional linked list. Here's the C++ code for traversing:

ItemStruct *CurrentItem = FirstItem, *PreviousItem=NULL;
while (  CurrentItem != NULL )
{
    // Work with CurrentItem->Data

    ItemStruct *NextItem = CurrentItem ^ PreviousItem;
    PreviousItem = CurrentItem;
    CurrentItem = NextItem;
}

To traverse from the end you just need to change the very first line from FirstItem to LastItem. That's another memory saving right there.

Another place where I use the ^ operator on a regular basis in C# is when I have to calculate a HashCode for my type which is a composite type. Like:

class Person
{
    string FirstName;
    string LastName;
    int Age;

    public int override GetHashCode()
    {
        return (FirstName == null ? 0 : FirstName.GetHashCode()) ^
            (LastName == null ? 0 : LastName.GetHashCode()) ^
            Age.GetHashCode();
    }
}

这篇关于按位运算的实际应用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆