否定数字的最快方法

Ale*_*dre 33 c c++ intel visual-c++-2012

我今天早上在这里思考,最好的方法是将一些积极转为负面,从消极转为正面,当然,最简单的方法可能是:

int a = 10;
a = a*(-1);
Run Code Online (Sandbox Code Playgroud)

要么

int a = 10;
a = -a;
Run Code Online (Sandbox Code Playgroud)

但是,我想,我接着这样做,使用命令shift和指针......真的可以使用命令移位运算符和内存来改变值的符号吗?

Arm*_*yan 39

使用可读的东西,例如

a *= -1;
Run Code Online (Sandbox Code Playgroud)

要么

a = -a;
Run Code Online (Sandbox Code Playgroud)

将剩下的部分留给优化器.


Ani*_*nge 23

第一个产生:

    .file   "optimum.c"
    .def    ___main;    .scl    2;  .type   32; .endef
    .text
.globl _main
    .def    _main;  .scl    2;  .type   32; .endef
_main:
    pushl   %ebp
    movl    %esp, %ebp
    andl    $-16, %esp
    subl    $16, %esp
    call    ___main
    movl    $10, 12(%esp) ;i = 10
    negl    12(%esp)      ;i = -i
    movl    $0, %eax
    leave
    ret
Run Code Online (Sandbox Code Playgroud)

第二个产生:

    .file   "optimum.c"
    .def    ___main;    .scl    2;  .type   32; .endef
    .text
.globl _main
    .def    _main;  .scl    2;  .type   32; .endef
_main:
    pushl   %ebp
    movl    %esp, %ebp
    andl    $-16, %esp
    subl    $16, %esp
    call    ___main
    movl    $10, 12(%esp)   ;i = 10
    negl    12(%esp)        ;i = -i
    movl    $0, %eax
    leave
    ret
Run Code Online (Sandbox Code Playgroud)

相同的输出!生成的汇编代码没有区别.

--------------------------编辑,OP回答他使用VC++ 2012,INTEL ARCH ----------- --------

编译使用 cl optimum.c /Fa optimum.asm

; Listing generated by Microsoft (R) Optimizing Compiler Version 16.00.30319.01 

    TITLE   C:\Users\Dell\Downloads\TTH\TTH\TTH\optimum.c
    .686P
    .XMM
    include listing.inc
    .model  flat

INCLUDELIB LIBCMT
INCLUDELIB OLDNAMES

PUBLIC  _main
; Function compile flags: /Odtp
_TEXT   SEGMENT
_a$ = -4                        ; size = 4
_argc$ = 8                      ; size = 4
_argv$ = 12                     ; size = 4
_main   PROC
; File c:\users\dell\downloads\tth\tth\tth\optimum.c
; Line 4
    push    ebp
    mov ebp, esp
    push    ecx
; Line 5
    mov DWORD PTR _a$[ebp], 10          ; 0000000aH
; Line 6
    mov eax, DWORD PTR _a$[ebp]
    neg eax ;1 machine cycle!
    mov DWORD PTR _a$[ebp], eax
; Line 7
    xor eax, eax
; Line 8
    mov esp, ebp
    pop ebp
    ret 0
_main   ENDP
_TEXT   ENDS
END
Run Code Online (Sandbox Code Playgroud)

并采用第二种方法(a = a*-1)

; Listing generated by Microsoft (R) Optimizing Compiler Version 16.00.30319.01 

    TITLE   C:\Users\Dell\Downloads\TTH\TTH\TTH\optimum.c
    .686P
    .XMM
    include listing.inc
    .model  flat

INCLUDELIB LIBCMT
INCLUDELIB OLDNAMES

PUBLIC  _main
; Function compile flags: /Odtp
_TEXT   SEGMENT
_a$ = -4                        ; size = 4
_argc$ = 8                      ; size = 4
_argv$ = 12                     ; size = 4
_main   PROC
; File c:\users\dell\downloads\tth\tth\tth\optimum.c
; Line 4
    push    ebp
    mov ebp, esp
    push    ecx
; Line 5
    mov DWORD PTR _a$[ebp], 10          ; 0000000aH
; Line 6
    mov eax, DWORD PTR _a$[ebp]
    imul    eax, -1 ;1 instruction, 3 machine/cycles :|
    mov DWORD PTR _a$[ebp], eax
; Line 7
    xor eax, eax
; Line 8
    mov esp, ebp
    pop ebp
    ret 0
_main   ENDP
_TEXT   ENDS
END
Run Code Online (Sandbox Code Playgroud)

  • @MrLister任何体面的自尊编译器都会产生相同(相似)的代码. (7认同)
  • 关键是:不要猜测,不要假设,不要读心:) 问题一般是关于 C 或 C++。但实际上,除非您对特定 CPU 有深入的了解,否则尝试手动优化根本没有任何意义。99% 的程序员并不比为特定 CPU 编写编译器端口的人更了解这些事情。 (2认同)

PJT*_*ill 7

其他答案正确表明可读性更重要:

  • 你应该忘记速度并选择你认为最具可读性的成语.
  • 几乎所有编译器(启用了优化)都能理解a = -aa *= -1完全相同,并且无论你如何编写它们,它们都会发出他们认为在目标CPU上最有效的任何asm.(例如,用于x86 gcc/MSVC/clang和ARM gcc的Godbolt编译器资源管理器.)
    • 但是虽然MSVS 2012(仅在调试模式下)每个都使用一条指令,但是使用实际指令,它们需要1个周期= -a,3个用于*= -1最近的Intel CPU imul.
  • 任何使它更快的尝试都会使它的可读性降低,并且很容易使它变慢.
  • 如果需要优化,则应首先分析生成的代码和性能.


然而,这个成语有一个实际的优点*= -1:你只需要写一次左手边,它只被评估一次 - 读者只需要读一次!当LHS长,复杂或昂贵或可能有副作用时,这是相关的:

(valid ? a : b)[prime_after(i++)] *= -1;
*look_up (input) *= -1;  // Where look_up may have side-effects
parity[state][(unsigned int)getc(stdin)] *= -1;
variable_with_a_long_explanatory_name *= -1;
Run Code Online (Sandbox Code Playgroud)

一旦采用了成语,人们就会在其他情况下坚持使用.


Jer*_*emy 5

还有 0 - n

Gcc 针对所有四种情况发出“neg”指令:-n、0 - n、n * -1 和 ~n + 1