问题
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 be:
int a = 10;
a = a*(-1);
or
int a = 10;
a = -a;
But then, I thought, I take that to do this, using commands shift and pointers ... That really would be possible to change the sign of a value, using commands shift operators and memory?
回答1:
The first 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
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
; 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)
; 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
回答2:
Use something that is readable, such as
a *= -1;
or
a = -a;
Leave the rest to the optimizer.
回答3:
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) understand that
a = -a
anda *= -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 actualimul
instruction.
- But though MSVS 2012 (in debug mode only) uses one instruction for each, they take 1 cycle for
- 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.
回答4:
Assuming the processor is at least somewhat competent and has sizeof(int) == sizeof(Cpu_register)
, then a "make this number negative" will be a single instruction (usually called neg
) [well, may need the value loading and storing too, but if you are using the variable for anything else, it can remain after the load, and only be stored later one...]
Multiplying by -1
is most likely slower than a = -a;
, but most competent compilers should be able to make both of these equivalent.
So, just write the code clearly, and the rest should take care of itself. Negating a number is not a difficult operation in most processors. If you are using some unusual processsor, then look at the compiler output, and see what it does.
回答5:
Also 0 - n
Gcc emits the "neg" instruction for all four cases: -n, 0 - n, n * -1, and ~n + 1
回答6:
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 :
- complement a number using ~ operator
- 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
回答7:
You can try
int a = 10;
a= ~a+1;
but you shouldn't worry about that, because compiler makes it in the best way.
来源:https://stackoverflow.com/questions/15111466/fastest-way-to-negate-a-number