Alternative implementations of standard functions/approaches - page 9

 
fxsaber:

Got to the point where the problem no longer occurs and safely forgot about it. It's great when you don't have to go back to once-written code. It works - that's the main thing.

That's right. I always do this myself (and this time too, as you can see).

The problem will arise if something suddenly changes. When code is clear and non-obvious places are well commented, causes of errors in some changes are easy to find. But in such cases of "and forgot" - it is much more difficult to make corrections.

Yes, of course, that it is a rare case... But these very rare cases - personally I'm very nervous. That's why in such situations I try to write clear code as much as possible and give detailed comments for non-obvious places.

 
fxsaber:

An example of my code, which right now I don't understand at all. And there are a lot of factors that need to be very well understood.


As you can see, the code/style is very simple. But I will only be able to detect an error in it or its absence when I am able to write the same code all over again. It will really take me a lot of time, as I need to get into the problem completely.

That's why the principle is that complex things are cleaned up (stress tests are written) at the creation stage and used in a simple form by plugging in mqh. As you can see, complexity is not always determined by style or brevity.


There is also an example of purely linguistic constructs - TypeToBytes. The comprehension complexity there is quite a different level. And this is where I would wither away without macros. It is because of macros that you get into the source code quite quickly. Because macros are often used not for brevity, but for comprehension.


And there's also the case when you have to consider a lot of uncomplicated but forgettable pitfalls. This is the case with MT4Orders. That's why some lines there are accompanied by comments addressed only to oneself. It helps to understand your code.


But note that these are all mqh, which you don't need to get into. And TC code is written with mqh, which is very simple. You do not look into source code of regular iHigh functions. And they are monster indeed. You just use them. You should do the same with libraries. The same Generic-bibble to use doesn't require you to fully understand it.


Look at the QB for MT4 EAs and their MT5 ports. MT5 ports are a gimp to understand. Not only does it not smell close to conciseness (the code is many times larger than the original), it also has rattling MT5 pitfalls that are not accounted for in the mqh-files.

Honestly, I have nothing to argue with here. Obviously, everything is correct based on your approach to programming (maybe only with the exception of cases of excessive and unjustified code compression), but if you take my approach, a lot is wrong.

1. of course, hard-to-find errors may hide even in very simply-written code. But they are even harder to find in hard-to-write code. Consider the mental effort involved in unpacking the meaning. If you need to do a large amount of work (write a lot of functions, build new mechanisms, successfully integrate them into existing ones), saving time and effort is the main thing. It is not about "beauty" of code. Not about styles. You need to compose your code in such a way that you could read it in the middle of the night and understand it as quickly as possible. You start searching for the ideal method of coding in order to get the maximum result from yourself. And looking at it:

return((int)((Value > 0) ? Value / Points[digits] + HALF_PLUS : Value / Points[digits] - HALF_PLUS) * Points[digits]);

you immediately understand all the disadvantages of writing it in this way:

1. A lot of characters.

2. Excessive "packing".

3. uncommented mathematical operations.

You won't be able to handle this code while you are awake. It is also difficult to cope with being overworked and very tired. Imagine you are working like this every day. You immediately turn away from such a code.


2. Don't look at other people's code and just plug it in?

I believe that large, serious and, what is most important, high-quality programs are not created merely by assembling other people's blocks. You cannot create an efficient program by creating only a small part of it and attaching the rest. It will be a "mess".

It can and will work. But these are "makeshift" programs.

I don't believe in the effectiveness of programs assembled from blocks (into which the developer doesn't even look). This is a fiction. The program will be lame and solutions will be ineffective. There will be a lot of problems. If programmers work as a team and solve a common task, it is good, but if solutions are used which "float" between different programs of different people (who don't even look into them), it is nothing from the viewpoint of efficiency.

 
Реter Konow:

It can and will work. But this is, - programmes "on their knees".

You can look at my publications in KB. Someone must be using them.

I write only for myself and "on my knees". Publications are a by-product.

 
Georgiy Merts:

So the check for LONG_MAX - should be before converting double to long. Clearly, the rounding function is not designed for values that do not fit into an integer. And it does not change the problem.

If the function returns double, which we then convert into long, we face the same danger of overflow.

Personally, I always have assert-checking for boundary values just before rounding; in addition, the logic of the program is that I always make sure that a value greater than the maxima for an integer can never arrive at the transform.

Do you often cast long into char? It's the same with double - it is the last rung of the hierarchy, you don't need to cast it, in most cases you don't need to, std has everything to work with it. Don't cast down the hierarchy and don't sweat it.

Add checks on LONG_MAX/MIN - and something tells me that performance tests won't be so rosy. And the person is aiming for std substitution, so it should work for the whole range of values.

 
pavlick_:

Do you cast long into char often? It's the same with dabl - it's the last rung of the hierarchy, there's no need to cast from it, in most cases there's nothing to do with it, std has everything to work with it. Don't cast down the hierarchy and don't bother.

Add checks for LONG_MAX/MIN and I'm sure the performance tests won't be so lucky. And the man is aiming at std substitution, so it should work for the whole range of values.

long to ulong (and vice versa) - all too often.

long to char - seldom.

Conversion is necessary because integer and floating-point operations result significantly different. The execution speed of integer data is supposedly faster, too.

About range check - I've already stressed that it's ASSERT - i.e. such check works only in DEBUG-version. In my case all input parameters are always checked for valid range with asserts at the beginning of any public-function, which helped me out more than once. RELEASE versions, of course, already work without any checks.

 
fxsaber:

You can have a look at my publications in KB. Someone must be using them.

I write only for myself and "on my knees". Publications are a by-product.

I am not questioning your experience and professionalism.

It's just that in the process of exhausting and daily programming and development during several years you start to estimate the advantages of some particular code, solution or approach. And you often come to very strange conclusions... Strange ones but justified by much practice.

I'm just sharing my point of view.

 
Georgiy Merts:

The need for conversion arises because the result of integer and floating point operations is significantly different.

I can't imagine in which situations something can't be done properly with dubles. In Lua (attached to quik), there are no integer types at all, only dubles, and nothing.

 
pavlick_:

I have a bad idea in which situations something cannot be done properly on dubles.

Counter.

void OnStart()
{
  const long Num1 = 9007199254967295;
  const long Num2 = Num1 + 1;

  Print(Num1 == Num2); // false
  Print((double)Num1 == (double)Num2); // true
}

double does not lose all int-range information, not so much with long anymore.

Особенности языка mql5, тонкости и приёмы работы
Особенности языка mql5, тонкости и приёмы работы
  • 2018.01.15
  • www.mql5.com
В данной теме будут обсуждаться недокументированные приёмы работы с языком mql5, примеры решения тех, или иных задач...
 
fxsaber:

Counter.

Well, you still have to count up to that many )). And if you really want to, that's not an option:

double cnt;
double high_cnt;
if (++ cnt == 1 000 000) {
   ++ high_cnt;
   cnt = 0;
}
 
pavlick_:

Well, you still have to count up to that many )). But if you really want to, that's not an option:

It's understandable that it's possible to get twisted. But is it worth it?

In my opinion, if the variable must have only integer values, it should be integer just to make it impossible to write a floating point value into it. The type of variable or return value itself already contains important information about the variable and partially about the algorithm. If we use floating point values everywhere, this information will be lost.

And even the integer - depending on the algorithm, in my opinion - must be declared as either signed or unsigned, and not necessarily long, but perhaps "shorter" - just so that when looking at the code we can immediately understand what range of values the variable in question is allowed to have.

The fact that there are no integer values in Lua is, in my opinion, a serious disadvantage.

Reason: