The pits that have been trampled in C + + (appendix I)
Liu Junyan (Alinshans)This series of articles is aimed at the various pits I've stepped into when I write C + + code, especially when I'm doing my own project. Take this as a warning to yourself.
"Copyright notice" reproduced please specify the original from: Http://www.cnblogs.com/GodA/p/6639526.html
It was just last month that I began to write, and it was not so much until now. Maybe some kids don't know the cause of writing this essay, so you can look at what I wrote earlier.
At the end of the previous article, I mentioned a problem: code optimization. and left a small test: the performance comparison of unsigned numbers and signed numbers. I wonder if anyone is going to experiment. I made a simple test:
#include <iostream>#include<chrono>intMain () {/*unsigned*/intA =123456789; Auto T1=Std::chrono::system_clock::now (); for(inti =0; I < -; ++i) {a+=3; A-=5; A*=7; A/=7; } Auto T2=Std::chrono::system_clock::now (); Auto Runtime= Std::chrono::d uration_cast<std::chrono::nanoseconds> (T2-t1); Std::cout<<"A ="<< a <<"\ n"; Std::cout<< Runtime.count () <<"NS";}
The above code is run in the Debug mode of VS (release is optimized), stable run time at 2800ns, and then remove the comments, run again, stable after running time or 2800ns. On my computer, there is almost no difference between calculating signed and unsigned types, and I believe the same result is true on most computers.
Similarly, the calculation of floating-point numbers is slower than the integer number? For this question, you can look at this question:https://www.zhihu.com/question/26494062.
First I would like to state: I am not against code optimization. For a lot of so-called optimization techniques, I think we should be learning to explore the mentality, rather than blindly pursue some meaningless things. Some optimizations are really subtle. But many of the so-called tricks seem to mean that the people who make the compiler are idiots. It's a normal and supposed idea to optimize our program, but we should use scientific methods rather than listening to some kinky tricks, but we don't know what's going on inside.
Actually very simple, explore performance bottleneck by profiling, explore the code behind the unknown story to see Assembly. Let's start with one of the latter.
I think most people are still programming under Windows, so it's definitely the strongest IDE VS in the universe. It's easy to see the assembly in VS, just set a breakpoint, then press Debug to start debugging, and then open the Debugger window to find the disassembly, and you can see it. For example, we study signed numbers and unsigned numbers, and write a program first:
int Main () { /**/int123456789; - ; << A;}
Then follow the new method ( under Debug ) to see the disassembly:
/*unsigned * *intA =123456789;00b4104e movDWORD ptr [a],75bcd15h a = A/ -;00b41055 movEax,dword ptr [a]00b41058 CDQ 00b41059 movECX,0DH00b4105e Idiveax,ecx00b41060 movDWORD ptr [A],eax
Then try to remove the comment:
UnsignedintA =123456789;00c3104e movDWORD ptr [a],75bcd15h a = A/ -;00c31055 movEax,dword ptr [a]00c31058 XOREdx,edx00c3105a movECX,0DH00c3105f Diveax,ecx00c31061 movDWORD ptr [A],eax
almost exactly the same, the biggest difference is that the signed number uses the IDIV instruction (signed division), the unsigned number uses the div instruction (without symbolic division), and the CPU cycles are the same for both directives. http://www.agner.org/optimize/instruction_tables.pdf.
Of course, I'm not saying no unsigned numbers, but rather what we use to see the occasion, not what you think is better performance, unless it is accepted by the public or you undergo rigorous testing. As for some books or places, as long as the scope is not negative, it is unsigned type, I do not agree. If you speak a range, then if a signed type is not enough, then it usually does not have enough unsigned type for the same bit. For example, you int32_t not enough, you should use int64_t, if not enough, consider writing a BigInteger class bar:). However, for unsigned and signed types, the performance between them is really almost no different in the present day. What's the specific occasion? This is not necessarily the same, as in general:
- For bit storage, bit operations, modulo operations, and so on, use unsigned types
- Use a signed type for general operations
In fact, I have no sign of the symbol is that I feel very that something. Usually we say a number, or is an integer, or is a decimal, but also to divide there is no sign that really is. But because it's C + +, there's nothing strange about it.
Seems a little off the subject I want to say (pull back
I'm not trying to talk about what's symbolic and unsigned, but I want to take this question to elicit some of my views:
- Premature optimization is the source of all evil.
- Do not attempt to help the compiler optimize
- Do not guess when optimizing, take for granted to optimize oneself "think" the performance is poor place
- Explore the bottleneck of performance by profiling
Let's talk at 1.1.
For a requirement, we should complete the function first, if the performance is not up to the requirements, after the bottleneck is determined to optimize. Premature optimization, not only makes the code not direct, but also easy to bug, but also can have little impact on performance. Moreover, when we optimize, we should pay attention to the general direction and make sure the general direction is correct. For example, to write an algorithm, we should first ensure that the big-o time complexity can be met, you can use O (n) without O (NLOGN), you can use O (Nlogn) without O (N2), instead of first in there buckle i++ or ++i. In addition, do not want to help the compiler optimization, because the compiler is a lot more than you do not know how many people write out, and for the average person, want to help compiler optimization, most of it is invalid, a small part is wrong. For example, if someone learns a little bit of std::move, they always think of move move move to improve performance, to give a chestnut, (different) easy to write such code:
Template <typename t>t Create () { objectnew t (); return std::move (object);}
It's not wrong to run, but what you do behind the code is not necessarily the same as what you think, often as you might imagine. There are situations where compilers can take a better approach, as a result of which you are forced to adopt only a second point. Can look at this problem , do not repeat it.
There are, for example, using XOR to Exchange two variables, some people will think, with bit operations, not only need to create temporary variables, and bit operations are generally not faster! For this question, Aboutspeaker much earlier, in Https://cloud.github.com/downloads/chenshuo/documents/CppPractice.pdf 's 9th chapter. If you have not seen the reader, you can go.
If you've already looked at the links above, then you know that you (almost) won't know what the compiler did, the compiler can do optimizations beyond your imagination (but sometimes people can clearly see that the optimizer does not do it, but it doesn't do much) in my series of articles (ii) Also repeatedly stressed, do not try to help the compiler to optimize. If you want to explore the details behind a small piece of code, look at the disassembly!
and then about the performance bottleneck, I'd like to put an answer:https://www.zhihu.com/question/56727144/answer/150555866
Finally I hope I put the link to have a serious look! Why do I post so many links? Because I said no authority, no one believed! The great God said there is always a little reference value! (
Well, for the time being, write so much first.
Learn to shallow, if there is improper place also please Haihan, thank guidance!
The pits (appendix I) of the C + + years