免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: yulihua49
打印 上一主题 下一主题

[C] 通用可重复值的排序数组的二分法检索 [复制链接]

论坛徽章:
44
15-16赛季CBA联赛之浙江
日期:2021-10-11 02:03:59程序设计版块每日发帖之星
日期:2016-07-02 06:20:0015-16赛季CBA联赛之新疆
日期:2016-04-25 10:55:452016科比退役纪念章
日期:2016-04-23 00:51:2315-16赛季CBA联赛之山东
日期:2016-04-17 12:00:2815-16赛季CBA联赛之福建
日期:2016-04-12 15:21:2915-16赛季CBA联赛之辽宁
日期:2016-03-24 21:38:2715-16赛季CBA联赛之福建
日期:2016-03-18 12:13:4015-16赛季CBA联赛之佛山
日期:2016-02-05 00:55:2015-16赛季CBA联赛之佛山
日期:2016-02-04 21:11:3615-16赛季CBA联赛之天津
日期:2016-11-02 00:33:1215-16赛季CBA联赛之浙江
日期:2017-01-13 01:31:49
31 [报告]
发表于 2016-11-03 13:54 |只看该作者
回复 30# yulihua49

怎么可能,你看我的代码不就用的是数组么……

论坛徽章:
15
射手座
日期:2014-11-29 19:22:4915-16赛季CBA联赛之青岛
日期:2017-11-17 13:20:09黑曼巴
日期:2017-07-13 19:13:4715-16赛季CBA联赛之四川
日期:2017-02-07 21:08:572015年亚冠纪念徽章
日期:2015-11-06 12:31:58每日论坛发贴之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-07-12 22:20:002015亚冠之浦和红钻
日期:2015-07-08 10:10:132015亚冠之大阪钢巴
日期:2015-06-29 11:21:122015亚冠之广州恒大
日期:2015-05-22 21:55:412015年亚洲杯之伊朗
日期:2015-04-10 16:28:25
32 [报告]
发表于 2016-11-03 14:33 |只看该作者
本帖最后由 yulihua49 于 2016-11-03 14:59 编辑
windoze 发表于 2016-11-03 13:54
回复 30# yulihua49

怎么可能,你看我的代码不就用的是数组么……

我查不到。

-O3是STL快了。大概是宏,更容易优化吧。
优化的汇编码看了,完全看不懂,二者都被打乱了函数调用的次序。比较函数都被嵌入到代码里了。
又试了下使用库函数,这个完全不能与应用代码揉合,就得老老实实调函数。速度更慢了。但是看汇编码,简单明了,已经无法优化了。

-O3对宏的优化水平的确超过了一般汇编程序员的能力。

附上汇编码,还看得出来就是前边的cpp程序吗?


  1. [sdbc@erg0devprc01 test]$ cat stl_test.s
  2.         .file   "stl_test.cpp"
  3.         .text
  4.         .p2align 4,,15
  5.         .globl  _Z3cmpPvS_i
  6.         .type   _Z3cmpPvS_i, @function
  7. _Z3cmpPvS_i:
  8. .LFB1218:
  9.         .cfi_startproc
  10.         movslq  %edx, %rdx
  11.         movl    (%rsi,%rdx,4), %eax
  12.         subl    (%rdi), %eax
  13.         ret
  14.         .cfi_endproc
  15. .LFE1218:
  16.         .size   _Z3cmpPvS_i, .-_Z3cmpPvS_i
  17.         .p2align 4,,15
  18.         .globl  _Z5test2v
  19.         .type   _Z5test2v, @function
  20. _Z5test2v:
  21. .LFB1221:
  22.         .cfi_startproc
  23.         movl    $100000, %edi
  24.         movl    $test_data, %esi
  25. .L3:
  26.         movq    %rdi, %rax
  27.         sarq    %rax
  28.         leaq    (%rsi,%rax,4), %rcx
  29.         cmpl    $8000, (%rcx)
  30.         jg      .L7
  31.         jmp     .L11
  32.         .p2align 4,,10
  33.         .p2align 3
  34. .L5:
  35.         movq    %rax, %rdx
  36.         sarq    %rdx
  37.         leaq    (%rsi,%rdx,4), %rcx
  38.         cmpl    $8000, (%rcx)
  39.         jle     .L4
  40.         movq    %rdx, %rax
  41. .L7:
  42.         testq   %rax, %rax
  43.         jg      .L5
  44. .L6:
  45.         subq    $test_data, %rsi
  46.         sarq    $2, %rsi
  47.         subq    $1, %rsi
  48.         movq    %rsi, garbage(%rip)
  49.         ret
  50. .L11:
  51.         movq    %rax, %rdx
  52.         movq    %rdi, %rax
  53.         .p2align 4,,10
  54.         .p2align 3
  55. .L4:
  56.         subq    %rdx, %rax
  57.         leaq    4(%rcx), %rsi
  58.         leaq    -1(%rax), %rdi
  59.         testq   %rdi, %rdi
  60.         jg      .L3
  61.         jmp     .L6
  62.         .cfi_endproc
  63. .LFE1221:
  64.         .size   _Z5test2v, .-_Z5test2v
  65.         .p2align 4,,15
  66.         .globl  _Z5test1v
  67.         .type   _Z5test1v, @function
  68. _Z5test1v:
  69. .LFB1219:
  70.         .cfi_startproc
  71.         subq    $24, %rsp
  72.         .cfi_def_cfa_offset 32
  73.         movl    $_Z3cmpPvS_i, %ecx
  74.         movl    $100000, %edx
  75.         movq    %rsp, %rdi
  76.         movl    $test_data, %esi
  77.         movl    $8000, (%rsp)
  78.         call    upperBound
  79.         subl    $1, %eax
  80.         cltq
  81.         movq    %rax, garbage(%rip)
  82.         addq    $24, %rsp
  83.         .cfi_def_cfa_offset 8
  84.         ret
  85.         .cfi_endproc
  86. .LFE1219:
  87.         .size   _Z5test1v, .-_Z5test1v
  88.         .section        .text.unlikely,"ax",@progbits
  89.         .type   _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc.part.1, @function
  90. _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc.part.1:
  91. .LFB1242:
  92.         .cfi_startproc
  93.         pushq   %rax
  94.         .cfi_def_cfa_offset 16
  95.         movq    (%rdi), %rax
  96.         addq    -24(%rax), %rdi
  97.         movl    32(%rdi), %esi
  98.         orl     $1, %esi
  99.         call    _ZNSt9basic_iosIcSt11char_traitsIcEE5clearESt12_Ios_Iostate
  100.         popq    %rdx
  101.         .cfi_def_cfa_offset 8
  102.         ret
  103.         .cfi_endproc
  104. .LFE1242:
  105.         .size   _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc.part.1, .-_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc.part.1
  106.         .text
  107.         .p2align 4,,15
  108.         .globl  _Z18generate_test_datav
  109.         .type   _Z18generate_test_datav, @function
  110. _Z18generate_test_datav:
  111. .LFB1217:
  112.         .cfi_startproc
  113.         xorl    %ecx, %ecx
  114.         movabsq $-3689348814741910323, %rsi
  115.         .p2align 4,,10
  116.         .p2align 3
  117. .L18:
  118.         movq    %rcx, %rax
  119.         mulq    %rsi
  120.         shrq    $3, %rdx
  121.         movl    %edx, test_data(,%rcx,4)
  122.         addq    $1, %rcx
  123.         cmpq    $100000, %rcx
  124.         jne     .L18
  125.         rep ret
  126.         .cfi_endproc
  127. .LFE1217:
  128.         .size   _Z18generate_test_datav, .-_Z18generate_test_datav
  129.         .section        .rodata.str1.1,"aMS",@progbits,1
  130. .LC0:
  131.         .string "Duration: "
  132. .LC1:
  133.         .string ",N="
  134.         .text
  135.         .p2align 4,,15
  136.         .globl  _Z7time_itmPFvvE
  137.         .type   _Z7time_itmPFvvE, @function
  138. _Z7time_itmPFvvE:
  139. .LFB1222:
  140.         .cfi_startproc
  141.         pushq   %r13
  142.         .cfi_def_cfa_offset 16
  143.         .cfi_offset 13, -16
  144.         pushq   %r12
  145.         .cfi_def_cfa_offset 24
  146.         .cfi_offset 12, -24
  147.         movq    %rsi, %r12
  148.         pushq   %rbp
  149.         .cfi_def_cfa_offset 32
  150.         .cfi_offset 6, -32
  151.         movq    %rdi, %rbp
  152.         pushq   %rbx
  153.         .cfi_def_cfa_offset 40
  154.         .cfi_offset 3, -40
  155.         xorl    %ebx, %ebx
  156.         subq    $8, %rsp
  157.         .cfi_def_cfa_offset 48
  158.         call    now_usec
  159.         testq   %rbp, %rbp
  160.         movq    %rax, %r13
  161.         je      .L23
  162.         .p2align 4,,10
  163.         .p2align 3
  164. .L27:
  165.         addq    $1, %rbx
  166.         call    *%r12
  167.         cmpq    %rbp, %rbx
  168.         jne     .L27
  169. .L23:
  170.         movq    garbage(%rip), %rbp
  171.         call    now_usec
  172.         movl    $10, %edx
  173.         movq    %rax, %rbx
  174.         movl    $.LC0, %esi
  175.         movl    $_ZSt4cout, %edi
  176.         call    _ZSt16__ostream_insertIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_PKS3_l
  177.         movl    %ebx, %esi
  178.         movl    $_ZSt4cout, %edi
  179.         subl    %r13d, %esi
  180.         call    _ZNSolsEi
  181.         movl    $3, %edx
  182.         movq    %rax, %rbx
  183.         movl    $.LC1, %esi
  184.         movq    %rax, %rdi
  185.         call    _ZSt16__ostream_insertIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_PKS3_l
  186.         movq    %rbp, %rsi
  187.         movq    %rbx, %rdi
  188.         call    _ZNSo9_M_insertImEERSoT_
  189.         movq    %rax, %rbp
  190.         movq    (%rax), %rax
  191.         movq    -24(%rax), %rax
  192.         movq    240(%rbp,%rax), %rbx
  193.         testq   %rbx, %rbx
  194.         je      .L30
  195.         cmpb    $0, 56(%rbx)
  196.         je      .L25
  197.         movzbl  67(%rbx), %eax
  198. .L26:
  199.         movq    %rbp, %rdi
  200.         movsbl  %al, %esi
  201.         call    _ZNSo3putEc
  202.         addq    $8, %rsp
  203.         .cfi_remember_state
  204.         .cfi_def_cfa_offset 40
  205.         movq    %rax, %rdi
  206.         popq    %rbx
  207.         .cfi_def_cfa_offset 32
  208.         popq    %rbp
  209.         .cfi_def_cfa_offset 24
  210.         popq    %r12
  211.         .cfi_def_cfa_offset 16
  212.         popq    %r13
  213.         .cfi_def_cfa_offset 8
  214.         jmp     _ZNSo5flushEv
  215.         .p2align 4,,10
  216.         .p2align 3
  217. .L25:
  218.         .cfi_restore_state
  219.         movq    %rbx, %rdi
  220.         call    _ZNKSt5ctypeIcE13_M_widen_initEv
  221.         movq    (%rbx), %rax
  222.         movl    $10, %esi
  223.         movq    %rbx, %rdi
  224.         call    *48(%rax)
  225.         jmp     .L26
  226. .L30:
  227.         call    _ZSt16__throw_bad_castv
  228.         .cfi_endproc
  229. .LFE1222:
  230.         .size   _Z7time_itmPFvvE, .-_Z7time_itmPFvvE
  231.         .section        .rodata.str1.1
  232. .LC2:
  233.         .string "Binary "
  234. .LC3:
  235.         .string "MAP "
  236.         .section        .text.startup,"ax",@progbits
  237.         .p2align 4,,15
  238.         .globl  main
  239.         .type   main, @function
  240. main:
  241. .LFB1223:
  242.         .cfi_startproc
  243.         xorl    %ecx, %ecx
  244.         movabsq $-3689348814741910323, %rsi
  245.         .p2align 4,,10
  246.         .p2align 3
  247. .L33:
  248.         movq    %rcx, %rax
  249.         mulq    %rsi
  250.         shrq    $3, %rdx
  251.         movl    %edx, test_data(,%rcx,4)
  252.         addq    $1, %rcx
  253.         cmpq    $100000, %rcx
  254.         jne     .L33
  255.         pushq   %rbx
  256.         .cfi_def_cfa_offset 16
  257.         .cfi_offset 3, -16
  258.         movl    $100, %ebx
  259.         subq    $16, %rsp
  260.         .cfi_def_cfa_offset 32
  261.         .p2align 4,,10
  262.         .p2align 3
  263. .L40:
  264.         movl    $test_data, %esi
  265.         movq    %rsp, %rdi
  266.         movl    $_Z3cmpPvS_i, %ecx
  267.         movl    $100000, %edx
  268.         movl    $8000, (%rsp)
  269.         call    upperBound
  270.         movl    $test_data, %esi
  271.         movl    $100000, %edi
  272. .L34:
  273.         movq    %rdi, %rax
  274.         sarq    %rax
  275.         leaq    (%rsi,%rax,4), %rcx
  276.         cmpl    $8000, (%rcx)
  277.         jg      .L38
  278.         jmp     .L44
  279.         .p2align 4,,10
  280.         .p2align 3
  281. .L36:
  282.         movq    %rax, %rdx
  283.         sarq    %rdx
  284.         leaq    (%rsi,%rdx,4), %rcx
  285.         cmpl    $8000, (%rcx)
  286.         jle     .L35
  287.         movq    %rdx, %rax
  288. .L38:
  289.         testq   %rax, %rax
  290.         jg      .L36
  291. .L37:
  292.         subq    $test_data, %rsi
  293.         sarq    $2, %rsi
  294.         subq    $1, %rsi
  295.         subq    $1, %rbx
  296.         movq    %rsi, garbage(%rip)
  297.         jne     .L40
  298.         movl    $.LC2, %esi
  299.         movl    $_ZSt4cout, %edi
  300.         call    _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc
  301.         movl    $_Z5test1v, %esi
  302.         movl    $100000, %edi
  303.         call    _Z7time_itmPFvvE
  304.         movl    $.LC3, %esi
  305.         movl    $_ZSt4cout, %edi
  306.         call    _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc
  307.         movl    $_Z5test2v, %esi
  308.         movl    $100000, %edi
  309.         call    _Z7time_itmPFvvE
  310.         addq    $16, %rsp
  311.         .cfi_remember_state
  312.         .cfi_def_cfa_offset 16
  313.         xorl    %eax, %eax
  314.         popq    %rbx
  315.         .cfi_restore 3
  316.         .cfi_def_cfa_offset 8
  317.         ret
  318. .L44:
  319.         .cfi_restore_state
  320.         movq    %rax, %rdx
  321.         movq    %rdi, %rax
  322.         .p2align 4,,10
  323.         .p2align 3
  324. .L35:
  325.         subq    %rdx, %rax
  326.         leaq    4(%rcx), %rsi
  327.         leaq    -1(%rax), %rdi
  328.         testq   %rdi, %rdi
  329.         jg      .L34
  330.         jmp     .L37
  331.         .cfi_endproc
  332. .LFE1223:
  333.         .size   main, .-main
  334.         .p2align 4,,15
  335.         .type   _GLOBAL__sub_I_test_data, @function
  336. _GLOBAL__sub_I_test_data:
  337. .LFB1240:
  338.         .cfi_startproc
  339.         subq    $8, %rsp
  340.         .cfi_def_cfa_offset 16
  341.         movl    $_ZStL8__ioinit, %edi
  342.         call    _ZNSt8ios_base4InitC1Ev
  343.         movl    $__dso_handle, %edx
  344.         movl    $_ZStL8__ioinit, %esi
  345.         movl    $_ZNSt8ios_base4InitD1Ev, %edi
  346.         addq    $8, %rsp
  347.         .cfi_def_cfa_offset 8
  348.         jmp     __cxa_atexit
  349.         .cfi_endproc
  350. .LFE1240:
  351.         .size   _GLOBAL__sub_I_test_data, .-_GLOBAL__sub_I_test_data
  352.         .section        .init_array,"aw"
  353.         .align 8
  354.         .quad   _GLOBAL__sub_I_test_data
  355.         .globl  garbage
  356.         .bss
  357.         .align 16
  358.         .type   garbage, @object
  359.         .size   garbage, 8
  360. garbage:
  361.         .zero   8
  362.         .globl  test_data
  363.         .align 32
  364.         .type   test_data, @object
  365.         .size   test_data, 400000
  366. test_data:
  367.         .zero   400000
  368.         .local  _ZStL8__ioinit
  369.         .comm   _ZStL8__ioinit,1,1
  370.         .hidden __dso_handle
  371.         .ident  "GCC: (GNU) 4.8.3 20140911 (Red Hat 4.8.3-9)"
  372.         .section        .note.GNU-stack,"",@progbits
  373. [sdbc@erg0devprc01 test]$
复制代码


论坛徽章:
15
射手座
日期:2014-11-29 19:22:4915-16赛季CBA联赛之青岛
日期:2017-11-17 13:20:09黑曼巴
日期:2017-07-13 19:13:4715-16赛季CBA联赛之四川
日期:2017-02-07 21:08:572015年亚冠纪念徽章
日期:2015-11-06 12:31:58每日论坛发贴之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-07-12 22:20:002015亚冠之浦和红钻
日期:2015-07-08 10:10:132015亚冠之大阪钢巴
日期:2015-06-29 11:21:122015亚冠之广州恒大
日期:2015-05-22 21:55:412015年亚洲杯之伊朗
日期:2015-04-10 16:28:25
33 [报告]
发表于 2016-11-03 15:01 |只看该作者
windoze 发表于 2016-11-03 13:54
回复 30# yulihua49

怎么可能,你看我的代码不就用的是数组么……

这组函数的使用说明你能给我直接贴出来吗?

论坛徽章:
44
15-16赛季CBA联赛之浙江
日期:2021-10-11 02:03:59程序设计版块每日发帖之星
日期:2016-07-02 06:20:0015-16赛季CBA联赛之新疆
日期:2016-04-25 10:55:452016科比退役纪念章
日期:2016-04-23 00:51:2315-16赛季CBA联赛之山东
日期:2016-04-17 12:00:2815-16赛季CBA联赛之福建
日期:2016-04-12 15:21:2915-16赛季CBA联赛之辽宁
日期:2016-03-24 21:38:2715-16赛季CBA联赛之福建
日期:2016-03-18 12:13:4015-16赛季CBA联赛之佛山
日期:2016-02-05 00:55:2015-16赛季CBA联赛之佛山
日期:2016-02-04 21:11:3615-16赛季CBA联赛之天津
日期:2016-11-02 00:33:1215-16赛季CBA联赛之浙江
日期:2017-01-13 01:31:49
34 [报告]
发表于 2016-11-03 22:41 |只看该作者
本帖最后由 windoze 于 2016-11-03 22:45 编辑

回复 33# yulihua49

std::upper_bound的说明在这里:
http://en.cppreference.com/w/cpp/algorithm/upper_bound

简要的说一下,这个函数有两个重载:

  1. template< class ForwardIt, class T >
  2. ForwardIt upper_bound( ForwardIt first, ForwardIt last, const T& value );

  3. template< class ForwardIt, class T, class Compare >
  4. ForwardIt upper_bound( ForwardIt first, ForwardIt last, const T& value, Compare comp );
复制代码

第一个用std::less,第二个允许自定义compare。
[first, last)这个前闭后开区间定义了一个序列,这个函数会在这个序列里找到第一个比value大的元素,也就是满足comp(value, element)==true的元素。对于数组x[size],你可以用x和x+size。
这个函数用二分法查找,所以序列要求是由小到大排好序的。
Compare要求是可传递且不可逆的,对于任意abc,如果comp(a,b)==true且comp(b,c)==true,则comp(a,c)必须是true;
如果comp(a,b)==true,则comp(b,a)必须是false。
简单说就是Compare定义了一个partial order且对于每一次comp(x,y)调用都要保证a和b可比较。

因为这个函数是个template,所以很多东西在开了优化以后都会inline,而且在我的测试程序中comp是一个functor,所以也会inline,这样就会比较快了。

论坛徽章:
15
射手座
日期:2014-11-29 19:22:4915-16赛季CBA联赛之青岛
日期:2017-11-17 13:20:09黑曼巴
日期:2017-07-13 19:13:4715-16赛季CBA联赛之四川
日期:2017-02-07 21:08:572015年亚冠纪念徽章
日期:2015-11-06 12:31:58每日论坛发贴之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-07-12 22:20:002015亚冠之浦和红钻
日期:2015-07-08 10:10:132015亚冠之大阪钢巴
日期:2015-06-29 11:21:122015亚冠之广州恒大
日期:2015-05-22 21:55:412015年亚洲杯之伊朗
日期:2015-04-10 16:28:25
35 [报告]
发表于 2016-11-04 13:10 |只看该作者
本帖最后由 yulihua49 于 2016-11-04 13:44 编辑
windoze 发表于 2016-11-03 22:41
回复 33# yulihua49

std::upper_bound的说明在这里:

C++真的很神奇,服了。

这是我修改下,再做的测试。
其中Binary是调的库函数,完全不能inline。STL是inline的:
./stl_test
Binary Duration: 14619,N=79999
STL Duration: 5397,N=79999
[sdbc@erg0devprc01 test]$ ./stl_test
Binary Duration: 7352,N=79999
STL Duration: 12376,N=79999
[sdbc@erg0devprc01 test]$ ./stl_test
Binary Duration: 7420,N=79999
STL Duration: 5348,N=79999
[sdbc@erg0devprc01 test]$ ./stl_test
Binary Duration: 7638,N=79999
STL Duration: 19317,N=79999
[sdbc@erg0devprc01 test]$ ./stl_test
Binary Duration: 14582,N=79999
STL Duration: 5287,N=79999
[sdbc@erg0devprc01 test]$ ./stl_test
Binary Duration: 14591,N=79999
STL Duration: 5422,N=79999
[sdbc@erg0devprc01 test]$ ./stl_test
Binary Duration: 7420,N=79999
STL Duration: 12317,N=79999
[sdbc@erg0devprc01 test]$ ./stl_test
Binary Duration: 18667,N=79999
STL Duration: 5370,N=79999
[sdbc@erg0devprc01 test]$ ./stl_test
Binary Duration: 14392,N=79999
STL Duration: 5316,N=79999
[sdbc@erg0devprc01 test]$ ./stl_test
Binary Duration: 18378,N=79999
STL Duration: 5242,N=79999
[sdbc@erg0devprc01 test]$ ./stl_test
Binary Duration: 7375,N=79999
STL Duration: 5507,N=79999
[sdbc@erg0devprc01 test]$ ./stl_test
Binary Duration: 7531,N=79999
STL Duration: 12426,N=79999

在库函数里不知道数据类型,所以要在比较函数里要自己取下标数据,这个开销也很显著。STL因为知道数据类型,直接用寄存器进行数组寻址。
如果针对复杂数据结构数组,多字段组合KEY,估计它优势没那么高。
这是stl的汇编码:
  1. cat stl_a.s
  2.         .file   "stl_a.cpp"
  3.         .text
  4.         .p2align 4,,15
  5.         .globl  _Z5test2Pimi
  6.         .type   _Z5test2Pimi, @function
  7. _Z5test2Pimi:
  8. .LFB410:
  9.         .cfi_startproc
  10.         salq    $2, %rsi
  11.         movq    %rdi, %r9
  12.         sarq    $2, %rsi
  13. .L2:
  14.         testq   %rsi, %rsi
  15.         jle     .L5
  16.         movq    %rsi, %rax
  17.         sarq    %rax
  18.         leaq    (%rdi,%rax,4), %r8
  19.         cmpl    (%r8), %edx
  20.         jl      .L6
  21.         jmp     .L10
  22.         .p2align 4,,10
  23.         .p2align 3
  24. .L4:
  25.         movq    %rax, %rcx
  26.         sarq    %rcx
  27.         leaq    (%rdi,%rcx,4), %r8
  28.         cmpl    %edx, (%r8)
  29.         jle     .L3
  30.         movq    %rcx, %rax
  31. .L6:
  32.         testq   %rax, %rax
  33.         jne     .L4
  34. .L5:
  35.         subq    %r9, %rdi
  36.         sarq    $2, %rdi
  37.         leal    -1(%rdi), %eax
  38.         ret
  39. .L10:
  40.         movq    %rax, %rcx
  41.         movq    %rsi, %rax
  42.         .p2align 4,,10
  43.         .p2align 3
  44. .L3:
  45.         subq    %rcx, %rax
  46.         leaq    4(%r8), %rdi
  47.         leaq    -1(%rax), %rsi
  48.         jmp     .L2
  49.         .cfi_endproc
  50. .LFE410:
  51.         .size   _Z5test2Pimi, .-_Z5test2Pimi
  52.         .ident  "GCC: (GNU) 4.8.3 20140911 (Red Hat 4.8.3-9)"
  53.         .section        .note.GNU-stack,"",@progbits
复制代码

upper_bound是宏,根本没有作为一个函数出现。
一套复杂的下标计算和取数据操作,它一条指令解决了:
  leaq    (%rdi,%rcx,4), %r8

test1的汇编码,无法优化了:

  1.         .globl  _Z5test1Pimi
  2.         .type   _Z5test1Pimi, @function
  3. _Z5test1Pimi:
  4. .LFB1219:
  5.         .cfi_startproc
  6.         subq    $24, %rsp
  7.         .cfi_def_cfa_offset 32
  8.         movl    $_Z3cmpPvS_i, %ecx
  9.         movl    %edx, 12(%rsp)
  10.         movl    %esi, %edx
  11.         movq    %rdi, %rsi
  12.         leaq    12(%rsp), %rdi
  13.         call    upperBound
  14.         addq    $24, %rsp
  15.         .cfi_def_cfa_offset 8
  16.         subl    $1, %eax
  17.         ret
  18.         .cfi_endproc
  19. .LFE1219:
  20.         .size   _Z5test1Pimi, .-_Z5test1Pimi
复制代码





论坛徽章:
15
射手座
日期:2014-11-29 19:22:4915-16赛季CBA联赛之青岛
日期:2017-11-17 13:20:09黑曼巴
日期:2017-07-13 19:13:4715-16赛季CBA联赛之四川
日期:2017-02-07 21:08:572015年亚冠纪念徽章
日期:2015-11-06 12:31:58每日论坛发贴之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-07-12 22:20:002015亚冠之浦和红钻
日期:2015-07-08 10:10:132015亚冠之大阪钢巴
日期:2015-06-29 11:21:122015亚冠之广州恒大
日期:2015-05-22 21:55:412015年亚洲杯之伊朗
日期:2015-04-10 16:28:25
36 [报告]
发表于 2016-11-04 14:07 |只看该作者
yulihua49 发表于 2016-11-04 13:10
C++真的很神奇,服了。

这是我修改下,再做的测试。

  1.   /**
  2.    *  @brief Finds the last position in which @p __val could be inserted
  3.    *         without changing the ordering.
  4.    *  @ingroup binary_search_algorithms
  5.    *  @param  __first   An iterator.
  6.    *  @param  __last    Another iterator.
  7.    *  @param  __val     The search term.
  8.    *  @return  An iterator pointing to the first element greater than @p __val,
  9.    *           or end() if no elements are greater than @p __val.
  10.    *  @ingroup binary_search_algorithms
  11.   */
  12.   template<typename _ForwardIterator, typename _Tp>
  13.     _ForwardIterator
  14.     upper_bound(_ForwardIterator __first, _ForwardIterator __last,
  15.                 const _Tp& __val)
  16.     {
  17.       typedef typename iterator_traits<_ForwardIterator>::value_type
  18.         _ValueType;
  19.       typedef typename iterator_traits<_ForwardIterator>::difference_type
  20.         _DistanceType;

  21.       // concept requirements
  22.       __glibcxx_function_requires(_ForwardIteratorConcept<_ForwardIterator>)
  23.       __glibcxx_function_requires(_LessThanOpConcept<_Tp, _ValueType>)
  24.       __glibcxx_requires_partitioned_upper(__first, __last, __val);

  25.       _DistanceType __len = std::distance(__first, __last);

  26.       while (__len > 0)
  27.         {
  28.           _DistanceType __half = __len >> 1;
  29.           _ForwardIterator __middle = __first;
  30.           std::advance(__middle, __half);
  31.           if (__val < *__middle)
  32.             __len = __half;
  33.           else
  34.             {
  35.               __first = __middle;
  36.               ++__first;
  37.               __len = __len - __half - 1;
  38.             }
  39.         }
  40.       return __first;
  41.     }
  42.   /**
  43.    *  @brief Finds the last position in which @p __val could be inserted
  44.    *         without changing the ordering.
  45.    *  @ingroup binary_search_algorithms
  46.    *  @param  __first   An iterator.
  47.    *  @param  __last    Another iterator.
  48.    *  @param  __val     The search term.
  49.    *  @param  __comp    A functor to use for comparisons.
  50.    *  @return  An iterator pointing to the first element greater than @p __val,
  51.    *           or end() if no elements are greater than @p __val.
  52.    *  @ingroup binary_search_algorithms
  53.    *
  54.    *  The comparison function should have the same effects on ordering as
  55.    *  the function used for the initial sort.
  56.   */
  57.   template<typename _ForwardIterator, typename _Tp, typename _Compare>
  58.     _ForwardIterator
  59.     upper_bound(_ForwardIterator __first, _ForwardIterator __last,
  60.                 const _Tp& __val, _Compare __comp)
  61.     {
  62.       typedef typename iterator_traits<_ForwardIterator>::value_type
  63.         _ValueType;
  64.       typedef typename iterator_traits<_ForwardIterator>::difference_type
  65.         _DistanceType;

  66.       // concept requirements
  67.       __glibcxx_function_requires(_ForwardIteratorConcept<_ForwardIterator>)
  68.       __glibcxx_function_requires(_BinaryPredicateConcept<_Compare,
  69.                                   _Tp, _ValueType>)
  70.       __glibcxx_requires_partitioned_upper_pred(__first, __last,
  71.                                                 __val, __comp);

  72.       _DistanceType __len = std::distance(__first, __last);

  73.       while (__len > 0)
  74.         {
  75.           _DistanceType __half = __len >> 1;
  76.           _ForwardIterator __middle = __first;
  77.           std::advance(__middle, __half);
  78.           if (__comp(__val, *__middle))
  79.             __len = __half;
  80.           else
  81.             {
  82.               __first = __middle;
  83.               ++__first;
  84.               __len = __len - __half - 1;
  85.             }
  86.         }
  87.       return __first;
  88.     }
复制代码
找到了STL的源码,很神奇。

论坛徽章:
3
处女座
日期:2015-03-18 14:35:45羊年新春福章
日期:2015-03-18 14:48:23午马
日期:2015-03-18 14:51:09
37 [报告]
发表于 2016-11-04 17:31 |只看该作者
回复 21# yulihua49
像你那样的情况,我直接用红黑树了。


https://github.com/dongwencai/kernel_rbtree/blob/master/demo.c

论坛徽章:
3
处女座
日期:2015-03-18 14:35:45羊年新春福章
日期:2015-03-18 14:48:23午马
日期:2015-03-18 14:51:09
38 [报告]
发表于 2016-11-04 17:35 |只看该作者

论坛徽章:
36
子鼠
日期:2013-08-28 22:23:29黄金圣斗士
日期:2015-12-01 11:37:51程序设计版块每日发帖之星
日期:2015-12-14 06:20:00CU十四周年纪念徽章
日期:2015-12-22 16:50:40IT运维版块每日发帖之星
日期:2016-01-25 06:20:0015-16赛季CBA联赛之深圳
日期:2016-01-27 10:31:172016猴年福章徽章
日期:2016-02-18 15:30:3415-16赛季CBA联赛之福建
日期:2016-04-07 11:25:2215-16赛季CBA联赛之青岛
日期:2016-04-29 18:02:5915-16赛季CBA联赛之北控
日期:2016-06-20 17:38:50技术图书徽章
日期:2016-07-19 13:54:03程序设计版块每日发帖之星
日期:2016-08-21 06:20:00
39 [报告]
发表于 2016-11-04 21:15 |只看该作者
C++是未来高级智慧生命——机器人的基础,人类终将退出历史舞台被机器人取代lol

论坛徽章:
44
15-16赛季CBA联赛之浙江
日期:2021-10-11 02:03:59程序设计版块每日发帖之星
日期:2016-07-02 06:20:0015-16赛季CBA联赛之新疆
日期:2016-04-25 10:55:452016科比退役纪念章
日期:2016-04-23 00:51:2315-16赛季CBA联赛之山东
日期:2016-04-17 12:00:2815-16赛季CBA联赛之福建
日期:2016-04-12 15:21:2915-16赛季CBA联赛之辽宁
日期:2016-03-24 21:38:2715-16赛季CBA联赛之福建
日期:2016-03-18 12:13:4015-16赛季CBA联赛之佛山
日期:2016-02-05 00:55:2015-16赛季CBA联赛之佛山
日期:2016-02-04 21:11:3615-16赛季CBA联赛之天津
日期:2016-11-02 00:33:1215-16赛季CBA联赛之浙江
日期:2017-01-13 01:31:49
40 [报告]
发表于 2016-11-04 21:44 |只看该作者
本帖最后由 windoze 于 2016-11-04 21:47 编辑

回复 35# yulihua49

和C不同,C++是强类型语言,永远都知道数据的类型和尺寸,所以编译器永远都可以把下标或者结构体成员的访问直接优化成偏移量。


我一直建议用惯了C的人就把C++当做一个优化更好的C来用,什么虚函数继承多态之类OO相关的东西放在一边,只用C和template部分,这样心情好效率也高。基本算法STL里有一大堆: http://en.cppreference.com/w/cpp/header/algorithm ,都是些很常用而且自己写很容易出错的东西;容器也有一堆现成的,虽说list和map之类的东西可能效率略差,但是array和vector确实比原生数组方便多了。
等STL里的东西用熟了之后你就可以动手写自己的算法和容器了,像是KM/BMP或者B+Tree之类,写对了的话也比C快不少。

string和iostream一般在追求效率的地方应该尽量避免,这一块确实坑很多,不过说实话,关掉sync之后,iostream也比printf快。

唯一需要注意的地方就是所有template函数都要放在头文件里,编译时间也慢了很多。

另外C粉可以关注一下Rust,虽说这货现在坑依然不少,但是真的很有意思。



评分

参与人数 1信誉积分 +10 收起 理由
lxyscls + 10 赞一个!

查看全部评分

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

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP