C ++ XOR交换浮点值

时间:2017-02-06 13:52:21

标签: c++ floating-point swap xor

是否可以在C ++中使用具有浮点值的XOR交换算法?

然而维基百科说:

  

XOR按位运算以交换具有相同数据类型的不同变量的值

但我有点困惑。使用此代码:

void xorSwap (int* x, int* y) {
   *x ^= *y;
   *y ^= *x;
   *x ^= *y;
}

int main() {

   float a = 255.33333f;
   float b = 0.123023f;
   xorSwap(reinterpret_cast<int*>(&a), reinterpret_cast<int*>(&b));
   std::cout << a << ", " << b << "\n";

   return 0;
}

它似乎有效(至少在gcc下),但我担心如果需要这样的做法?

4 个答案:

答案 0 :(得分:6)

从技术上讲,你要求的可能性,但正如IInspectable明确评论的那样,它会导致UB(未定义行为)。
无论如何,我建议您使用std::swap代替,它是一个专门用于特定数据类型的模板,旨在做好工作。

答案 1 :(得分:1)

如果intfloat的大小相同,那么它将在任何合理的架构上实际运行。 float中的内存是一组位,您可以解释这些位并使用xor操作完全交换它们。然后,您可以再次将这些位用作正确的float。您引用的引用仅表示您交换的两个值必须属于同一类型,并且都是int s。

但是,在某些体系结构中,这可能导致不同类型的寄存器之间的移动,或者明确地将寄存器刷新到内存。您现在将在几乎任何理智的架构上看到的,使用理智的优化编译器,使用std::swap或带有临时变量的表达式的显式交换实际上更快。

即。你应该写:

float a = 255.33333f;
float b = 0.123023f;
float tmp = a;
a = b;
b = tmp;

或者最好:

float a = 255.33333f;
float b = 0.123023f;
std::swap(a,b);

如果您的架构的标准库作者已确定xor交换确实有益,那么您应该希望最后一个表单将使用它。 xor交换是一种典型的不良习惯,就隐藏在不必要的神秘实现中的意图而言。在严重缺乏优势的情况下,它只能在严重注册缺陷的情况下有效。

答案 2 :(得分:1)

那里的代码会调用未定义的行为。将float*强制转换为int*并将其用作此类,在C或C ++中是不合法的。 reinterpret_cast应该用于在具有兼容布局的不相关结构之间进行转换,或者在类型指针和void*之间进行临时转换。

哦,在这种特殊情况下,UB不仅仅是学术上的关注点。编译器可能会注意到xorSwap()没有触及任何float,执行该语言的别名规则允许的优化,并打印出a的原始值和b而不是交换的值。而这甚至没有进入intfloat具有不同大小或路线的架构。

如果您想安全地执行此操作,则必须从浮点数memcpy()进入无符号字符数组,在循环中执行XOR,然后再返回memcpy()。这当然会使操作比正常交换慢。当然,基于xor的交换比正常交换更慢。

答案 3 :(得分:1)

是:

a)编译器允许的时候可能。

b)标准未定义行为(即未定义行为)的操作

c)关于gcc,实际上效率低于准确说明你想要的东西:

下式给出:

void xorSwap (unsigned int* x, unsigned int* y) {
   *x ^= *y;
   *y ^= *x;
   *x ^= *y;
}

void swapit3(float& a, float&b)
{
  xorSwap(reinterpret_cast<unsigned int*>(&a), reinterpret_cast<unsigned int*>(&b));
}

结果如下:

swapit3(float&, float&):                         # @swapit3(float&, float&)
        mov     eax, dword ptr [rdi]
        xor     eax, dword ptr [rsi]
        mov     dword ptr [rdi], eax
        xor     eax, dword ptr [rsi]
        mov     dword ptr [rsi], eax
        xor     dword ptr [rdi], eax
        ret

而这:

void swapit2(float& a, float&b)
{
  std::swap(a,b);
}

结果如下:

swapit2(float&, float&):                         # @swapit2(float&, float&)
        mov     eax, dword ptr [rdi]
        mov     ecx, dword ptr [rsi]
        mov     dword ptr [rdi], ecx
        mov     dword ptr [rsi], eax
        ret

link:https://godbolt.org/g/K4cazx