x/2 和 x>>1 或 x*2 和 x << 1 之间的差异,其中 x 是整数

2024-01-23

正如我们所知,计算整数 x/2 我们只需编写y=x/2;对于 x*2 也类似;但优秀的程序员会使用位操作来计算这个值。

他们只是做y = x >> 1;

这两种方法有什么区别吗? 我所说的差异是指所需时间/空间/内存的差异,或者两者完全相同(即 x/2 由 x >> 1 实现)?

与其他数字而不是 2 的乘法/除法也以相同的方式实现(即5*5 = 10*2 + 5*1 = 10 << 1 + 5 = 25)?


这个问题已经在荒谬的鱼博客上得到了回答:http://ridiculousfish.com/blog/posts/will-it-optimize.html http://ridiculousfish.com/blog/posts/will-it-optimize.html

  1. 除以 2 右移

GCC 会将整数除以 2 转换为右移吗?

int halve_it(int x) {
   return x / 2;
}

int halve_it(int x) {
   return x >> 1;
}

右移运算符相当于四舍五入的除法 负无穷大,但普通除法向零舍入。就这样 对于奇数负数,建议的优化将会产生错误的结果 数字。

通过将最高有效位添加到结果中可以“修复”结果 分子在移位之前,gcc 就是这样做的。

优秀的程序员会让编译器优化他们的代码,除非它们会造成性能损失。

EDIT :既然你要求官方来源,我们就引用C99的标准原理文档。你可以在这里找到它:http://www.open-std.org/jtc1/sc22/wg14/www/docs/C99RationaleV5.10.pdf http://www.open-std.org/jtc1/sc22/wg14/www/docs/C99RationaleV5.10.pdf

在 C89 中,涉及负操作数的整数除法可以以实现定义的方式向上或向下舍入;目的是避免在运行时代码中产生开销来检查特殊情况并强制执行特定行为。然而,在 Fortran 中,结果总是会截断为零,并且开销对于数字编程社区来说似乎是可以接受的。因此,C99 现在需要类似的行为,这应该有助于将代码从 Fortran 移植到 C。本文档第 7.20.6.2 节中的表说明了所需的语义。

您的优化在 C89 中是正确的,因为它让编译器按照自己的意愿行事。然而,C99 引入了新的约定来遵守 Fortran 代码。以下是除法运算符的预期示例(始终来自同一文档):

不幸的是,您的优化不符合 C99 标准,因为它没有给出 x = -1 的正确结果:

#include <stdio.h>

int div8(int x)
{
    return x/3;
}

int rs8( int x )
{
    return x >> 3;
}

int main(int argc, char *argv[])
{
    volatile int x = -1;
    printf("div : %d \n", div8(x) );
    printf("rs : %d \n", rs8(x) );

    return 0;
}

Result:
div : 0 
rs : -1 
[Finished in 0.2s]

如果查看编译后的代码,您可以发现一个有趣的差异(使用 g++ v4.6.2 编译):

0040138c <__Z4div8i>:
  40138c:   55                      push   %ebp
  40138d:   89 e5                   mov    %esp,%ebp
  40138f:   8b 45 08                mov    0x8(%ebp),%eax
  401392:   85 c0                   test   %eax,%eax
  401394:   79 03                   jns    401399 <__Z4div8i+0xd>
  401396:   83 c0 0f                add    $0x7,%eax
  401399:   c1 f8 04                sar    $0x3,%eax
  40139c:   5d                      pop    %ebp
  40139d:   c3                      ret    

0040139e <__Z3rs8i>:
  40139e:   55                      push   %ebp
  40139f:   89 e5                   mov    %esp,%ebp
  4013a1:   8b 45 08                mov    0x8(%ebp),%eax
  4013a4:   c1 f8 03                sar    $0x3,%eax
  4013a7:   5d                      pop    %ebp
  4013a8:   c3                      ret  

line 401392,有一个test指令,它将检查奇偶校验位,如果数字为负,则添加1 << (n-1) = 7右移 3 个单位之前的 x。

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

x/2 和 x>>1 或 x*2 和 x << 1 之间的差异,其中 x 是整数 的相关文章

随机推荐

  • 在 Python 中调试期间绘制函数

    我曾经在 Matlab 中工作 在调试过程中使用可视化中间结果非常方便 当使用大数组 矩阵和嵌套函数时 plot功能 在Python中 我无法在调试模式下绘制任何内容 带有图形图的窗口永远不会加载 我正在使用Spyder IDE进行编码和m
  • 在 Google 地图的不同图层上显示标记集

    我需要在 Google 地图上显示一组标记 我知道可以直接在 Google 地图上添加标记 但鉴于我有 3 组标记 一组用于商店 一组用于公园 另一组用于酒店 我如何在 3 个不同的图层上显示它们 以便稍后使用 javascript 我可以
  • GRPC 异步响应流 C#

    如何从处理程序外部生成 RPC 的流响应值 具体来说 来自 IObservable 我目前正在执行以下操作 但这会产生跨线程问题 因为AnRxObservable在 RPC 处理程序之间共享 public override Task Get
  • 计算列中唯一值的每个实例

    假设你有一个 SQL 表格 Prices 13 99 14 00 52 00 52 00 52 00 13 99 您如何计算输入不同字段的次数 因此 此类计数的示例将输出 13 99 2 times 14 00 1 times 52 00
  • 在后台运行 Webrick 服务器?

    MBPro shovell myname ruby script server gt Booting WEBrick gt Rails 2 3 8 application starting on http 0 0 0 0 3000 gt C
  • tidytext::unnest_tokens 是否适用于西班牙语字符?

    我正在尝试将 unnest tokens 与西班牙语文本一起使用 它适用于一元语法 但会破坏二元语法中的特殊字符 该代码在 Linux 上运行良好 我添加了一些有关区域设置的信息 library tidytext library dplyr
  • Mono - 通过 SSL 的 HttpWebRequest - 写入标头时出错

    下面抛出一个 System Net WebException Error SendFailure Errorwriting headers over SSL 但工作正常http www google com http www google
  • 加速Python中的双循环

    有没有一种方法可以加快双循环的速度 从而更新上一次迭代的值 In code def calc N m x 1 0 y 2 0 container np zeros N 2 for i in range N for j in range m
  • 当我的应用程序在 Ionic 中关闭时,如何发送通知?

    我正在使用 Ionic 进行移动开发 我实际上正在使用本地通知 https ionicframework com docs native local notifications 每 5 分钟我会检查我的服务器是否有新问题 this chec
  • 类型错误:图像数据的形状无效(3072)

    这是我的事情 我不想在 Colab 上运行 而是想读取本地 CIFAR10 数据集并使用以下代码玩 CNNcolab https colab research google com github tensorflow docs blob m
  • 为什么 devise 不通过 gmail smtp 发送电子邮件?

    我正在使用设备进行身份验证 它提供了一个忘记密码的链接 当我发送电子邮件时 电子邮件未发送 以下是我使用过的设置 你能告诉我为什么 gmail 不发送电子邮件吗 我还打开了 允许不太安全的应用程序发送电子邮件 并且还在 gmail 设置中启
  • SQL Server 时区

    使用 AT TIME ZONE 有一种方法可以获取我的 UTC 时间 而无需在查询中使用 LEFT 结尾的 00 00 AT 我正在这样做 SELECT GETDATE AT TIME ZONE EASTERN standard time
  • SKProductsRequest 返回空结果

    我查看了其他一些答案 它们似乎对我的情况没有帮助 我有一个新应用程序即将首次发布 我正在处理 应用程序内购买 部分 我在之前的应用程序中使用过 IAP 所以我认为转移应该是直接的 然而 问题是 每当我运行 SKProductsRequest
  • 在 C++ 中格式化输出

    在 C 代码中 我有一个双变量矩阵 我将其打印出来 然而 由于它们的位数不同 输出格式被破坏 一种解决方案是做cout precision 5 但我希望不同的列有不同的精度 此外 由于在某些情况下存在负值 因此 标志也会引起问题 如何解决这
  • 为什么尝试写入大文件会导致 js 堆内存不足

    这段代码 const file require fs createWriteStream test dat for var i 0 i lt 1e7 i file write a 运行大约 30 秒后出现此错误消息 lt Last few
  • 无法使用 Windows 10 安装 Firebase Tools cli

    您好 我无法在 Windows 中通过命令行安装 firebase 工具 我使用下面的命令 npm install g firebase tools 输入此命令后 我收到以下错误 npm 错误 路径 C Users data AppData
  • 使用 OpenSSL API 读取公钥的密码回调

    当使用公钥加密技术时 通常习惯以加密格式存储私钥 因为它们当然应该是秘密的 这反映在 OpenSSL C API 中 它提供了诸如PEM write PrivateKey 它采用一个可选密码作为函数参数 用于加密密钥 如 AES 然后 当从
  • 通过 Amazon SNS 和 Unity 的 iOS APNS - 无法创建开发 iOS 证书

    我正在尝试通过 Unity 中的 Amazon SNS 设置推送通知 我的 Android 方面工作得很好 但 iOS 方面却遇到了问题 我能够让设备注册到苹果生产SNS 应用程序并订阅主题 但一旦我尝试发送通知 端点 已启用 状态就会变为
  • Javascript:“取消”动态脚本标签?

    我使用动态脚本标签从外部域请求 javascript 有时请求花费的时间太长 如果请求时间太长 是否可以停止请求或超时 我不想使用 xmlhttprequest 因为我想避免使用服务器端代理 Thanks 话虽如此 动态添加脚本有多种方法
  • x/2 和 x>>1 或 x*2 和 x << 1 之间的差异,其中 x 是整数

    正如我们所知 计算整数 x 2 我们只需编写y x 2 对于 x 2 也类似 但优秀的程序员会使用位操作来计算这个值 他们只是做y x gt gt 1 这两种方法有什么区别吗 我所说的差异是指所需时间 空间 内存的差异 或者两者完全相同 即