I have the following piece of simple code that is potentially going to be executed many hundreds of millions of times;
for (int i = 0; i < 8; i++)
if (((p[i].X >= x) && (p[i].X <= x + d))
&&((p[i].Y >= y) && (p[i].Y <= y + d))
&&((p[i].Z >= z) && (p[i].Z <= z + d)))
return 1;
Will the optimizer in the Visual C++ 2010 compiler unroll this loop for me, or am I better off to do it manually? I've looked at other similar questions but don't see any specific results. I
The real question is, what do you gain from unrolling ?
Unrolling shaves off one branch (if i >= 8 stop) for every "unroll".
Your loop body contains 6 branches already (if * 1, || * 2, && * 3); so is there much to gain in unrolling it ?
It might be interesting to see how the code is optimized; but I am quite unsure whether unrolling should be your primary focus, I'd be more worried about how the complex condition is handled!
Related
Suppose we have the following code snippet in c++17:
for(int8 l = 0; l < 6; l++)
{
if constexpr (l % 2 == 0)
{
if(some_runtime_number > some_other_runtime_number)
{
// Do stuff
}
}
else
{
if(some_runtime_number < some_other_runtime_number)
{
// Do stuff
}
}
}
Will this actually evaluate at compile time so that every iteration the if statement switches?
The actual question is can I enforce the constexpr to cause the code to be handled at compile time rather than using the extra if every iteration.
I expect the code to function like this
When l = 0 uses the > if statement
When l = 1 uses the < if statement
When l = 2 uses the > if statement
etc..
As far as I understand this could be done being that all the numbers are known at compile time (being that it uses literals for the loop), but I would like a more knowledgeable individual to clarify that this valid and maybe provide a better understanding. Especially in regard to how this gets translated into machine code assembly, because the goal is to erase the if constexpr (l % 2 == 0) evaluation at runtime completely.
I have noticed that there is a precedence of assignment while using if-else conditionals in Verilog. For example as in the code below:
if(counter < 6)
z <= 1;
else if(counter < 12)
z <= 2;
else
z <= 3;
I noticed that until the counter is less than 6, the value of z is assigned the value of 1 (z <= 1) and as soon as the value of the counter exceeds 6 and is less than 12, z is assigned the value 2 (z <= 2).
What if there are different variables used inside the conditionals as in the code below?
if(wire1_is_enabled)
z <= 1;
else if(wire2_is_enabled)
z <= 0;
What happens when both conditions are true? What is the behaviour of the assignment operator here?
I believe this is poor programming habit.
Yes, nested if-else branching statements naturally assume a priority in the order of execution. Think about using a case statement instead of deeply nesting if statements which are much more readable.
There is nothing wrong with this coding style unless you have code like:
if(counter < 6)
z <= 1;
else if(counter < 2)
z <= 2; // unreachable
else
z <= 3;
Then the statement z <= 2; becomes unreachable because when the first condition is false, the second condition can never be true. Fortunately there are a number of tools that can flag this problem for you.
Both if and case statements assume priority logic. However, you have an option to explicitly add a priority or unique keyword before the if or case keywords to declare and check your intent. See sections 12.4 and 12.5 in the IEEE 1800-2017 SystemVerilog LRM.
The 2 if/else statements behave the same way; the first condition to be true has the highest priority. Once a condition evaluates to true, all the following else clauses are ignored. Therefore, z <= 1 if both wire1_is_enabled and wire2_is_enabled are true. This is easy to prove to yourself with a simple simulation.
This is not a poor coding habit. This situation is common in Verilog. When you say programming, perhaps you are thinking of software languages. Keep in mind that these are hardware signals instead of software variables.
In my code, I often use a formula that returns me an index into a 2D array:
cells[cellToMarkX + cellToMarkY * xSize]
// ...
if (cells[j + i * xSize] == 0)
//...
else if (cells[j + i * xSize] >= 5)
//..
cells[cellToMarkX + cellToMarkY * xSize] += 4;
I'm not sure if I should instead create some function like
getCell(int x, int y)
or should is this unnecessary and I should prefer to use a macro?
Particularly in the example you give, you might want to consider precomputing as well, as in:
int myindex = j + i * xSize;
if (cells[myindex] == 0)
....
else if (cells[myindex] >= 5)
but to answer your question more directly, a function call is not out of place here, particularly if you declare it with the inline attribute. In many cases, a good optimizing compiler will generate the same code regardless of whether you use a macro or a function, but that is of course implementation-dependent.
Personally, I'd prefer a function.
1.Imagine condition if (obj.is_x() || obj.is_y() || obj.is_z())
Will obj.is_y() and obj.is_z() be called and evaluated if obj.is_x() returned true ?
2.Is this a bad idea(in general)? Does this code look bad ?
bool isbn13_prefix_valid (const string& prefix)
{
unsigned num = stoi(prefix);
if (num == 978 || num == 979) return 1; //super common ones
else if ( num >= 0 && num <= 5 || num == 7 || num >= 600 && num <= 649
|| num >= 80 && num <= 94 || num >= 950 && num <= 989
|| num >= 9900 && num <= 9989 || num >= 99900 && num <= 99999)
return 1;
return 0;
}
No, it will not, due to short-circuiting.
Yes, that code looks bad. Not because it's incorrect, but because you're stuffing an extremely long conditional into a single if statement. Try refactoring your code to make it cleaner.
Your code is absolutely fine. I'd like to see a comment where these strange numbers come from, that's all.
Turning it into a dozen trivial functions as has been suggested is in no way helpful. It actually makes it a lot harder to read the code, because it gets spread out over many many lines of code. Yes, it is complex. But that's due to the problem being complex, and trying to spread the complexity out doesn't help one bit.
Your actual question: In a || b, a is evaluated first. If it is true, then b is not evaluated and the result is true. If a is false, then b is also evaluated and the result is true or false, depending on the result of b.
An optimising compiler may start evaluating b before it has finished evaluating a, if it can prove that the evaluation of b has no side effects, and if it believes that (mostly due to parallelism in the hardware) it is on average faster to evaluate as much in parallel as possible, even if some things are evaluated when it wasn't necessary. But this is not noticable in the results of your code, and will only make the code faster.
I'm trying to make a solver that checks the block to make sure that no number repeats. Unfortunately, I can not get the correct logic on this and I'm not sure what I am doing incorrectly. Here is what I've got:
not quite sure why this is not working. Here's my code.
bool sudoku :: check_if_non_repeat(int r, int c, int v) //where r=row, c=column, v=value
Any idea why this is not working? I'm just getting infinite loops
if (!(j = brow && k == bcol))
Check that j=.... should be ==
I'm not sure what you tried to do, but I would do it like this:
bool sudoku :: check_if_non_repeat(int r, int c, int v) //where r=row, c=column, v=value
{
int brow = r/3;
int bcol = c/3;
for (int j = brow * 3; j < (brow * 3 + 3); j++)
for (int k = bcol * 3; k < (bcol * 3 + 3); k++)
if (sudoku_array[j][k] == v)
return true;
return false;
}
EDIT:
As noted below, the if statement need to be more complicated:
if ( sudoku_array[j][k] == v
&& v != 0
&& !(j == r && k == c))
return true;
I'm about to tell you about a different approach to the problem. I made a full solver a long while ago, and it basically used the opposite approach.
For each field, I had a std::bitset<9> which told me which values were still possible in that field. Each insertion would then update the other fields in the same row, column and box to remove that possibility, recursively filling out subsequent fields when any one of the them had one option left.
If it then tried to fill a number which was no longer allowed, then the last input given was no longer a valid number for that spot. That was also a far more thorough check than you're doing here: you won't be checking if you close off the last possibility for another field in the same row/column/box, let alone others.
I never did a couple planned optimizations, but even without them it outperformed (too quick to notice) my friend's solver (>50 seconds). Mostly because he had code like yours.