Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/138.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 位移位效率_C++_Bit Manipulation - Fatal编程技术网

C++ 位移位效率

C++ 位移位效率,c++,bit-manipulation,C++,Bit Manipulation,短字节上的位移位(至少1个位置)比整数上的位移位(对于AMD64或x86体系结构)快吗(需要更少的CPU周期)?我怀疑答案是否定的,因为在这两种情况下都将使用相同的32位或64位CPU指令,并且这两种指令都将占用相同的时钟周期。这是真的吗?我之前发布的代码不正确。尽管代码包含移位,但由于结果未存储,编译器只是跳过了移位。下面是一个简单的int示例: void main() { int value = 0; value = value << 3; } void foo

短字节上的位移位(至少1个位置)比整数上的位移位(对于AMD64或x86体系结构)快吗(需要更少的CPU周期)?我怀疑答案是否定的,因为在这两种情况下都将使用相同的32位或64位CPU指令,并且这两种指令都将占用相同的时钟周期。这是真的吗?

我之前发布的代码不正确。尽管代码包含移位,但由于结果未存储,编译器只是跳过了移位。下面是一个简单的int示例:

void main() {
    int value = 0;
    value = value << 3;
}
void foo() {
    short value = 0;
    value = value << 3;
}
简短示例生成:

    .file   "main.c"
    .text
    .globl  _Z3foov
    .def    _Z3foov;    .scl    2;  .type   32; .endef
    .seh_proc   _Z3foov
_Z3foov:
.LFB0:
    pushq   %rbp
    .seh_pushreg    %rbp
    movq    %rsp, %rbp
    .seh_setframe   %rbp, 0
    subq    $16, %rsp
    .seh_stackalloc 16
    .seh_endprologue
    movl    $0, -4(%rbp)
    sall    $3, -4(%rbp)
    nop
    addq    $16, %rsp
    popq    %rbp
    ret
    .seh_endproc
    .ident  "GCC: (GNU) 5.4.0"
    .file   "main.c"
    .text
    .globl  _Z3foov
    .def    _Z3foov;    .scl    2;  .type   32; .endef
    .seh_proc   _Z3foov
_Z3foov:
.LFB0:
    pushq   %rbp
    .seh_pushreg    %rbp
    movq    %rsp, %rbp
    .seh_setframe   %rbp, 0
    subq    $16, %rsp
    .seh_stackalloc 16
    .seh_endprologue
    movw    $0, -2(%rbp)
    movswl  -2(%rbp), %eax
    sall    $3, %eax
    movw    %ax, -2(%rbp)
    nop
    addq    $16, %rsp
    popq    %rbp
    ret
    .seh_endproc
    .ident  "GCC: (GNU) 5.4.0"
简短的示例执行:

movw    $0, -2(%rbp)
movswl  -2(%rbp), %eax
sall    $3, %eax
movw    %ax, -2(%rbp)
movl    $0, -4(%rbp)
sall    $3, -4(%rbp)
整数示例执行:

movw    $0, -2(%rbp)
movswl  -2(%rbp), %eax
sall    $3, %eax
movw    %ax, -2(%rbp)
movl    $0, -4(%rbp)
sall    $3, -4(%rbp)

因此,在没有任何编译器优化的情况下,整数移位实际上更快。

我之前发布的代码不正确。尽管代码包含移位,但由于结果未存储,编译器只是跳过了移位。下面是一个简单的int示例:

void main() {
    int value = 0;
    value = value << 3;
}
void foo() {
    short value = 0;
    value = value << 3;
}
简短示例生成:

    .file   "main.c"
    .text
    .globl  _Z3foov
    .def    _Z3foov;    .scl    2;  .type   32; .endef
    .seh_proc   _Z3foov
_Z3foov:
.LFB0:
    pushq   %rbp
    .seh_pushreg    %rbp
    movq    %rsp, %rbp
    .seh_setframe   %rbp, 0
    subq    $16, %rsp
    .seh_stackalloc 16
    .seh_endprologue
    movl    $0, -4(%rbp)
    sall    $3, -4(%rbp)
    nop
    addq    $16, %rsp
    popq    %rbp
    ret
    .seh_endproc
    .ident  "GCC: (GNU) 5.4.0"
    .file   "main.c"
    .text
    .globl  _Z3foov
    .def    _Z3foov;    .scl    2;  .type   32; .endef
    .seh_proc   _Z3foov
_Z3foov:
.LFB0:
    pushq   %rbp
    .seh_pushreg    %rbp
    movq    %rsp, %rbp
    .seh_setframe   %rbp, 0
    subq    $16, %rsp
    .seh_stackalloc 16
    .seh_endprologue
    movw    $0, -2(%rbp)
    movswl  -2(%rbp), %eax
    sall    $3, %eax
    movw    %ax, -2(%rbp)
    nop
    addq    $16, %rsp
    popq    %rbp
    ret
    .seh_endproc
    .ident  "GCC: (GNU) 5.4.0"
简短的示例执行:

movw    $0, -2(%rbp)
movswl  -2(%rbp), %eax
sall    $3, %eax
movw    %ax, -2(%rbp)
movl    $0, -4(%rbp)
sall    $3, -4(%rbp)
整数示例执行:

movw    $0, -2(%rbp)
movswl  -2(%rbp), %eax
sall    $3, %eax
movw    %ax, -2(%rbp)
movl    $0, -4(%rbp)
sall    $3, -4(%rbp)

因此,在没有任何编译器优化的情况下,整数移位实际上更快。

视情况而定。一般来说,如果您有一个N位处理器,那么最有可能的是,任何高达N位的数据都需要相同的时间进行移位,较大的变量需要更长的时间。如果要对字节执行操作,但要确保使用大小合适的整数来提高速度,请使用类型
uint\u fast8\t

但是:如果在循环中进行位移位,那么编译器可能能够对代码进行矢量化。如果处理器带有SSE2指令,它可以在一条指令中执行8个16位移位。如果您有AVX甚至AVX512,那么它可以在一条指令中执行16位甚至32位16位移位。然而,这是否比使用常规指令更有效,取决于将许多变量加载到SSE寄存器中的容易程度,以及您是否对它们进行了更多的操作,而不仅仅是位移位

查看编译器的汇编程序输出很有帮助(例如,使用
gcc-save temps
编译程序并查看生成的
.s
文件)。请注意,选择的优化级别对生成的汇编程序有很大影响


确定最快变量大小的最佳方法就是测量它。

这取决于它。一般来说,如果您有一个N位处理器,那么最有可能的是,任何高达N位的数据都需要相同的时间进行移位,较大的变量需要更长的时间。如果要对字节执行操作,但要确保使用大小合适的整数来提高速度,请使用类型
uint\u fast8\t

但是:如果在循环中进行位移位,那么编译器可能能够对代码进行矢量化。如果处理器带有SSE2指令,它可以在一条指令中执行8个16位移位。如果您有AVX甚至AVX512,那么它可以在一条指令中执行16位甚至32位16位移位。然而,这是否比使用常规指令更有效,取决于将许多变量加载到SSE寄存器中的容易程度,以及您是否对它们进行了更多的操作,而不仅仅是位移位

查看编译器的汇编程序输出很有帮助(例如,使用
gcc-save temps
编译程序并查看生成的
.s
文件)。请注意,选择的优化级别对生成的汇编程序有很大影响


确定最快变量大小的最佳方法就是测量它。

我的假设是8位或16位(无符号)整数上的移位与32位字机上32位量上的移位相同

大多数32位字大小处理器在内部以32位数量运行。桶形移位器、算术单元等设计用于32位操作。数据获取机制将在移位操作发生之前将8位或16位数量转换为32位数量。32位的数量不需要任何调整,所以较小的整数可能会有轻微的延迟

另一方面,可能有处理器具有8位或16位大小整数的特殊数据路径

验证的方法是在您的系统和其他目标系统上配置文件


另外,问问自己执行时间差是重要还是重要。

我的假设是,8位或16位(无符号)整数上的移位与32位字机上32位量上的移位相同

大多数32位字大小处理器在内部以32位数量运行。桶形移位器、算术单元等设计用于32位操作。数据获取机制将在移位操作发生之前将8位或16位数量转换为32位数量。32位的数量不需要任何调整,所以较小的整数可能会有轻微的延迟

另一方面,可能有处理器具有8位或16位大小整数的特殊数据路径

验证的方法是在您的系统和其他目标系统上配置文件


另外,问问自己执行时间差是重要还是重要。

硬件上的基准测试说明了什么?为您的用例发出了什么机器代码?这里的最佳选择是对正确表示您的问题的示例进行基准测试。有许多问题与单个指令所消耗的周期无关,这些周期可以加速或减慢程序(加载/存储、simd等)。短字节上的位移位(至少1个位置)比整数上的位移位(对于AMD64或x86体系结构)快还是快(需要更少的CPU周期)?不。你的问题的答案是否定的,32位x86 CPU将字节/短字节存储为32位变量,但考虑到现代CPU上使用管道的一条指令性能,超标量和推测执行没有任何意义。硬件上的基准测试说明了什么?发出什么机器代码供您使用