Reputation: 2025
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?
Upvotes: 45
Views: 104522
Reputation: 25695
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.
Upvotes: 28
Reputation: 1420
The other answers have correctly indicated that readability matters more:
a = -a
, a *= -1
etc.1
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.
Upvotes: 13
Reputation: 2742
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 :
> 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
Upvotes: 1
Reputation: 314
Also 0 - n
Gcc emits the "neg" instruction for all four cases: -n, 0 - n, n * -1, and ~n + 1
Upvotes: 6
Reputation: 129314
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.
Upvotes: 4
Reputation: 43
You can try
int a = 10;
a= ~a+1;
but you shouldn't worry about that, because compiler makes it in the best way.
Upvotes: 0
Reputation: 132974
Use something that is readable, such as
a *= -1;
or
a = -a;
Leave the rest to the optimizer.
Upvotes: 52