两种不同的交换功能有什么区别?

2023-11-29

我想知道两种代码在性能上的区别。有什么优点和缺点?

Code 1:

temp  = a;
a  = b;
b  = temp;

Code 2:

a = a + b;
b = a - b;
a = a - b;

第一种技术的优点是它是一个通用的习语,明显且正确。它适用于任何地方、任何类型的变量。它很可能被优化编译器识别并被实际的“交换”指令(如果可用)替换。因此,除了更清晰、更正确之外,第一种技术也可能更有效。

第二种技术的优点是它避免了使用临时变量,并且它是一种令人愉快的晦涩技巧,深受那些不断收集晦涩技巧并提出涉及晦涩技巧的误导性“陷阱”面试问题的人的喜爱,并且(据我所知),他们通过用一些晦涩难懂的技巧来使自己的程序变得更难维护、更难移植、更不可靠。

第一种技术的缺点是:None.
(理论上,有人可能会说它使用临时变量是有缺点的,但实际上,这根本没有缺点,因为临时变量是免费的。我认为地球上没有人仍在为处理器编写代码,所以内存和寄存器有限,以这种方式“保存”临时变量实际上是值得担心的。)

第二种技术的缺点是它更难编写,更难让读者理解,并且可能效率较低(也许效率非常低)。它仅“适用于”算术类型,不适用于结构或其他类型。如果它被用来尝试与自身交换数据,它将无法工作(它会悄悄地损坏数据)。 (稍后会详细介绍这种可能性。)如果这些还不够糟糕,那么即使在“普通”情况下,它也可能从根本上存在错误,因为它可能会溢出,并且对于浮点类型,它可能会改变一个或两个值稍微由于舍入误差而导致,并且对于指针类型,如果被交换的指针不指向同一对象内,则它是未定义的。

您具体询问了性能问题,所以让我们多说几句。 (免责声明:我不是微优化方面的专家;我倾向于用相当抽象、随意的术语来思考指令级性能。)

第一种技术使用三个分配。第二种技术使用一次加法和两次减法。在许多机器上,算术运算与简单的赋值所花费的周期数相同,因此在许多情况下,两种技术的性能是相同的。但很难想象第二种技术如何变得更加高效,而很容易想象第一种技术如何变得更加高效。特别是,正如我已经提到的,如果目标处理器有第一种技术,编译器更容易识别并转换为更高效的 SWP 指令。


现在,有些题外话。这里介绍的第二种技术是传统的、令人惊奇的晦涩技巧的一种不太美味的变体,用于在不使用临时变量的情况下交换两个变量。在不使用临时变量的情况下交换两个变量的传统的、令人难以理解的技巧是:

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

曾几何时,在某些圈子里,以一种更加美妙而晦涩的方式呈现这些技术是一种时尚:

a ^= b ^= a ^= b;       /* WRONG */
a += b -= a -= b;       /* WRONG */

但是这些演绎(同时,是的,绝对是精致地如果你喜欢这类东西,那就太晦涩难懂了)还有它们所代表的额外的崩溃缺点未定义的行为,因为他们尝试修改a在同一个表达式中多次出现,且没有插入序列点。 (另请参阅关于该主题的规范问题.)


公平地说,我必须提到,在一种实际情况下,第一种技术使用临时变量可能是一个重大缺点,而第二种技术缺乏临时变量可能因此成为一个实际优势。一种情况是,如果您试图编写一个通用的“交换”宏,类似于

#define Swap(a, b) (a = a + b, b = a - b, a = a - b)

这个想法是,您可以在任何地方、任何类型的变量上使用这个宏,并且(因为它是一个宏,因此很神奇)您甚至不必使用&关于您调用它的参数,就像它是一个函数一样。但在传统的 C 语言中,至少,如果你想写一个Swap像这样的宏,使用技术 1 基本上是不可能做到的,因为没有办法声明必要的临时变量。

你不是在问这个子问题,但既然我提出了它,我不得不说解决方案(尽管它对那些喜欢美味默默无闻的人来说永远是令人沮丧的)就是首先不要尝试编写“通用”宏来交换两个值。你不能在 C 中做到这一点。(事实上,你可以在 C++ 中做到这一点,使用新的定义auto,现在我猜 C 也有一些编写通用宏的新方法。)

当您尝试以这种方式编写“交换”宏时,实际上还有一个额外的崩溃问题,那就是它会not工作 — 如果调用者尝试与自身交换值,它将把一个或两个变量设置为 0,而不是交换值。你可能会说这不是问题,因为也许没有人会写Swap(x, x),但在不太完美的排序例程中,他们可能很容易编写Swap(a[i], a[j])有时在哪里i恰好等于j, or Swap(*p, *q)有时指针p恰好等于q.

另请参阅C 常见问题列表, 问题3.3b, 10.3 and 20.15c.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

两种不同的交换功能有什么区别? 的相关文章

随机推荐

  • Snakemake 无法处理很长的命令行?

    这是一个很奇怪的问题 当我的 input 中指定的rule部分是 input 有超过 500 个文件 snakemake 刚刚退出并显示消息 one of the commands exited with non zero exit cod
  • 如何创建一个 Mailto Share 按钮,该按钮打开一个窗口,可以在其中输入要发送到的电子邮件地址

    我一直在互联网上搜索以了解如何创建mailto共享按钮将打开一个新窗口 用户可以在其中输入他选择发送到的电子邮件地址 我附上了一组连续的图像作为操作示例 这其中有什么技巧呢 为什么我找不到任何有关如何编写此类代码的信息 堆栈溢出上也绝对找不
  • 如何阻止Savon向soap.body添加前缀

    这就是我创建客户端的方式 client Savon Client new do wsdl document my document wsdl endpoint my endpoint end 这就是我得到回复的方式 response cli
  • 将 PHP 数组传递给函数?

    我有以下代码 params array api user gt user api key gt pass to gt email protected subject gt testing from curl html gt testing
  • 如何更改 JAX-RS 应用程序中的 Jackson 版本 (WebSphere Liberty)

    我正在将 JAX RS 应用程序从 WebSphere 8 0 迁移到 WebSphere Liberty 8 5 5 在WebSphere 8 0 中 Jackson 由WebSphere 提供 我可以找到jackson core asl
  • 从 read 调用中得到负一

    我使用 SQL Developer 连接到具有只读访问权限的数据库 这是 TNS 连接 我使用 tnsnames ora 转发端口脚本和 SQL Developer 过去 有时在连接时会收到错误消息 从 read 调用中得到负一 供应商代码
  • 当通过启动器中的图标按下启动时,应用程序完全重新启动

    我正在尝试制作我的第一个 Android 应用程序的发布版本 以发送给一些测试人员 然而 我遇到了一个问题 当您退出应用程序 然后通过其图标启动它重新进入它时 它会重新启动整个应用程序 而不是返回到之前的位置 即使您退出后立即重新进入 也会
  • 如果未使用 CloseHandle 正确关闭,则重新打开串行端口会失败

    我正在 Windows 上使用 USB 设备 该设备被视为虚拟串行端口 我可以使用 CreateFile 和 ReadFile 函数与设备进行通信 但在某些情况下 我的应用程序不会调用 CloseHandle 当我的应用程序在开发中崩溃时
  • 混合模式程序集是针对版本“v1.1.4322”构建的

    我在 c net 4 0 应用程序中包含了一个 directX 播放器 该应用程序包含在此处 答案2 问题是 当我尝试初始化对象 即 Player mPlayer new Player 时 会发生此错误 混合模式程序集是针对运行时版本 v1
  • 画布被跨源数据污染

    我正在从我可以信任的第三方网站加载动态 jpeg 我试图getImageData 但浏览器 Chrome 23 0 抱怨 Unable to get image data from canvas because the canvas has
  • 快速找到以2为底的对数的整数部分

    计算浮点数以 2 为底的对数的整数部分的有效方法是什么 就像是 N ceil log2 f or N floor log2 f 对于浮点数 f 我想这可以以某种方式非常有效地实现 因为人们可能只需要访问浮点指数 EDIT2 我主要不感兴趣精
  • 参与者数量为奇数的每周小组分配算法

    问题有一个循环解决方案我之前问过 它对于偶数的人来说效果很好 但是一旦你实现了算法并尝试了它们 这些建议似乎都不起作用 我已经尝试了很多变化并且 将最后一个与一大堆其他人分组 第二组最后一组 不同的组合 2和4到底行的最后一个 我认为这会给
  • 检索 Matplotlib 热图颜色

    我正在尝试检索 matplotlib 热图上每个单元格的颜色 该热图由imshow 功能 例如由magic function below import matplotlib pyplot as plt import numpy as np
  • 如何使用 javascript d3 打开 json 文件?

    我正在尝试使用 javascript 从 JSON 文件中提取元素 但是收到一条错误消息 指出它无法加载 JSON 文件 这就是我的代码的样子
  • 异步nodejs执行顺序

    processItem什么时候开始执行 是否在某些项目被推入队列后立即开始 或者 for 循环必须在队列中的第一项开始执行之前完成 var processItem function item callback console log ite
  • 将列插入 pandas 数据框

    设想 我有一段代码 可以将 Excel 工作表中的数据读取到数据框中 合并到一个数据框中 并执行一些清理过程 Issue 我试图使用 pd insert 将具有给定值的列添加到数据帧的开头 但每次运行此行时 数据帧都会从变量资源管理器中消失
  • 从 Facebook API 将数据插入 Meteor

    我按照给出的例子here从 FB Graph 中提取数据 到目前为止 我已经设法从 FB 中提取数据 但我不知道如何将其插入到 MongoDB 中 目前 Facebook 的数据呈现如下 data picture https photo j
  • 将 Ajax 与 jQuery DataTables 结合使用时,如何确定如何处理返回的数据?

    像许多其他人一样 我查看类似问题的各种答案 在网上搜索示例等 但除非我碰巧找到我遇到的几乎相同的情况 否则我无法弄清楚如何让 DataTable 填充阿贾克斯呼叫 我认为如果有人能够解释所发生的步骤以及如何使用 DataTables 的 A
  • 按字典顺序查找排列列表中给定排列的索引[重复]

    这个问题在这里已经有答案了 可能的重复 给定一个字符串和该字符串的排列 在字符串排列的排序列表中查找该排列字符串的索引 这是一道面试题 假设有一个按字典顺序排列的排列列表 例如 123 132 213 231 312 321 给定一个排列
  • 两种不同的交换功能有什么区别?

    我想知道两种代码在性能上的区别 有什么优点和缺点 Code 1 temp a a b b temp Code 2 a a b b a b a a b 第一种技术的优点是它是一个通用的习语 明显且正确 它适用于任何地方 任何类型的变量 它很可