C++ 否定一个数字的最快方法
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/15111466/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
fastest way to negate a number
提问by Alexandre
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?
但是,然后,我想,我会这样做,使用命令移位和指针......使用命令移位运算符和内存真的可以改变值的符号吗?
采纳答案by Aniket Inge
With optimization disabled, gcc for x86 compiles the first to this asm:
禁用优化后,x86 的 gcc 将第一个编译为这个 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 , %esp
call ___main # MinGW library init function
movl , 12(%esp) ;i = 10
negl 12(%esp) ;i = -i
movl .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 , %esp
call ___main
movl , 12(%esp) ;i = 10
negl 12(%esp) ;i = -i
movl ; 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
, %eax
leave
ret
, %eax
leave
ret
With optimization disabled, the second one produces:
禁用优化后,第二个产生:
; 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
Same output! No difference in the assembly code produced.
一样的输出!生成的汇编代码没有区别。
--------------------------EDIT, OP ANSWERS HE USES VC++2012, INTEL ARCH-------------------
--------------------------编辑,OP 答案他使用 VC++2012,INTEL ARCH ----------- --------
Compiled using cl optimum.c /Fa optimum.asm
(optimization disabled)
编译使用cl optimum.c /Fa optimum.asm
(禁用优化)
a *= -1;
and with second approach (a = a * -1
), optimization disabled MSVC:
使用第二种方法 ( a = a * -1
),优化禁用了 MSVC:
a = -a;
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.
因此,如果您关心 MSVC 下调试模式 asm 的性能,则可以相应地优化源代码。通常,您只关心优化构建中的性能。
回答by Armen Tsirunyan
Use something that is readable, such as
使用可读的东西,例如
(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;
or
或者
> int addNumbers(int x, int y)
> {
> if(y==0) return x; // carry is 0
> return addNumbers(x^y,(x&y)<<1);
> }
Leave the rest to the optimizer.
剩下的交给优化器。
回答by PJTraill
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.
- 您应该忘记速度并选择您认为最易读的习语。
- 几乎所有的编译器(启用了优化)产生像任何等价最佳代码(可能是一个单指令)
a = -a
,a *= -1
等1 - 任何使其更快的尝试都会使其可读性大大降低,并且很容易使其变慢。
- 如果你需要优化,你应该从分析生成的代码和性能开始。
There is however a practical advantageto 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:
然而,这个习语有一个实际的优势*= -1
:你只需要写一次左边,它只被评估一次——而读者只需要阅读一次!当 LHS 时间长、复杂或昂贵或可能有副作用时,这是相关的:
> int addNumbers(int x, int y)
> {
> if(y==0) return x; // carry is 0
> return addNumbers(x^y,(x&y)<<1);
> }
And once one has adopted an idiom, one tends to stick with it in other situations.
一旦采用了一种习语,人们往往会在其他情况下坚持使用它。
1Observations 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 explorerfor 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.
1 Peter Cordes 的观察:几乎所有的编译器都理解这一点a = -a
,a *= -1
并且完全相同,并且会发出他们认为在目标 CPU 上最有效的任何 asm,无论您如何编写它。(例如,用于 x86 gcc/MSVC/clang 和 ARM gcc 的Godbolt 编译器资源管理器。)但是,尽管 MSVS 2012(仅在调试模式下)为每个指令使用一条指令,但它们在最近的 Intel CPU 上需要 1 个周期= -a
和 3个周期*= -1
,使用实际imul
操作说明。
回答by Mats Petersson
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...]
假设处理器至少在某种程度上有能力并且有sizeof(int) == sizeof(Cpu_register)
,那么“使这个数字为负”将是一条指令(通常称为neg
)[好吧,可能也需要加载和存储值,但如果您将变量用于其他任何事情,它可以在加载后保留,并且只能在以后存储一个...]
Multiplying by -1
is most likely slower than a = -a;
, but most competent compilers should be able to make both of these equivalent.
乘法-1
很可能比 慢a = -a;
,但大多数有能力的编译器应该能够使这两者等效。
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.
所以,只要把代码写清楚,剩下的就自己处理好了。在大多数处理器中,否定一个数字并不是一个困难的操作。如果您正在使用一些不寻常的处理器,请查看编译器输出,看看它做了什么。
回答by Jeremy
Also 0 - n
还有 0 - n
Gcc emits the "neg" instruction for all four cases: -n, 0 - n, n * -1, and ~n + 1
Gcc 为所有四种情况发出“neg”指令:-n、0 - n、n * -1 和 ~n + 1
回答by Divyanshu Jimmy
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 :
- 使用 ~ 运算符补充一个数字
- 然后使用半加法器逻辑将步骤 1 中获得的数字加 1:
int a = 10; a= ~a+1;
##代码##
Here x^y performs addition of bits and x&y handles carry operation
这里 x^y 执行位相加,x&y 处理进位操作
回答by Alexander
You can try
你可以试试
##代码##but you shouldn't worry about that, because compiler makes it in the best way.
但是您不必担心,因为编译器以最好的方式做到了这一点。