【问题标题】:Pointer issue when applying the XOR swap algorithm应用 XOR 交换算法时的指针问题
【发布时间】:2017-07-11 14:26:38
【问题描述】:

我有一个浮点数组,我想在其中进行一些交换。所以,我在网上看了一圈,发现最有效的方法是通过异或交换XOR swap algorithm

所以我有这个代码sn-p:

  float tmp;
  tmp   = x[i];
  x[i]  = x[j];
  x[j]  = tmp;

我已经尝试将其更改为 XOR 交换方式:

  /*Made sure that address x[i] is different than the one of x[j] */
  float* a= &x[i];
  float* b= &x[j];
  a ^= b;
  b ^= a;
  a ^= b;

但我明白了:error: invalid operands to binary ^ (have ‘float *’ and ‘float *’)

老实说,我不是这样的指针专家,有时它会让我感到困惑,所以,谁能告诉我我做错了什么。

【问题讨论】:

  • 错误信息中有什么不清楚的地方?位运算仅针对整数类型定义。
  • @A.nechi 首先,使用 XOR 运算符进行交换以及尝试将其用于浮点数通常是一个坏主意。:)
  • @VladfromMoscow On pointers to float numbers - 更糟糕的主意...
  • 为什么你认为它是高效的?通常,使用临时变量进行常规交换会更快。
  • 从您发布的链接中,大多数现代编译器可以优化掉本机交换中的临时变量,在这种情况下 *本机交换使用相同数量的内存和相同的寄存器数量与 XOR 交换相同,并且至少与 XOR 交换一样快,而且通常更快*。对于不熟悉该技术的人来说,XOR 交换的可读性也差得多,而且完全不透明。 简而言之,只需使用本机交换,即使用临时变量旋转值。

标签: c arrays algorithm


【解决方案1】:

编辑

简短的回答:您不能对指针执行按位运算。不幸的是,你cannot perform bitwise operations on floats, either!不要对 float 值使用 XOR 交换。

原创

评论者给了你简短的回答。现在我来回答一下长篇大论——

^ 等按位运算是为整数定义的。但是,指针不一定是整数。在实模式 x86 上,指针包含两个整数,或者在某种程度上与两个整数相关:一个段和一个偏移量 (additional info)。 更糟糕的是,这两个整数重叠,因此更改一个整数也会更改另一个整数。因此,没有单一的、明确的方式来定义^ 或其他指针的按位运算。

许多代码确实假设指针可以被视为整数,因为分段寻址不像以前那么常见。但是,C 标准仍然必须支持不太常见的架构,因此没有定义指针的按位操作。

其余编辑

我看到您链接的示例使用了指针。这是因为,在 C 中,您必须使用指针通过参数将值传回函数的调用者。 code you linked 是:

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

(enwiki,CC-BY-SA 3.0)。您可以在您的上下文中将其称为

if(x[i]!=x[j]) xorSwap(&x[i], &x[j]);

如果xints 的数组,它会交换数组元素的内容,正如我想你所期望的那样。当您直接使用 XOR 交换而不是通过函数时,您根本不需要使用指针。例如:

if(x[i]!=x[j]) {
    x[i] ^= x[j];
    x[j] ^= x[i];
    x[i] ^= x[j];
}

如果xint 而不是float,则应该再次工作。

【讨论】:

  • 浮点数数字。看来 OP 又犯了一个错字。
  • @Olaf cxw 谈论的是指针,而不是浮点数。该操作正在对指针使用 BW 操作。
  • @EugeneSh。再次阅读我的评论。代码不是文本所述,问题不清楚缺少正确的 mcve。
  • 1) 没有“_XOR 技巧”。 2)根本不要使用那种方式。将优化留给编译器。 3) 不保证更快,也可能更慢。
【解决方案2】:

如果您使用指针执行a ^= b,您希望交换地址而不是实际值。相反,您应该使用这些值。下一个问题是你想对浮点数进行异或,这是不可能的。相反,您可以获取浮点数的单个字节并对它们进行异或:

void swap( float * one, float * two){
    unsigned char* a= (unsigned char *)one;
    unsigned char* b= (unsigned char *)two;

    for(int i = 0; i < sizeof(float); i++){
        *a ^= *b;
        *b ^= *a;
        *a ^= *b;
        a++;
        b++;
    }
}

int main(void) {
    float one = 1.0, two = 2.0;

    swap(&one, &two);
    printf("%f    %f", one, two); // prints 2.0000    1.0000
    return 0;
}

这是很多额外的工作,不值得付出努力,而且肯定会更慢。您可以对整数使用 XOR 交换,对浮点数使用临时变量进行常规交换。

【讨论】:

  • 为什么建议用异或交换换成整数?这显然是一个劣质的解决方案。
  • @geza 我不想推荐它,也许我选择的词有点误导。我想说的是,如果你愿意,你可以将它与整数一起使用。
【解决方案3】:

这是正常的。

  float* a= x[i];

无效。你的浮点数组是 x。 您正在尝试从数组中获取值。 所以应该是:

float a = x[i];
float b = x[j];

如果你放一个'*',你就创建了一个指针。 无论如何,正如Wikipedia 所示,它不应该工作。仅适用于整数。

【讨论】:

  • 哦,对不起,我添加了其余的答案
  • 我已经在帖子中修复了,请再看一遍!!
  • 不过,建议的交换方法不适用于浮点数
猜你喜欢
  • 2014-06-04
  • 1970-01-01
  • 2012-06-13
  • 2016-06-02
  • 1970-01-01
  • 1970-01-01
  • 2011-10-12
  • 1970-01-01
相关资源
最近更新 更多