Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Performance 有没有必要在不使用第三个变量的情况下交换两个变量?_Performance_Algorithm_Assembly_Language Agnostic_Swap - Fatal编程技术网

Performance 有没有必要在不使用第三个变量的情况下交换两个变量?

Performance 有没有必要在不使用第三个变量的情况下交换两个变量?,performance,algorithm,assembly,language-agnostic,swap,Performance,Algorithm,Assembly,Language Agnostic,Swap,我知道不要使用它们,但是有一些技术可以在不使用第三个变量的情况下交换两个变量,例如 x ^= y; y ^= x; x ^= y; 及 在课堂上,教授提到,20年前,当内存非常有限时,这些应用程序非常流行,今天仍在高性能应用程序中使用。这是真的吗?我对为什么使用这些技术毫无意义的理解是: 使用第三个变量永远不会成为瓶颈 优化器无论如何都会这样做 那么,有没有一个不与第三个变量交换的好时机?它更快了吗 相比较而言,使用XOR的方法与使用+/-的方法相比是否更快?大多数体系结构都有一个加法/减法和

我知道不要使用它们,但是有一些技术可以在不使用第三个变量的情况下交换两个变量,例如

x ^= y;
y ^= x;
x ^= y;

在课堂上,教授提到,20年前,当内存非常有限时,这些应用程序非常流行,今天仍在高性能应用程序中使用。这是真的吗?我对为什么使用这些技术毫无意义的理解是:

  • 使用第三个变量永远不会成为瓶颈
  • 优化器无论如何都会这样做
  • 那么,有没有一个不与第三个变量交换的好时机?它更快了吗


    相比较而言,使用XOR的方法与使用+/-的方法相比是否更快?大多数体系结构都有一个加法/减法和XOR的单元,所以这不意味着它们的速度都相同吗?或者仅仅因为CPU有一个操作单元并不意味着它们的速度都相同?

    这一点都没有意义。这是一种展示聪明的尝试。考虑到它在很多情况下(浮点、指针、结构)都不起作用,不可访问,并且使用三个依赖操作,这比仅仅交换值要慢得多,因此它完全没有意义,并且证明了它实际上并不聪明


    您是对的,如果速度更快,那么优化编译器将在交换两个数字时检测模式,并替换它。这很容易做到。但编译器确实会注意到,当您交换两个变量时,可能根本不会生成任何代码,但之后会开始使用不同的变量。例如,如果您交换x和y,则写入a+=x;b+=y;编译器可能只是将其更改为a+=y;b+=x。另一方面,xor或加法/减法模式将无法识别,因为它非常罕见,不会得到改进

    对于编写普通洗衣机固件的程序员来说,了解这些技术仍然很重要。很多这样的硬件仍然运行在Z80或类似的CPU上,通常内存不超过4K左右。在这个场景之外,知道这些算法的“诡计”,正如你所说,几乎没有实际用途


    (尽管如此,我还是想说,记住并了解这类东西的程序员,即使是对于“常规”应用程序,也往往比那些不会费事的“同行”更好。正是因为后者往往采取“内存足够大”的态度太过分了。)

    如果您想交换内存中的两个整字或两个整寄存器,这些技巧不太可能有用。但是,如果没有可用寄存器(或者只有一个用于内存到内存交换的可用寄存器),并且没有可用的“交换”指令(如在x86中交换两个SSE寄存器时),或者“交换”指令过于昂贵(如x86中的寄存器内存
    xchg
    )不可能避免交换或降低寄存器压力

    但如果您的变量是单个字中的两个位字段,则修改3-XOR方法可能是一个好主意:

    y = (x ^ (x >> d)) & mask
    x = x ^ y ^ (y << d)
    
    y=(x^(x>>d))&掩码
    
    当然,知道这一点仍然很有用。还有什么办法呢

    c = a
    a = b
    b = c
    
    三次行动使用三种资源,而不是三次行动使用两种资源

    确保指令集可能有一个交换,但只有在1)编写程序集或2)优化器将其作为交换,然后对该指令进行编码时,才起作用。或者,您可以进行内联汇编,但这是不可移植的,而且维护起来很困难。如果您调用了asm函数,那么编译器必须为调用进行设置,并消耗大量的资源和指令。尽管可以这样做,但除非该语言具有交换操作,否则实际上不太可能利用指令集功能

    一般程序员现在不需要知道这一点,就像以前一样,人们会抨击这种过早的优化,除非你知道诀窍并经常使用它,如果代码没有文档化,那么它就不明显了,因此它是糟糕的编程,因为它是不可读和不可维护的


    例如,让一个人发明一个测试来证明它实际上交换了所有位模式的组合,这仍然是一种价值编程教育和实践。就像在x86上执行xor reg,reg以将寄存器归零一样,对于高度优化的代码,它有一个小但真实的性能提升。

    是的,有,特别是在汇编代码中

    处理器只有有限数量的寄存器。当寄存器非常满时,这个技巧可以避免将寄存器溢出到另一个内存位置(可能在未蚀刻的缓存线中)

    实际上,我使用了3路xor来交换一个寄存器,该寄存器位于x86的高性能手动编码锁例程的关键路径中,在该路径中,寄存器压力很高,并且没有(锁安全!)的位置来放置临时值。(在X86上,了解XCHG内存指令的相关成本很高是很有用的,因为它包含自己的锁,我不想看到它的效果。考虑到X86有锁前缀操作码,这确实是不必要的,但历史错误正是如此)


    士气:每一种解决方案,无论孤立地站着看起来有多难看,都可能有一些用处。认识他们很好;如果不合适,您始终不能使用它们。在它们有用的地方,它们是非常有效的。

    这种结构在PIC系列微控制器的许多成员上是有用的,这些微控制器要求几乎所有的操作都通过一个累加器(“工作寄存器”)[请注意,虽然这有时可能是一个障碍,但每个指令只需要编码一个寄存器地址和一个目标位,而不是两个寄存器地址,这使得PIC的工作集可能比其他微控制器大得多]c = a a = b b = c
    xorwf other,w  ; w=(w ^ other)
    xorwf other,f  ; other=(w ^ other)
    xorwf other,w  ; w=(w ^ other)
    
    movwf temp1     ; temp1 = w
    movf  other,w   ; w = other
    movwf temp2     ; temp2 = w
    movf  temp1,w   ; w = temp1 [old w]
    movwf other     ; other = w
    movf  temp2,w   ; w = temp2 [old other]
    
    subwf other,w    ; w = other-w
    btfss STATUS,C   ; Skip next instruction if carry set (other >= W)
     subwf other,f   ; other = other-w [i.e. other-(other-oldW), i.e. old W]