fastest way to negate a number

后端 未结 7 1693
南旧
南旧 2020-12-29 03:20

I was thinking this morning here, what would be the fastest way to reverse a number of positive to negative and from negative to positive, of course, the simplest way might

相关标签:
7条回答
  • 2020-12-29 03:35

    With optimization disabled, gcc for x86 compiles the first to this asm:

        .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               # MinGW library init function
        movl    $10, 12(%esp) ;i = 10
        negl    12(%esp)      ;i = -i
        movl    $0, %eax
        leave
        ret
    

    With optimization disabled, the second one produces:

        .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
    

    Same output! No difference in the assembly code produced.

    --------------------------EDIT, OP ANSWERS HE USES VC++2012, INTEL ARCH-------------------

    Compiled using cl optimum.c /Fa optimum.asm (optimization disabled)

    ; 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
    

    and with second approach (a = a * -1), optimization disabled MSVC:

    ; 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
    

    So if you care about the performance of your debug-mode asm under MSVC, you could optimize your source accordingly. Normally you only care about performance in optimized builds.

    0 讨论(0)
  • 2020-12-29 03:35

    Also 0 - n

    Gcc emits the "neg" instruction for all four cases: -n, 0 - n, n * -1, and ~n + 1

    0 讨论(0)
  • 2020-12-29 03:38

    The other answers have correctly indicated that readability matters more:

    • You should forget about speed and choose the idiom that you find most readable.
    • Almost all compilers (with optimizations enabled) generate equivalent optimal code (probably a single instruction) for anything like a = -a, a *= -1 etc.1
    • Any attempt to make it faster will make it far less readable and could easily make it slower.
    • If you need to optimise, you should start by analysing generated code and performance.


    There is however a practical advantage to the *= -1 idiom: you only have to write the left hand side once, it is only evaluated once – and the reader only has to read it once! This is relevant when the LHS is long, complex or expensive or may have side-effects:

    (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;
    

    And once one has adopted an idiom, one tends to stick with it in other situations.


    1 Observations by Peter Cordes: Almost all compilers understand that a = -a and a *= -1 are exactly the same and will emit whatever asm they decide will be most efficient on the target CPU, regardless of how you write it. (e.g. Godbolt compiler explorer for x86 gcc/MSVC/clang, and ARM gcc.) But though MSVS 2012 (in debug mode only) uses one instruction for each, they take 1 cycle for = -a and 3 for *= -1 on recent Intel CPUs, using an actual imul instruction.

    0 讨论(0)
  • 2020-12-29 03:39

    You can try

    int a = 10;
    a= ~a+1;
    

    but you shouldn't worry about that, because compiler makes it in the best way.

    0 讨论(0)
  • 2020-12-29 03:45

    Use something that is readable, such as

    a *= -1;
    

    or

    a = -a;
    

    Leave the rest to the optimizer.

    0 讨论(0)
  • 2020-12-29 03:49

    Solution using high level language

    Questions like these are popular in interviews and competitive programming world .

    I landed here researching more solution for negation of a number without using - or + operator .

    For this :

    1. complement a number using ~ operator
    2. Then add 1 to the number obtained in step 1 using Half adder logic :
    > int addNumbers(int x, int y)
    >       {
    >                    if(y==0)  return x; // carry is 0 
    >                    return addNumbers(x^y,(x&y)<<1);
    >         }
    

    Here x^y performs addition of bits and x&y handles carry operation

    0 讨论(0)
提交回复
热议问题