为什么带有两个常量的三元运算符比带有变量的三元运算符更快?

2023-11-24

在Java中,我有两个不同的语句,通过使用三元运算符来实现相同的结果,如下所示:

  1. num < 0 ? 0 : num;
  2. num * (num < 0 ? 0 : 1);

看来第二条语句不必要地复杂,并且比第一条语句花费的时间更长,但是当我使用以下代码记录每个语句所花费的时间时,结果如下:

final long startTime = System.currentTimeMillis();

Random rand = new Random();
float[] results = new float[100000000];
for (int i = 0; i < 100000000; i++) {
    float num = (rand.nextFloat() * 2) - 1;
    results[i] = num < 0 ? 0 : num;
    //results[i] = num * (num < 0 ? 0 : 1);
}

final long endTime = System.currentTimeMillis();

System.out.println("Total Time: " + (endTime - startTime));
  1. 1.232秒
  2. 1.023秒 (每个平均值超过 5 次运行)

为什么使用第二个语句时会有如此显着的加速?它似乎包含了不必要的乘法并且具有相同的比较。第一个创建分支而第二个没有创建分支吗?


首先,让我们重写基准测试JMH避免常见的基准测试陷阱.

public class FloatCompare {

    @Benchmark
    public float cmp() {
        float num = ThreadLocalRandom.current().nextFloat() * 2 - 1;
        return num < 0 ? 0 : num;
    }

    @Benchmark
    public float mul() {
        float num = ThreadLocalRandom.current().nextFloat() * 2 - 1;
        return num * (num < 0 ? 0 : 1);
    }
}

JMH 还表明乘法代码更快:

Benchmark         Mode  Cnt   Score   Error  Units
FloatCompare.cmp  avgt    5  12,940 ± 0,166  ns/op
FloatCompare.mul  avgt    5   6,182 ± 0,101  ns/op

现在是时候参与了性能分析器(内置于 JMH 中)查看 JIT 编译器生成的程序集。以下是输出中最重要的部分(评论是我的):

cmp method:

  5,65%  │││  0x0000000002e717d0: vxorps  xmm1,xmm1,xmm1  ; xmm1 := 0
  0,28%  │││  0x0000000002e717d4: vucomiss xmm1,xmm0      ; compare num < 0 ?
  4,25%  │╰│  0x0000000002e717d8: jbe     2e71720h        ; jump if num >= 0
  9,77%  │ ╰  0x0000000002e717de: jmp     2e71711h        ; jump if num < 0

mul method:

  1,59%  ││  0x000000000321f90c: vxorps  xmm1,xmm1,xmm1    ; xmm1 := 0
  3,80%  ││  0x000000000321f910: mov     r11d,1h           ; r11d := 1
         ││  0x000000000321f916: xor     r8d,r8d           ; r8d := 0
         ││  0x000000000321f919: vucomiss xmm1,xmm0        ; compare num < 0 ?
  2,23%  ││  0x000000000321f91d: cmovnbe r11d,r8d          ; r11d := r8d if num < 0
  5,06%  ││  0x000000000321f921: vcvtsi2ss xmm1,xmm1,r11d  ; xmm1 := (float) r11d
  7,04%  ││  0x000000000321f926: vmulss  xmm0,xmm1,xmm0    ; multiply

关键的区别是没有跳转指令mul方法。相反,条件移动指令cmovnbe用来。

cmov与整数寄存器一起使用。自从(num < 0 ? 0 : 1)表达式在右侧使用整数常量,JIT 足够智能,可以发出条件移动而不是条件跳转。

在这个基准测试中,条件跳转的效率非常低,因为分支预测由于数字的随机性,经常会失败。这就是为什么无分支代码mul方法出现得更快。

如果我们以一个分支优于另一个分支的方式修改基准,例如通过替换

ThreadLocalRandom.current().nextFloat() * 2 - 1

with

ThreadLocalRandom.current().nextFloat() * 2 - 0.1f

那么分支预测会更好地工作,并且cmp方法将变得一样快mul:

Benchmark         Mode  Cnt  Score   Error  Units
FloatCompare.cmp  avgt    5  5,793 ± 0,045  ns/op
FloatCompare.mul  avgt    5  5,764 ± 0,048  ns/op
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么带有两个常量的三元运算符比带有变量的三元运算符更快? 的相关文章

  • 如何使用 Java 和 Selenium WebDriver 在 C 目录中创建文件夹并需要将屏幕截图保存在该目录中?

    目前正在与硒网络驱动程序和代码Java 我有一种情况 我需要在 C 目录中创建一个文件夹 并在该文件夹中创建我通过 selenium Web 驱动程序代码拍摄的屏幕截图 它需要存储在带有时间戳的文件夹中 如果我每天按计划运行脚本 所有屏幕截
  • 如何在 Play java 中创建数据库线程池并使用该池进行数据库查询

    我目前正在使用 play java 并使用默认线程池进行数据库查询 但了解使用数据库线程池进行数据库查询可以使我的系统更加高效 目前我的代码是 import play libs Akka import scala concurrent Ex
  • 在画布上绘图

    我正在编写一个 Android 应用程序 它可以在视图的 onDraw 事件上直接绘制到画布上 我正在绘制一些涉及单独绘制每个像素的东西 为此我使用类似的东西 for int x 0 x lt xMax x for int y 0 y lt
  • 如何找到给定字符串的最长重复子串

    我是java新手 我被分配寻找字符串的最长子字符串 我在网上研究 似乎解决这个问题的好方法是实现后缀树 请告诉我如何做到这一点或者您是否有任何其他解决方案 请记住 这应该是在 Java 知识水平较低的情况下完成的 提前致谢 附 测试仪字符串
  • Final字段的线程安全

    假设我有一个 JavaBeanUser这是从另一个线程更新的 如下所示 public class A private final User user public A User user this user user public void
  • Android:捕获的图像未显示在图库中(媒体扫描仪意图不起作用)

    我遇到以下问题 我正在开发一个应用程序 用户可以在其中拍照 附加到帖子中 并将图片保存到外部存储中 我希望这张照片也显示在图片库中 并且我正在使用媒体扫描仪意图 但它似乎不起作用 我在编写代码时遵循官方的Android开发人员指南 所以我不
  • 如何加速Python中的N维区间树?

    考虑以下问题 给定一组n间隔和一组m浮点数 对于每个浮点数 确定包含该浮点数的区间子集 这个问题已经通过构建一个解决区间树 https en wikipedia org wiki Interval tree 或称为范围树或线段树 已经针对一
  • 磁模拟

    假设我在 n m 像素的 2D 表面上有 p 个节点 我希望这些节点相互吸引 使得它们相距越远吸引力就越强 但是 如果两个节点之间的距离 比如 d A B 小于某个阈值 比如 k 那么它们就会开始排斥 谁能让我开始编写一些关于如何随时间更新
  • Mockito when().thenReturn 不必要地调用该方法

    我正在研究继承的代码 我编写了一个应该捕获 NullPointerException 的测试 因为它试图从 null 对象调用方法 Test expected NullPointerException class public void c
  • 十进制到八进制的转换[重复]

    这个问题在这里已经有答案了 可能的重复 十进制转换错误 https stackoverflow com questions 13142977 decimal conversion error 我正在为一个类编写一个程序 并且在计算如何将八进
  • Java按日期升序对列表对象进行排序[重复]

    这个问题在这里已经有答案了 我想按一个参数对对象列表进行排序 其日期格式为 YYYY MM DD HH mm 按升序排列 我找不到正确的解决方案 在 python 中使用 lambda 很容易对其进行排序 但在 Java 中我遇到了问题 f
  • Java执行器服务线程池[关闭]

    很难说出这里问的是什么 这个问题是含糊的 模糊的 不完整的 过于宽泛的或修辞性的 无法以目前的形式得到合理的回答 如需帮助澄清此问题以便重新打开 访问帮助中心 help reopen questions 如果我使用 Executor 框架在
  • 如何从泛型类调用静态方法?

    我有一个包含静态创建方法的类 public class TestClass public static
  • 玩!框架:运行“h2-browser”可以运行,但网页不可用

    当我运行命令时activator h2 browser它会使用以下 url 打开浏览器 192 168 1 17 8082 但我得到 使用 Chrome 此网页无法使用 奇怪的是它以前确实有效 从那时起我唯一改变的是JAVA OPTS以启用
  • 获取 JVM 上所有引导类的列表?

    有一种方法叫做findBootstrapClass对于一个类加载器 如果它是引导的 则返回一个类 有没有办法找到类已经加载了 您可以尝试首先通过例如获取引导类加载器呼叫 ClassLoader bootstrapLoader ClassLo
  • 静态变量的线程安全

    class ABC implements Runnable private static int a private static int b public void run 我有一个如上所述的 Java 类 我有这个类的多个线程 在里面r
  • 编译器抱怨“缺少返回语句”,即使不可能达到缺少返回语句的条件

    在下面的方法中 编译器抱怨缺少退货声明即使该方法只有一条路径 并且它包含一个return陈述 抑制错误需要另一个return陈述 public int foo if true return 5 鉴于Java编译器可以识别无限循环 https
  • JGit 检查分支是否已签出

    我正在使用 JGit 开发一个项目 我设法删除了一个分支 但我还想检查该分支是否已签出 我发现了一个变量CheckoutCommand但它是私有的 private boolean isCheckoutIndex return startCo
  • 如何修复 JNLP 应用程序中的“缺少代码库、权限和应用程序名称清单属性”?

    随着最近的 Java 更新 许多人都遇到了缺少 Java Web Start 应用程序的问题Codebase Permissions and Application name体现属性 尽管有资源可以帮助您完成此任务 但我找不到任何资源综合的
  • 节拍匹配算法

    我最近开始尝试创建一个移动应用程序 iOS Android 它将自动击败比赛 http en wikipedia org wiki Beatmatching http en wikipedia org wiki Beatmatching 两

随机推荐

  • 为什么 printf 可以与托管字符串一起使用?

    我们目前正在挖掘一些非常古老的 C CLI 代码 旧语法 NET Beta 并且对看到这样的内容感到有点惊讶 System String source Test String printf s source 程序正确输出 Test Stri
  • 如何将无序列表设计得像表格一样?

    我只有一个 ul 在其下我们有一组 li ul li 1 li li li li 2 li li li li 3 li li 4 li li li ul 现在我想将它们显示为表格 请帮助我使用 CSS 我们如何以下表格式显示上述 UL LI
  • Django 和 Netbeans?

    我使用 netbeans 进行所有 Linux 开发 C C Php Python Symfony 我现在正在学习django 想知道是否可以使用netbeans作为IDE 我似乎找不到适用于 netbeans 的 Django 插件 有吗
  • Laravel 运行多个计划任务

    我目前有一个计划的控制台命令 每 5 分钟运行一次 不会重叠 如下所示 schedule gt command crawler gt everyFiveMinutes gt withoutOverlapping gt sendOutputT
  • android 中的 init.rc 是什么语言?

    我需要了解 init rc 的格式 init rc中有很多服务 其中之一是 service bootanim system bin bootanimation user graphics group graphics disabled on
  • iOS WKWebView 不显示 javascriptalert() 对话框

    我在 iOS 8 中使用 WKWebView 显示从 Javascript 调用的警报对话框时遇到一些问题 创建标准 WKWebView 并加载 HTML 文件后 我在页面上有一个按钮 用于创建带有一些文本的简单警报 这适用于 UIWebV
  • 在C#(WinForms)中拦截应用程序中所有控件的点击事件

    我想创建一个应用程序来拦截应用程序所有形式的所有 UI 事件并将它们写入日志 然后可以使用这些数据来查看哪些控件最常用 按什么顺序等 问题是我希望这种情况自动发生 而不需要修改现有的类 我制作了一个原型 将一个方法附加到表单中所有控件的单击
  • 64 位 Win 上缺少 dll

    我有一个 net 应用程序 它使用一些 vc 编译的 Win32 dll 它在 32 位 Win 上运行良好 但在 64 位上存在问题 无法加载 DLL xyz 找不到指定的模块 HRESULT 异常 0x8007007E 使用depend
  • 在 Python 中的函数中使用嵌套函数内的全局变量

    我想知道为什么我的代码不起作用 我预计它会返回 11 但它创建了一个异常 def f counter 1 def f1 global counter counter 1 while True f1 if counter gt 10 retu
  • Delphi Win32 的最佳共享软件锁 [关闭]

    Closed 此问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 目前不接受答案 与我上一个问题相同的介绍 我正在重写和 或合并一堆我的 应用程序框架 类 基本主窗体 关于框 锁定例程和购买链接 自动更新 数据模块初始化程序等 基
  • 在哪里可以获得 groovy-all-4.0.0.jar?

    我在哪里可以获取 下载 groovy all 4 0 0 jar 其中包含一个文件中所有重要的 Groovy 4 0 模块 类 到目前为止我只找到了一个pom文件 但我无法使用Maven https repo1 maven org mave
  • com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException:在 mysql 中

    您好 我已经创建了 jdbc 程序 数据库是 MySQL 5 1 我所有的朋友也使用相同的数据库进行连接 我们所有人的联系总数变成了150个 所以当我想连接更多时我收到以下错误 com mysql jdbc exceptions jdbc4
  • WPF 根元素对于导航无效

    我正在将 WPF XBAP 应用程序转换为 WPF 桌面应用程序 我让它在桌面上运行 但现在尝试将页面引用更改为窗口引用 MyApp StartForm root element is not valid for navigation 我尝
  • 如何更改导航抽屉标题中 TextView 的文本?

    我想更改导航抽屉标题内 TextView 的文本 但我收到这个错误 java lang NullPointerException 尝试调用虚拟方法 void android widget TextView setText java lang
  • ASP.NET / C#:服务器控件中的 DropDownList SelectedIndexChanged 未触发

    我正在创建一个服务器控件 它基本上绑定两个下拉列表 一个用于国家 地区 一个用于州 并更新国家 地区的 selectedindexchanged 事件的州下拉列表 但是 它不会回发 有什么想法吗 将它们包装在 UpdatePanel 中的奖
  • strtotime() 被认为有害吗?

    似乎很多人都在为 PHP 中的日期 时间问题而苦苦挣扎 不可避免地 许多接受的答案往往是 Use strtotime这样 这真的是指导人们处理约会问题的最佳方式吗 我开始觉得strtotime是一种巧妙的技巧 不一定依赖于重要的日期 时间计
  • 实时 PL/SQL 输出

    是否可以实时获得 PL SQL 的输出 我有一个相当大的包裹 运行了一个多小时 我想看看该包裹在特定时间在哪里 无论如何 我目前使用一个日志表来执行此操作 每次运行该表都会填充数百个日志描述 我只是好奇这是否可能 Thanks 这就是我使用
  • 在大括号和管道中对命令进行分组不会保留变量

    说我有一个文件myfile在我当前的工作目录中 如果命令正常执行 我想设置一个变量 但也使用它的结果 ls myfile v 3 myfile echo v 3 但现在我也想通过管道传输结果 所以我使用 list 对命令进行分组的语法 un
  • 响应式设计:不同屏幕尺寸显示不同图像

    我们的客户希望在小屏幕上与大屏幕上有不同的横幅图像 不仅仅是收缩 拉伸以适应 而且实际上替换了不同的图像 全尺寸图像相当复杂 几个人 两个徽标和一些装饰文本 因此对于较小的图像 他们想要裁剪掉一些人 删除徽标等 所以他们想要最大的 最复杂的
  • 为什么带有两个常量的三元运算符比带有变量的三元运算符更快?

    在Java中 我有两个不同的语句 通过使用三元运算符来实现相同的结果 如下所示 num lt 0 0 num num num lt 0 0 1 看来第二条语句不必要地复杂 并且比第一条语句花费的时间更长 但是当我使用以下代码记录每个语句所花