proof1 发表于 2026-6-12 14:55

求助:程序速度比较



数组 a~a,共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)modn;
  j = (n+j-1)modn;


  其它程序段
}


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

Rainwedell 发表于 2026-6-12 15:01

这种东西问AI 比上S1问又快又准,合理怀疑楼主就是想要白嫖ai回答,这是claude 答案:


结论先说:你的方向对(方案A通常更快),但两个数字都不准,各错了一个数量级。

**if 语句的真实开销**

编译后是 `cmp` + 条件跳转,在现代 x86 上这俩经常宏融合成一条 µop。关键在分支预测:

- 预测命中:约 1~2 个周期,几乎免费
- 预测失败:才是你说的 15~20 周期(流水线清空)

而你这个分支极其规律——n 次循环里只有 1 次走 else 分支,预测器轻松学会,几乎每次都命中。所以方案A的真实成本接近 1~2 周期,不是 20。

**mod 的真实开销**

mod 编译成 `div`/`idiv` 指令。32 位除法在 Skylake 上延迟约 20~26 周期,Ice Lake / Zen 3 之后已优化到约 10~18 周期,64 位会更慢一些。不是 200,200 周期那是上世纪的 CPU 或软件模拟除法的水平。

所以真实差距大约还是 10 倍量级(2 周期 vs 20 周期),你的结论碰巧成立,但绝对值都高估了 10 倍。

**三个重要的"但是"**

1. 如果 n 是编译期常量,编译器根本不会生成 div,而是用乘法+移位的魔数技巧(约 4~6 周期);如果 n 是 2 的幂,直接 `and` 掩码,1 个周期,这时方案B反而最快。
2. 比你的方案A更优的写法是:

```cpp
if (++i == n) i = 0;
if (j-- == 0) j = n - 1;
```

   逻辑等价但编译器很容易把它生成 `cmov`(条件传送),完全无分支、无预测失败风险,稳定 2~3 周期。这是环形缓冲区的标准写法。

3. 实战中这点差距通常无关紧要——循环体里只要碰一次内存(数组访问、cache miss 几十到几百周期),索引回绕的开销就被淹没了。除非循环体极小且全在寄存器里跑,否则 A/B 测不出差别。

所以你的审美没问题:方案A(或上面的 cmov 友好写法)直观且快。方案B 的价值主要在 n 为 2 的幂时(掩码写法 `i = (i+1) & (n-1)` 既简洁又是最快的),通用变量 n 下确实是又慢又"装"。

Xerxes_2 发表于 2026-6-12 15:02

    let mut forward = (0..n).cycle();
    let mut backward = (0..n).rev().cycle();
    loop {
      let i = forward.next().unwrap();
      let j = backward.next().unwrap();
    }


Rust,别纠结这个了,编译器比你想象中的聪明

子犴 发表于 2026-6-12 15:53

看了看楼主发帖记录 楼主这是把探油当AI用了 也是提前好几年用上“人工”智能了

proof1 发表于 2026-6-12 16:09

Xerxes_2 发表于 2026-6-12 15:02
Rust,别纠结这个了,编译器比你想象中的聪明

看不懂,话说这是什么语言?

还是C++的某种库模版?(之前我猜测,已经有某种现成的环状数据结构,提供给设计者使用)

Xerxes_2 发表于 2026-6-12 16:20

proof1 发表于 2026-6-12 18:09
看不懂,话说这是什么语言?

还是C++的某种库模版?(之前我猜测,已经有某种现成的环状数据结构,提供 ...

Rust,我说了啊

noword 发表于 2026-6-12 17:58

楼主先评估下是否真到了需要抠这点性能的地步

—— 来自 Xiaomi 22041211AC, Android 12, 鹅球 v4.0.100-alpha

元肉丸子 发表于 2026-6-12 20:22

楼主是程序员吗?我不是程序员都知道rust

袄_偶滴小乔 发表于 2026-6-12 20:43

子犴 发表于 2026-6-12 15:53
看了看楼主发帖记录 楼主这是把探油当AI用了 也是提前好几年用上“人工”智能了 ...

“人肉搜索”这个词已经变死语了吗

流缨 发表于 2026-6-12 23:24

为什么知名活化石proof1**还在纠结编程问题?本来以为到了AI时代**应该已经没有上泥潭的必要了
我甚至记得去年还是前年他问过一个vf6.0的问题

WiiGe 发表于 2026-6-13 00:08

我雷达响了,是 python 侠!

金轮法王 发表于 2026-6-13 06:30

ring buffer直接用boost库里的不就行了,干嘛手搓啊

—— 来自 Xiaomi 24129PN74C, Android 16, 鹅球 v3.5.99

yikaa 发表于 2026-6-13 17:37

没有benchmark的性能讨论毫无意义

—— 来自 Xiaomi 23049RAD8C, Android 15, 鹅球 v3.5.99

proof1 发表于 2026-6-13 21:55

本帖最后由 proof1 于 2026-6-13 21:57 编辑

2. 比你的方案A更优的写法是:

if(++i == n)   i = 0 ;
if(j-- == 0)   j = n-1 ;

这是环形缓冲区的标准写法。
if(j-- == 0)   j = n-1 ;
 不解
A、先判断,如果j≠0,执行j--,略过 j=n-1
B、先判断,如果j=0,执行j--,执行 j=n-1

是这个过程吗?

子犴 发表于 2026-6-13 23:34

袄_偶滴小乔 发表于 2026-6-12 20:43
“人肉搜索”这个词已经变死语了吗

过去只有这个词 但是现在回头看 “搜索”已经不足以形容楼主这种行为了 这不是单纯从已有资料中查找 而是让探油无私创造 😄

盐星 发表于 2026-6-14 00:36

袄_偶滴小乔 发表于 2026-6-12 20:43
“人肉搜索”这个词已经变死语了吗
人肉搜索是死语了没错
但是死语的原因是这个词的词义放今天叫“开盒”啊

袄_偶滴小乔 发表于 2026-6-14 01:40

盐星 发表于 2026-6-14 00:36
人肉搜索是死语了没错
但是死语的原因是这个词的词义放今天叫“开盒”啊 ...

开盒是指人肉搜索的对象是人,媒体传多了把最关键的因素给传没了,导致这个词后期有所转义。“人肉“是和”搜索引擎“相对的,那个时期最典型的人肉搜索其实是百度知道

scikirbypoke 发表于 2026-6-14 09:14

鹅球4.0进来就看见负鹅,很方便

ticatwj 发表于 2026-6-16 14:59

h哈哈,lz全是求助贴, 一排
页: [1]
查看完整版本: 求助:程序速度比较