是否可以在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下),但我担心如果需要这样的做法?
答案 0 :(得分:6)
从技术上讲,你要求的可能性,但正如IInspectable明确评论的那样,它会导致UB(未定义行为)。
无论如何,我建议您使用std::swap代替,它是一个专门用于特定数据类型的模板,旨在做好工作。
答案 1 :(得分:1)
如果int
与float
的大小相同,那么它将在任何合理的架构上实际运行。 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
而不是交换的值。而这甚至没有进入int
和float
具有不同大小或路线的架构。
如果您想安全地执行此操作,则必须从浮点数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