What is the difference between nested and cascaded if-else?
These two are equivalent:
if (condition1) block1
else if (condition2) block2
if (condition1) block1
else
{
if (condition2) block2
}
I presume they also compile to the same assembly, so there should be no difference.
I depends on how you arrange them. A nested if is equivalent to adding an and to each of the inner ifs:
if(A) {
if(B) {
statement1
}
else if(C) {
statement2
}
}
is equivalent to:
if(A and B) {
statement1
}
else if(A and C) {
statement2
}
My advice is to strive for readability and check your logic. You may find DeMorgan's Laws useful for re-arranging your logic.
Here's one that always irritates me:
if(A and B) {
statement1
statement2
}
else if(A and C) {
statement1
statement3
}
else if(not A) {
statement4
}
vs
if(A) {
statement1
if(B) {
statement2
}
else if(C) {
statement3
}
}
else if(not A) {
statement4
}
I'm just not sure which is more readable. They are logically equivalent. The first is more tabular and easier on the eye but repeats statement1; the second is more nested and a little uglier (to my eye) but does not repeat statements. Ultimately it's a judgment call because it makes no difference to the compiler.
Nested if-then-else control structures are minimized translations of complex logic rules. They are good in avoiding redundancy in checking conditions. Their main drawback is that in the long run these structures can grow and make enclosing methods too big and complex. First step in breaking nested if-then-else blocks is normalization. For example:
if (A) {
if (B || C) {
block 1;
} else {
if (!D) {
block 2;
}
}
} else {
block 3;
}
can be normalized to cascaded if-then-else
if (A && (B || C) {
block 1;
return;
}
if (A && !B && !C && !D) {
block 2;
return;
}
if (!A) {
block 3;
}
We have eliminated else blocks and made further extract method refactoring easy. All three if blocks can be extracted to separate methods named after the business logic their bodies execute.
Related
I am looking to change this code to prevent so much branch divergence
if (v == u) {
++c;
++u_t;
++v_t;
}
else if (v < u){
++u_t;
}
else {
++v_t;
}
Here is what I tried:
u_t++;
if(v == u){
++c;
++v_t;
}
else{
--u_t;
++v_t
}
Although this code is giving me the wrong answer for the whole program. Am I missing something obvious here?
It all comes down to
if (v == u) ++c;
if (v <= u) ++u_t;
if (v >= u) ++v_t;
Can you optimise this? Not sure you can without knowing anything about the rest of the code.
In CUDA device code, the following if-else statement will cause divergence among the threads of a warp, resulting in two passes by the SIMD hardware. Assume Vs is a location in shared memory.
if (threadIdx.x % 2) {
Vs[threadIdx.x] = 0;
} else {
Vs[threadIdx.x] = 1;
}
I believe there will also be two passes when we have an if statement, with no else branch. Why is this the case?
if (threadIdx.x % 2) {
Vs[threadIdx.x] = 0;
}
Would the following if statement be completed in 3 passes?
if (threadIdx.x < 10) {
Vs[threadIdx.x] = 0;
} else if (threadIdx.x < 20) {
Vs[threadIdx.x] = 1;
} else {
Vs[threadIdx.x] = 2;
}
On a GPU, it could very well be the case that there is only one pass with an if-else statement - one predicated pass. The condition will just turn on the "do nothing" bit for half the threads during the "then" block, and turn the other half's "do nothing" bit off for the "else" block.
As #njuffa points out, however, this is dependent upon parameters such as the target architecture etc.
For more details, see:
Branch predication on GPU
For your first specific example of an if body, a compiler might not even need a predicated pass, since it can be rewritten as
Vs[threadIdx.x] = (threadIdx.x % 2 ? 0 : 1);
and that's perfectly uniform across your warp. For your last example - it really depends, but again it could theoretically be optimized by the compiler into a single unpredicated pass, and it also might be the case that you'll have a predicated single path, with different predication within each of the three scopes.
I'm trying to use Splint with MySQL C API and have run in to some additional problems relating to freeing memory. In all the examples I can find about using the C API, the only freeing function that is called is mysql_free_result, but rows and fields are never freed:
while ((row = mysql_fetch_row(result)))
{
for(int i = 0; i < num_fields; i++)
{
if (i == 0)
{
while(field = mysql_fetch_field(result))
{
// Bla
}
}
}
}
mysql_free_result(result);
mysql_close(con);
Splint will of course throw an error saying that row and field are memory leaks. Are they? How to resolve this? Should I manually free the row and field structs?
Edit: OK, since mysql_fetch_row returns null when there is no more rows, I assume it also frees all memory from former row each loop. But how the hell would I tell Splint this?
EDit 2: Here's the implementation for mysql_fetch_row (version 5.5). No memory is allocated, the function just point you to the next row. So what's needed is a Splint annotation for the function that tells Splint no memory is allocated, but shared.
MYSQL_ROW STDCALL
mysql_fetch_row(MYSQL_RES *res)
{
DBUG_ENTER("mysql_fetch_row");
if (!res->data)
{ /* Unbufferred fetch */
if (!res->eof)
{
MYSQL *mysql= res->handle;
if (mysql->status != MYSQL_STATUS_USE_RESULT)
{
set_mysql_error(mysql,
res->unbuffered_fetch_cancelled ?
CR_FETCH_CANCELED : CR_COMMANDS_OUT_OF_SYNC,
unknown_sqlstate);
}
else if (!(read_one_row(mysql, res->field_count, res->row, res->lengths)))
{
res->row_count++;
DBUG_RETURN(res->current_row=res->row);
}
DBUG_PRINT("info",("end of data"));
res->eof=1;
mysql->status=MYSQL_STATUS_READY;
/*
Reset only if owner points to us: there is a chance that somebody
started new query after mysql_stmt_close():
*/
if (mysql->unbuffered_fetch_owner == &res->unbuffered_fetch_cancelled)
mysql->unbuffered_fetch_owner= 0;
/* Don't clear handle in mysql_free_result */
res->handle=0;
}
DBUG_RETURN((MYSQL_ROW) NULL);
}
{
MYSQL_ROW tmp;
if (!res->data_cursor)
{
DBUG_PRINT("info",("end of data"));
DBUG_RETURN(res->current_row=(MYSQL_ROW) NULL);
}
tmp = res->data_cursor->data;
res->data_cursor = res->data_cursor->next;
DBUG_RETURN(res->current_row=tmp);
}
}
The correct annotation for sharing read-only storage is /*#observer#*/. For sharing writeable storage, /*#exposed#*/ could be used.
/*#observer#*/ MYSQL_ROW STDCALL mysql_fetch_row(MYSQL_RES *result);
More in the Splint manual.
I have followed the pseducode on the wikipedia article, and I think I got it working. However, it returns the score, and that doesn't exactly help when I want to know what move I want to make.
I tried what I think would be a way to get the best move, but I don't think it is working as when I actually try to play against it (chess), the AI makes somewhat retarded moves with a depth level of 3.
Here is my function:
public static function alphaBeta(node, depth, alph, beta, team, tellTheMove:Boolean = false):* {
var pointer:ChessMove;
if (depth == 0) {
return scoreOf(node);
}
var childrenOf:Vector.<ChessMove > = returnPossibleMoves(node,team);
if (childrenOf.length == 0) {
return scoreOf(node);
}
if (team == 0) {
for (var i in childrenOf) {
var that:Number = alphaBeta(childrenOf[i],depth - 1,alph,beta,1);
if(tellTheMove){
}
if (that > alph) {
alph = that;
if(tellTheMove){
pointer = childrenOf[i];
}
}
if (beta <= alph) {
break;
}
}
if(tellTheMove){
return pointer; //Returns the move that's score last exceeded alpha.
}
return alph;
} else {
for (var j in childrenOf) {
var that2:Number = alphaBeta(childrenOf[j],depth - 1,alph,beta,0);
if (that2 < beta) {
beta = that2;
}
if (beta <= alph) {
break;
}
}
return beta;
}
}
Depth 3 is very little for a problem like chess. At this depth most of the power depends on your final evaluation function. This evaluation function is very hard to do in way that it can predict the value of the board efficiently.
Try something simpler, which can be solved efficiently at a lower depth. Tic-Tac-Toe is a very good game for a first attempt at Min-Max. This is because the final outcome is well known. If you get your algorithm correctly you should not be able to beat it at all. If you do Tic-Tac-Toe and the algorithm is loosing, you know that you have a mistake.
Also note that in some cases Min-Max plays optimal, but still will look retarded to a human opponent. For example if there is no chance at winning, Min-Max will start to play randomly and do very dumb moves. This is the case , because Min-Max expects the opponent to also play perfect, which is usually not the case with humans. There are some simple changes that can be done to the algorithm to change this behavior and have min-max play "less retarded" in such cases.
Here's the code.
bool b_div(int n_dividend)
{
for (int iii = 10 ; iii>0 ; iii--)
{
int n_remainder = n_dividend%iii;
if (n_remainder != 0)
return false;
if (iii = 1)
return true;
}
}
After testing this function I made for a program, the function seems to stop at the if (n_remainder != 0) part. Now then the function SHOULD test if the number that the function takes in can be divided by all numbers from 10 to 1.(it takes in numbers until it returns true) I know the first number that this works with it is 2520 but even on this number it stops at if(n_remainder != 0). So I was hoping for some advice! Im having trouble troubleshooting it! Any links or words I should look for would be awesome! Im still pretty new to programming so any help you can give for learning would rock! Thanks!
Change your last if statement to:
if (iii == 1)
return true;
Currently you have only a single equals sign, which sets the variable iii to 1, and is always true. By using a double equals it will compare iii and 1.
In addition to SC Ghost's answer, you can actually also clean up your function a bit more :)
bool b_div(int n_dividend) {
for (int i = 10 ; i > 1 ; i--) {
int n_remainder = n_dividend % i;
if (n_remainder != 0) {
return false;
}
}
return true;
}
A few notes,
modulus of 1 will always be zero, so you only need to iterate while i > 1
you can completely remove the if(i == 1) check and just always return true after the for loop if the for loop doesn't return false. It basically removes an unnecessary check.
I think it's more standard to name your iterator iii as i, And I prefer brackets the way I wrote them above (this is of course completely personal preference, do as you please)