找回密码
 注册
搜索
系统gho:最纯净好用系统下载站投放广告、加入VIP会员,请联系 微信:wuyouceo
查看: 455|回复: 15

[讨论] 求助:程序速度比较

[复制链接]
发表于 3 天前 | 显示全部楼层 |阅读模式
数组 a[0]~a[n-1],共n个元素。
组成数值圆环,首尾相连。
首值下标 i=0,向后移动(i++)
尾值下标 j=n-1,向前移动(j--)

如何做到数值循环访问,以下有2个方案
方案A:
while (true)
{
  if  ( i≠(n-1) )
    i++ ;
  else
    i=0 ;

  if  ( j≠0 )
    j-- ;
  else
    j=n-1 ;

  其它程序段
}

方案B:
while (true)
{
  i = (i+1)  mod  n  ;
  j = (n+j-1)  mod  n  ;

  其它程序段
}

两种边界处理方式,哪个更快一些?
例如采用C++编译,方案A 的 if 语句,方案B 的mod运算,耗用机器指令的时钟周期,相差有多少?
个人有以下理解,if 语句 编译成机器语言后,大约耗时20个时钟。而mod运算本质上是除法指令,大约耗时200个时钟。两者耗时相差10倍。
这样理解是否有误区?
个人更喜欢方案A,直观、简单、容易理解。
而方案B,看起来高大上,纸面上程序简洁,但是难理解,而且速度慢。

发表于 3 天前 | 显示全部楼层
我是菜鸟,期待牛人的解答
回复

使用道具 举报

发表于 3 天前 | 显示全部楼层
本帖最后由 wintoflash 于 2026-6-13 23:28 编辑
数组 a[0]~a[n-1],共n个元素。

这个n,是编译期常量还是变量?
如果n是编译期常量,对于 x mod n 这种语句,编译器会自动优化为移位和加减法操作,不会生成除法指令,这种情况下不好说。
如果n是编译期常量,且是 2 的整数幂(如1024),编译器会自动优化为只有移位操作,一般情况下是方案B快。
如果n是变量,那肯定是方案A快。

点评

大佬还在坚守论坛么。。有好多技术达人都不在论坛了,可惜了  详情 回复 发表于 前天 00:00

评分

参与人数 1无忧币 +1 收起 理由
proof + 1 赞一个!

查看全部评分

回复

使用道具 举报

发表于 3 天前 | 显示全部楼层
我只会一丢丢AU3,不懂撸主说的圆环是啥...


二○二六年六月十三日
回复

使用道具 举报

发表于 3 天前 | 显示全部楼层
wintoflash 发表于 2026-6-13 22:21
这个n,是编译期常量还是变量?
如果n是编译期常量,对于 x mod n 这种语句,编译器会自动优化为移位和加 ...

这就是专业阿
回复

使用道具 举报

发表于 前天 00:00 | 显示全部楼层
wintoflash 发表于 2026-6-13 22:21
这个n,是编译期常量还是变量?
如果n是编译期常量,对于 x mod n 这种语句,编译器会自动优化为移位和加 ...

大佬还在坚守论坛么。。有好多技术达人都不在论坛了,可惜了
回复

使用道具 举报

发表于 前天 07:05 | 显示全部楼层
不怎么看得明白
回复

使用道具 举报

发表于 前天 08:16 | 显示全部楼层
类似于减半 不断的。。。下去。。(个人理解)
用上多线程就提速了。
回复

使用道具 举报

发表于 前天 08:18 来自手机 | 显示全部楼层
学习学习
回复

使用道具 举报

发表于 前天 09:13 | 显示全部楼层
难得还有人会思考这类问题,现在多数人所谓的编程,能跑就行了
回复

使用道具 举报

发表于 前天 10:20 | 显示全部楼层
本帖最后由 wintoflash 于 2026-6-14 11:27 编辑

另外也不能单纯地看指令数量/耗时。
比如反直觉的一点是,某些场景下(比如多个数组并行访问等),CPU操作 int a[1025] 比 int a[1024] 更快。
a.png

评分

参与人数 1无忧币 +1 收起 理由
proof + 1 这个更专业、更具体了

查看全部评分

回复

使用道具 举报

发表于 前天 10:57 | 显示全部楼层
方案A好些
  • 大多数情况下更快——n是变量时快一个数量级
  • 可读性碾压——任何人都能一眼看懂
  • 即使n是2的幂常量,方案B的优势也只有1-2个周期,在真实程序中完全可以忽略
  • 不要提前优化掉清晰性,除非profiler告诉你这里是瓶颈

如果非要优化到极致,可以用模板特化:

  1. template<size_t N>
  2. inline size_t next_i(size_t i) {
  3.     if constexpr ((N & (N-1)) == 0)  // N是2的幂
  4.         return (i + 1) & (N - 1);
  5.     else
  6.         return (i + 1 < N) ? i + 1 : 0;
  7. }
复制代码



回复

使用道具 举报

发表于 前天 17:04 | 显示全部楼层
还有这种想法
回复

使用道具 举报

发表于 前天 22:09 | 显示全部楼层
你更偏好方案 A(直观、易理解)完全没问题。代码清晰是第一优先级,除非性能热点需要优化。
方案B 虽然简洁,但依赖模运算,阅读时需思考“为什么这样写”,可读性稍差。
不过,如果你在一个频繁使用环形缓冲区的项目里,可以封装成一个宏或内联函数,如 NEXT(i, n),既简洁又明确。

评分

参与人数 1无忧币 +1 收起 理由
proof + 1

查看全部评分

回复

使用道具 举报

发表于 昨天 14:02 | 显示全部楼层
来学习一下
回复

使用道具 举报

发表于 1 小时前 | 显示全部楼层
本帖最后由 Muacs 于 2026-6-16 01:23 编辑

既然讨论代码效率,那就不得不从汇编角度考虑了
方案A有个最大的问题,就是可能会遇到分支预测失败,一旦触发,整条指令流水线清空,性能开销瞬间暴涨几十倍;
汇编代码里有两条jne跳转指令,一旦命中重置分支,指令流水线重置,产生惩罚周期。
而方案B全程无分支跳转,性能稳定。

你有两个误区,
1.if虽然代码看起来直观,但≠性能更好,很容易遇到分支预测失败的的情况,
   分支代码最大的性能杀手不是单次判断,而是分支预测失败时的不确定性带来的延迟。
2.其实现代的CPU和编译器下,方案B的模运算实际上也远没有200,除法一般只有10~40周期,而且常量取模时会直接消除除法运算;
   mod n这里n是常量时,编译器会把取模优化成乘法+移位,完全消除除法指令,只有n为变量才会以除法进行运算;
   if的分支遇到最坏的情况时,性能损失远超除法开销;单次循环对比时,多数场景B也会比A更快。

总结:
新手用方案A可能更好,因为代码可读性更好,方案B需要熟悉模运算。
具体使用也需要结合实际项目环境。
如果是高频次循环,追求稳定,比如游戏、音视频处理、实时环形缓冲区等,用方案B更好。
如果是低频次循环,数组长度小且固定,还有逻辑判断多时,可以用方案A牺牲一点性能来换取代码可读性。
还有个方法是就是把方案A代码修改一下,和原逻辑相等,编译器会消除跳转,性能优于原来的双if。
  1. while (true)
  2. {
  3.     ++i;
  4.     if (i == n) i = 0;

  5.     --j;
  6.     if (j == -1) j = n - 1;
  7.     // 其它
  8. }
复制代码



回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

小黑屋|手机版|Archiver|捐助支持|无忧启动 ( 闽ICP备05002490号-1|闽公网安备35020302032614号 )

GMT+8, 2026-6-16 02:43

Powered by Discuz! X5.0

© 2001-2026 Discuz! Team.

快速回复 返回顶部 返回列表