【问题标题】:Weird XOR swap behavior while zeroing out data清零数据时出现奇怪的 XOR 交换行为
【发布时间】:2011-08-12 17:00:59
【问题描述】:

谢谢道格。这是修复:

void swap(int& a, int& b) {
    if (&a == &b) // added this check to ensure the same address is not passed in
        return;

    a ^= b;
    b ^= a;
    a ^= b;
}


我在 C++ 中实现快速排序以获得乐趣,并且我使用整数作为虚拟数据。我一直在使用 XOR 交换算法来交换两个值,但我注意到我的排序搞砸了。我改变了我的交换算法,它奏效了。我添加了一些调试语句,发现异或交换做了一些奇怪的事情。

我在交换之前和之后打印了数据,这就是它打印的内容:

...

swapping -5, -3
swapped  -3, -5

swapping -5, -5
swapped  0, 0     <---- What?

swapping -2, -4
swapped  -4, -2

...

这是我的代码:

// this might not be that great or even work as intended but it doesn't really matter for this problem
int av3index(int a[], int indx1, int indx2, int indx3) {
    if (a[indx3] <= max(a[indx1], a[indx2]) && a[indx3] >= min(a[indx1], a[indx2]))
        return indx3;

    if (a[indx2] <= max(a[indx1], a[indx3]) && a[indx2] >= min(a[indx1], a[indx3]))
        return indx2;

    if (a[indx1] <= max(a[indx2], a[indx3]) && a[indx1] >= min(a[indx2], a[indx3]))
        return indx1;
}

void swap(int& a, int& b) {
    /*
    This works
    int tmp = b;
    b = a;
    a = tmp;*/

    cout << "swapping " << a << ", " << b << endl;

    a ^= b;
    b ^= a;
    a ^= b;

    cout << "swapped  " << a << ", " << b << endl << endl;
}

void zqsort(int a[], int len) {
    if (len <= 1)
        return;

    int pivot = av3index(a, 0, len / 2, len - 1);

    swap(a[pivot], a[0]);

    int i = 1, j = len - 1;

    while (i <= j) {
        if (a[i] > a[0]) {
            while (i <= j && a[j] > a[0])
                --j;

            if (i <= j)
                swap(a[i], a[j]);
        }

        ++i;
    }

    swap(a[0], a[j]);

    zqsort(a, len / 2);
    zqsort(a + len / 2, len - len / 2);
}

int main() {
    int values[] = {5, 4, 3, 2, 1, 0, -1, -2, -3, -4, -5};

    int len = sizeof(values) / sizeof(int);

    int* arr = new int[len];

    for (int i = 0; i < len; ++i)
        arr[i] = values[i];

    zqsort(arr, len);

    cout << "sorted array:" << endl;
    for (int i = 0; i < len; ++i)
        cout << arr[i] << endl;

    cin.get();
}

我没有对快速排序代码使用任何引用,所以它可能是错误的,但我认为这与问题无关。

【问题讨论】:

  • 使用这个 XOR 实际上可能比使用临时变量的通常两个值交换要慢;您通过引用编写的事实表明您正在强制编译器执行 3 次内存(好的,高速缓存行)写入,而临时样式的 swamp 应该只执行两次内存写入(任何智能编译器都会将 temp 放入寄存器中)。添加条件检查肯定会使其变慢。因此,虽然这可能很有趣,但它可能不是一件实际的事情。
  • 是的,但异或交换并不是为了加快速度,而是为了避免暂时的。在这种情况下,我想说最终的原因是玩得开心。
  • 一个更好的解决方法是 不要使用 xor-swap;很慢.

标签: c++ swap quicksort xor


【解决方案1】:

除了现有的答案,我只是补充一点,如果您要在交换之前进行测试,那么您不妨更改:

if (&a == &b) // added this check to ensure the same address is not passed in
    return;

到:

if (a == b) // check that values are different
    return;

这将处理&amp;a == &amp;ba == b 的情况,这可能会节省一些不必要的交换。

【讨论】:

  • +1,但是为什么你用复数来指代“正确答案”呢? :) 另外,我想知道比较值是否实际上不会变慢(不一定很明显,但在理论上) - 你将不得不取消引用指针,我假设在大多数情况下值是不同的,所以你会去无论如何,交换;-)
  • 如果 OP 使用 xor 交换,他必须测试 a==b 否则他会破坏数据。
【解决方案2】:

您的交换 ab 是同一个位置。 XOR hack 仅在它们位于不同位置时才有效。

我认为在 C 中;这是一张桌子:

           &a != &b  &a == &b
           *a   *b   *a   *b
           -5   -5   -5   -5
*a ^= *b;   0   -5    0    0
*b ^= *a;   0   -5    0    0
*a ^= *b;  -5   -5    0    0

【讨论】:

  • 即使这个答案被否决,它实际上是正确的。这让我意识到,在某些时候交换函数会获得相同的地址。谢谢。
  • 接受答案,汤姆·赛克斯 ;-)
  • 还要再等几分钟:)
【解决方案3】:

任何与自身异或的东西都是零。

【讨论】:

    猜你喜欢
    • 2017-02-11
    • 1970-01-01
    • 1970-01-01
    • 2011-12-08
    • 1970-01-01
    • 2021-10-23
    • 1970-01-01
    • 2013-07-25
    • 2019-07-05
    相关资源
    最近更新 更多