RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 1596305
Accepted
Пьяная фея
Пьяная фея
Asked:2024-10-11 01:17:35 +0000 UTC2024-10-11 01:17:35 +0000 UTC 2024-10-11 01:17:35 +0000 UTC

C++ 嵌套数组数据访问和优化

  • 772

让我们想象一个存储数值的嵌套(二维)10x10 数组。我通常看到的迭代值的经典方法是嵌套循环,顺序读取第一个“行”的元素,然后转到下一个。

如果这些行中的每一行都占用一个单独的内存区域,则将有 10 次通过这些区域的转换,以及对行中各个元素的 10 次访问。
(模式:元素=数组[X][Y])

据我所知,访问行(X)比访问其中的元素(Y)花费更多的计算资源。

问题: 当非顺序访问数组元素时,并且行间跳转更加频繁(总共会产生超过 10 次转换),搜索时间会增加吗?

c++
  • 1 1 个回答
  • 26 Views

1 个回答

  • Voted
  1. Best Answer
    Harry
    2024-10-11T02:08:55Z2024-10-11T02:08:55Z

    您没有指出您实际上想要哪种二维数组。那么我们就来看最简单的一个:int arr[10][10];

    为了“跳”得更猛烈,我们逐行、逐列地总结一下……

    int enumer1()
    {
        int sum = 0;
        for(int i = 0; i < 10; ++i)
            for(int j = 0; j < 10; ++j)
                sum += arr[i][j];
        return sum;
    }
    int enumer2()
    {
        int sum = 0;
        for(int j = 0; j < 10; ++j)
            for(int i = 0; i < 10; ++i)
                sum += arr[i][j];
        return sum;
    }
    

    让我们编译并查找汇编代码中的差异。

    ?enumer2@@YAHXZ PROC                                  ?enumer1@@YAHXZ PROC                                 ; enumer2, COMDAT
    
    ; 31   :     int sum = 0;                             ; 23   :     int sum = 0;
    
            xor     eax, eax                                      xor     eax, eax
            lea     r8, OFFSET FLAT:?arr@@3PAY0CHBA@HA            lea     r8, OFFSET FLAT:?arr@@3PAY0CHBA@HA   ; arr
            mov     edx, eax                                      mov     edx, eax
            npad    5                                             npad    5
    $LL4@enumer2:                                         $LL4@enumer1:
    
    ; 32   :     for(int j = 0; j < 10; ++j)              ; 24   :     for(int i = 0; i < 10; ++i)
    ; 33   :         for(int i = 0; i < 10; ++i)          ; 25   :         for(int j = 0; j < 10; ++j)
    ; 34   :             sum += arr[i][j];                ; 26   :             sum += arr[i][j];
    
            mov     ecx, DWORD PTR [rdx+r8+32]                    mov     ecx, DWORD PTR [rdx+r8+32]
            add     ecx, DWORD PTR [rdx+r8+28]                    add     ecx, DWORD PTR [rdx+r8+28]
            add     ecx, DWORD PTR [rdx+r8+24]                    add     ecx, DWORD PTR [rdx+r8+24]
            add     ecx, DWORD PTR [rdx+r8+20]                    add     ecx, DWORD PTR [rdx+r8+20]
            add     ecx, DWORD PTR [rdx+r8+16]                    add     ecx, DWORD PTR [rdx+r8+16]
            add     ecx, DWORD PTR [rdx+r8+12]                    add     ecx, DWORD PTR [rdx+r8+12]
            add     ecx, DWORD PTR [rdx+r8+8]                     add     ecx, DWORD PTR [rdx+r8+8]
            add     ecx, DWORD PTR [rdx+r8+4]                     add     ecx, DWORD PTR [rdx+r8+4]
            add     ecx, DWORD PTR [rdx+r8+36]                    add     ecx, DWORD PTR [rdx+r8+36]
            add     ecx, DWORD PTR [rdx+r8]                       add     ecx, DWORD PTR [rdx+r8]
            add     rdx, 40000                                    add     rdx, 40000                           ; 00009c40H
            add     eax, ecx                                      add     eax, ecx
            cmp     rdx, 400000                                   cmp     rdx, 400000                          ; 00061a80H
            jl      SHORT $LL4@enumer2                            jl      SHORT $LL4@enumer1
    
    ; 35   :     return sum;                              ; 27   :     return sum;
    ; 36   : }                                            ; 28   : }
    
            ret     0                                             ret     0
    ?enumer2@@YAHXZ ENDP                                  ?enumer1@@YAHXZ ENDP                                 ; enumer2
    

    你也没有看出区别吗? :)

    好吧,让我们关闭优化。循环看起来相同,对数组元素的调用也相同:

    ; 26   :             sum += arr[i][j];          ; 34   :             sum += arr[i][j];
    
    movsxd  rax, DWORD PTR i$1[rsp]                 movsxd  rax, DWORD PTR i$1[rsp]
    imul    rax, rax, 40000                         imul    rax, rax, 40000
    lea     rcx, OFFSET FLAT:?arr@@3PAY0CHBA@HA     lea     rcx, OFFSET FLAT:?arr@@3PAY0CHBA@HA
    add     rcx, rax                                add     rcx, rax
    mov     rax, rcx                                mov     rax, rcx
    movsxd  rcx, DWORD PTR j$2[rsp]                 movsxd  rcx, DWORD PTR j$2[rsp]
    mov     eax, DWORD PTR [rax+rcx*4]              mov     eax, DWORD PTR [rax+rcx*4]
    mov     ecx, DWORD PTR sum$[rsp]                mov     ecx, DWORD PTR sum$[rsp]
    

    所以对于数组来说int[][],内存是一块分配的,本质上没有什么区别。尤其是这种大小的数组,当整个数组可以轻松放入处理器缓存中时......

    但如果你考虑

    int ** arr = new int*[10];
    for(int i = 0; i < 10; ++i) arr[i] = new int[10];
    

    差异最终会出现。但你不太可能在 10x10 矩阵上捕捉到它。现在在 1000x1000 下更加真实。请参阅此处的代码和结果: https: //bit.ly/3Y091w6

    你的好奇心满足了吗?

    • 3

相关问题

  • 编译器和模板处理

  • 指针。找到最小数量

  • C++,关于枚举类对象初始化的问题

  • 函数中的二维数组

  • 无法使用默认构造函数创建类对象

  • C++ 和循环依赖

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    我看不懂措辞

    • 1 个回答
  • Marko Smith

    请求的模块“del”不提供名为“default”的导出

    • 3 个回答
  • Marko Smith

    "!+tab" 在 HTML 的 vs 代码中不起作用

    • 5 个回答
  • Marko Smith

    我正在尝试解决“猜词”的问题。Python

    • 2 个回答
  • Marko Smith

    可以使用哪些命令将当前指针移动到指定的提交而不更改工作目录中的文件?

    • 1 个回答
  • Marko Smith

    Python解析野莓

    • 1 个回答
  • Marko Smith

    问题:“警告:检查最新版本的 pip 时出错。”

    • 2 个回答
  • Marko Smith

    帮助编写一个用值填充变量的循环。解决这个问题

    • 2 个回答
  • Marko Smith

    尽管依赖数组为空,但在渲染上调用了 2 次 useEffect

    • 2 个回答
  • Marko Smith

    数据不通过 Telegram.WebApp.sendData 发送

    • 1 个回答
  • Martin Hope
    Alexandr_TT 2020年新年大赛! 2020-12-20 18:20:21 +0000 UTC
  • Martin Hope
    Alexandr_TT 圣诞树动画 2020-12-23 00:38:08 +0000 UTC
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5