我今天早上在这里思考,最好的方法是将一些积极转为负面,从消极转为正面,当然,最简单的方法可能是:
int a = 10;
a = a*(-1);
或
int a = 10;
a = -a;
然而,我想,我接着这样做,使用命令shift和指针...... 真的可以使用命令移位运算符和内存来改变值的符号吗?
答案 0 :(得分:37)
使用可读的内容,例如
a *= -1;
或
a = -a;
将其余部分留给优化器。
答案 1 :(得分:22)
第一个产生:
.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
第二个产生:
.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
相同的输出!生成的汇编代码没有区别。
--------------------------编辑,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
并采用第二种方法(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 :(得分:6)
其他答案已正确表明可读性更重要:
a = -a
和a *= -1
完全相同,并且会发出他们认为在目标CPU上最有效的任何asm,无论你如何编写它。 (例如Godbolt compiler explorer表示x86 gcc / MSVC / clang和ARM gcc。)
= -a
和*= -1
需要1个周期,使用实际的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;
一旦采用了成语,人们就会在其他情况下坚持使用。
答案 3 :(得分:3)
假设处理器至少有一定程度并且有sizeof(int) == sizeof(Cpu_register)
,那么“使这个数字为负数”将是一条指令(通常称为neg
)[嗯,可能需要加载值和存储也是如此,但是如果你将变量用于其他任何东西,它可以在加载后保留,并且只能在以后存储...]
乘以-1
最有可能慢于a = -a;
,但大多数称职的编制者应该能够使这两者等效。
所以,只要清楚地编写代码,其余的就应该自己处理。在大多数处理器中,否定数字并不困难。如果你正在使用一些不寻常的过程,那么看看编译器输出,看看它做了什么。
答案 4 :(得分:3)
也是0 - n
Gcc为所有四种情况发出“neg”指令:-n,0-n,n * -1和~n + 1
答案 5 :(得分:1)
使用高级语言的解决方案
这些问题在采访和竞争性编程领域很受欢迎。
我在这里找到了更多的解决方案来研究否定数字而不使用 - 或+运算符。
为此:
> int addNumbers(int x, int y) > { > if(y==0) return x; // carry is 0 > return addNumbers(x^y,(x&y)<<1); > }
这里x ^ y执行位的添加和x&amp; y句柄进位操作
答案 6 :(得分:-2)
你可以尝试
int a = 10;
a= ~a+1;
但你不应该担心,因为编译器以最好的方式使它。