为什么减去比mod慢?

时间:2022-06-13 21:20:13

in that specific case

在那个特定的情况下

    Const debugTime As String = "hh:mm:ss.fffffff"
    Dim i As Integer

    Debug.Print("Start " & Now.ToString(debugTime))
    For i = 0 To 4000000
        j = 5 - 4
    Next
    Debug.Print("End " & Now.ToString(debugTime))

    Debug.Print("Start " & Now.ToString(debugTime))
    For i = 0 To 4000000
        j = 5 Mod 4
    Next
    Debug.Print("End " & Now.ToString(debugTime))

result

Start 05:33:39.8281250

End 05:33:39.8437500

Start 05:33:39.8437500

End 05:33:39.8437500

* EDIT *

*编辑*

modified the code to make it look like that

修改了代码使其看起来像那样

    Const debugTime As String = "hh:mm:ss.fffffff"
    Dim i As Long, j As Integer
    Dim r As Random

    r = New Random(1)
    Debug.Print("Start " & Now.ToString(debugTime))
    For i = 0 To 400000000
        j = 5 - r.Next(1, 5)
    Next
    Debug.Print("End " & Now.ToString(debugTime))

    r = New Random(1)
    Debug.Print("Start " & Now.ToString(debugTime))
    For i = 0 To 400000000
        j = 5 Mod r.Next(1, 5)
    Next
    Debug.Print("End " & Now.ToString(debugTime))

now the minus is faster...

现在减去更快......

Start 05:49:25.0156250

End 05:49:35.7031250

Start 05:49:35.7031250

End 05:49:48.2187500

3 个解决方案

#1


  • Benchmarking with such tiny time intervals leaves you wide open to problems of timer granularity, which is what you're seeing here.
  • 使用如此微小的时间间隔进行基准测试可以让您对计时器粒度问题持开放态度,这就是您在此处所看到的。

  • Your code doesn't actually calculate anything, as you've got a constant both times.
  • 你的代码实际上并没有计算任何东西,因为你两次都有一个常数。

In fact, benchmarking operations this small is quite tricky - to make sure neither the compiler nor the JIT compiler optimise things away, you really want to make it use the result somehow, but that will affect the results quite significantly.

实际上,这个小的基准测试操作非常棘手 - 为了确保编译器和JIT编译器都没有优化,你真的想让它以某种方式使用结果,但这会非常显着地影响结果。

#2


The compiler will optimize both of them to an assignment. The very small difference is probably a result of another factor.

编译器会将它们优化为赋值。很小的差异可能是另一个因素的结果。

UPDATE: I wrote a benchmark on Mac OS X, Intel 64 architecture. Huge difference:

更新:我在Mac OS X,Intel 64架构上写了一个基准。巨大的差异:

a.asm: assemble with yasm -f macho64 a.asm

a.asm:用yasm -f macho64 a.asm组装

SECTION .text
global _bmod, _bmin
_bmod:  push rdx
    push rbx
    mov rcx, 1000000000
    mov rdi, 5
    mov rsi, 4
.bmod:  mov rax, rdi
    mov rbx, rsi
    xor rdx, rdx
    div rbx             ; div instruction stores the mod in rdx.
    dec rcx
    jnz .bmod
    pop rbx
    pop rdx
    ret

_bmin:  push rdx
    push rbx
    mov rcx, 1000000000
    mov rdi, 5
    mov rsi, 4
.bmin:  mov rax, rdi
    mov rbx, rsi
    sub rax, rbx
    dec rcx
    jnz .bmin
    pop rbx
    pop rdx
    ret

a.c: compile with gcc -m64 a.c a.o

a.c:使用gcc -m64 a.c a.o编译

#include <time.h>
#include <stdio.h>

void bmod();
void bmin();

main() {
    time_t timex,timex2;
    time(&timex);
    bmod();
    time(&timex2);
    printf("Mod: %d\n", timex2 - timex);
    time(&timex);
    bmin();
    time(&timex2);
    printf("Min: %d\n", timex2 - timex);
}

Result when I ran it on my MacBook Air:

我在MacBook Air上运行时的结果:

Mehrdad-Air:~ Mehrdad$ yasm -f macho64 a.asm 
Mehrdad-Air:~ Mehrdad$ gcc -m64 -O0 a.c a.o
Mehrdad-Air:~ Mehrdad$ ./a.out 
Mod: 14
Min: 2

As you can see, modulus is about an order of magnitude slower than subtraction.

如您所见,模数比减法慢一个数量级。

#3


Further to what Jon Skeet says, I usually use the System.Diagnostics.Stopwatch() for benchmarking as I've found that the high speed counter tends to be slightly more reliable than just referencing DateTime.Now

除了Jon Skeet所说的,我通常使用System.Diagnostics.Stopwatch()进行基准测试,因为我发现高速计数器比仅仅引用DateTime更可靠。

  Dim t = new System.Diagnostics.Stopwatch()
  t.Start

  ''Do Stuff...

  Debug.Print(t.Elapsed)
  t.Stop

Edit: (Or per Jon's suggestion in the comments:

编辑:(或根据Jon在评论中的建议:

  Dim t = System.Diagnostics.Stopwatch.StartNew

  ''Do Stuff...

  Debug.Print(t.Elapsed)
  t.Stop

)

#1


  • Benchmarking with such tiny time intervals leaves you wide open to problems of timer granularity, which is what you're seeing here.
  • 使用如此微小的时间间隔进行基准测试可以让您对计时器粒度问题持开放态度,这就是您在此处所看到的。

  • Your code doesn't actually calculate anything, as you've got a constant both times.
  • 你的代码实际上并没有计算任何东西,因为你两次都有一个常数。

In fact, benchmarking operations this small is quite tricky - to make sure neither the compiler nor the JIT compiler optimise things away, you really want to make it use the result somehow, but that will affect the results quite significantly.

实际上,这个小的基准测试操作非常棘手 - 为了确保编译器和JIT编译器都没有优化,你真的想让它以某种方式使用结果,但这会非常显着地影响结果。

#2


The compiler will optimize both of them to an assignment. The very small difference is probably a result of another factor.

编译器会将它们优化为赋值。很小的差异可能是另一个因素的结果。

UPDATE: I wrote a benchmark on Mac OS X, Intel 64 architecture. Huge difference:

更新:我在Mac OS X,Intel 64架构上写了一个基准。巨大的差异:

a.asm: assemble with yasm -f macho64 a.asm

a.asm:用yasm -f macho64 a.asm组装

SECTION .text
global _bmod, _bmin
_bmod:  push rdx
    push rbx
    mov rcx, 1000000000
    mov rdi, 5
    mov rsi, 4
.bmod:  mov rax, rdi
    mov rbx, rsi
    xor rdx, rdx
    div rbx             ; div instruction stores the mod in rdx.
    dec rcx
    jnz .bmod
    pop rbx
    pop rdx
    ret

_bmin:  push rdx
    push rbx
    mov rcx, 1000000000
    mov rdi, 5
    mov rsi, 4
.bmin:  mov rax, rdi
    mov rbx, rsi
    sub rax, rbx
    dec rcx
    jnz .bmin
    pop rbx
    pop rdx
    ret

a.c: compile with gcc -m64 a.c a.o

a.c:使用gcc -m64 a.c a.o编译

#include <time.h>
#include <stdio.h>

void bmod();
void bmin();

main() {
    time_t timex,timex2;
    time(&timex);
    bmod();
    time(&timex2);
    printf("Mod: %d\n", timex2 - timex);
    time(&timex);
    bmin();
    time(&timex2);
    printf("Min: %d\n", timex2 - timex);
}

Result when I ran it on my MacBook Air:

我在MacBook Air上运行时的结果:

Mehrdad-Air:~ Mehrdad$ yasm -f macho64 a.asm 
Mehrdad-Air:~ Mehrdad$ gcc -m64 -O0 a.c a.o
Mehrdad-Air:~ Mehrdad$ ./a.out 
Mod: 14
Min: 2

As you can see, modulus is about an order of magnitude slower than subtraction.

如您所见,模数比减法慢一个数量级。

#3


Further to what Jon Skeet says, I usually use the System.Diagnostics.Stopwatch() for benchmarking as I've found that the high speed counter tends to be slightly more reliable than just referencing DateTime.Now

除了Jon Skeet所说的,我通常使用System.Diagnostics.Stopwatch()进行基准测试,因为我发现高速计数器比仅仅引用DateTime更可靠。

  Dim t = new System.Diagnostics.Stopwatch()
  t.Start

  ''Do Stuff...

  Debug.Print(t.Elapsed)
  t.Stop

Edit: (Or per Jon's suggestion in the comments:

编辑:(或根据Jon在评论中的建议:

  Dim t = System.Diagnostics.Stopwatch.StartNew

  ''Do Stuff...

  Debug.Print(t.Elapsed)
  t.Stop

)