Cases where to use Pre-Increment or Post-Increment Operators - c

Reading a couple of questions about Post-Increment and Pre-Increment I am in need of trying to explain a new programmer in what cases I would actually need one or the other. In what type of scenarios one would apply a Post-Increment Operator and in what it is better to apply a Pre-Increment one.
This is to teach case studies where, in a particular code, one would need to apply one or the other in order to obtain specific values for certain tasks.

The short answer is: You never need them!
The long answer is that the instruction sets of early micro-computers had features like that. Upon reading of a memory cell, you could post-increment or pre-decrement that cell when reading it. Such machine level features inspired the predecessors of C, from whence it found its way even into more recent languages.
To understand this, one must remember that RAM was extremely scarce in those days. When you have 64k addressable RAM for your program, you'll find it worth it to write very compact code. The machine architectures of those days reflected this need by providing extremely powerful instructions. Hence you could express code like:
s = s + a[j]
j = j + 1
with just one instruction, given that s and j were in a register.
Thus we have language features in C that allowed the compiler without much effort to generate efficient code line:
register int s = 0; // clr r5
s += a[j++]; // mov j+, r6 move j to r6 and increment j after
// add r5,a[r6]
The same goes for the short-cut operations like +=, -=, *= etc.
They are
A way to save typing
A help for a compiler that had to fit in small RAM, and couldn't afford much optimizations
For example,
a[i] *= 5
which is short for
a[i] = a[i] * 5
in effect saves the compiler some form of common subexpression analysis.
And yet, all that language features, can always be replaced by equivalent, maybe a bit longer code that doesn't use them. Modern compilers should translate them to efficient code, just like the shorter forms.
So the bottom line and answer to your question: you don't need to look for cases where one needs to apply those operators. Such cases simply do not exits.

Well, some people like Douglas Crockford are against using those operators because they can lead to unexpected behaviors by hiding the final result from the untrained eye.
But, since I'm using JSHint, let's share an example here:
http://jsfiddle.net/coma/EB72c/
var List = function(values) {
this.index = 0;
this.values = values;
};
List.prototype.next = function() {
return this.values[++this.index];
};
List.prototype.prev = function() {
return this.values[--this.index];
};
List.prototype.current = function() {
return this.values[this.index];
};
List.prototype.prefix = function(prefixes) {
var i;
for (i = 0; i < this.values.length; i++) {
this.values[i] = prefixes[i] + this.values[i];
}
};
var animals = new List(['dog', 'cat', 'parrot']);
console.log('current', animals.current());
console.log('next', animals.next());
console.log('next', animals.next());
console.log('current', animals.current());
console.log('prev', animals.prev());
console.log('prev', animals.prev());
animals.prefix(['Snoopy the ', 'Gartfield the ', 'A ']);
console.log('current', animals.current());

As others have said, you never "need" either flavor of the ++ and -- operators. Then again, there are a lot of features of languages that you never "need" but that are useful in clearly expressing the intent of the code. You don't need an assignment that returns a value either, or unary negation since you can always write (0-x)... heck, if you push that to the limit you don't need C at all since you can always write in assembler, and you don't need assembler since you can always just set the bits to construct the instructions by hand...
(Cue Frank Hayes' song, When I Was A Boy. And get off my lawn, you kids!)
So the real answer here is to use the increment and decrement operators where they make sense stylistically -- where the value being manipulated is in some sense a counter and where it makes sense to advance the count "in passing". Loop control is one obvious place where people expect to see increment/decrement and where it reads more clearly than the alternatives. And there are many C idioms which have almost become meta-statements in the language as it is actually used -- the classic one-liner version of strcpy(), for example -- and which an experienced C programmer will recognize at a glance and be able to recreate at need; many of those do take advantage of increment/decrement as side effect.
Unfortunately, "where it makes sense stylistically" is not a simple rule to teach. As with any other aspect of coding style, it really needs to come from exposure to other folks' code and from an understanding of how "native speakers" of the programming language think about the code.
That isn't a very satisfying answer, I know. But I don't think a better one exists.

Usually, it just depends on what you need in your specific case. If you need the result of the operation, it's just a question of whether you need the value of the variable before or after incrementing / decrementing. So use the one which makes the code more clear to understand.
In some languages like C++ it is considered good practice to use the pre-increment / pre-decrement operators if you don't need the value, since the post operators need to store the previous value in a temporary during the operation, therefore they require more instructions (additional copy) and can cause performance issues for complex types.
I'm no C expert but I don't think it really matters which you use in C, since there are no increment / decrement operators for large structs.

Related

Parallel operations in array with dependency

I need help to solve this problem, I have a code with operations being performed on the previous element of the array, and I need to parallelize using openmp tasks, however I know how to remove this depency. My teacher says that in this case it is not interesting to use depend (in, out). How would I remove that depended on this then?
void sum_sequential(float a[N]) {
a[0] = 1.0;
for (int i = 1; i < N; i++)
a[i] = 2 * a[i-1] + 1;
}
You are quite right that there is is a data dependency. The value to be computed for each element is expressed in terms of the value previously computed for the preceding element, so this algorithm is inherently serial. There is no practical advantage in parallelizing it, as successfully dealing with the dependencies leaves no room for any concurrency.
HOWEVER, if you study the computation carefully, it is possible to re-express it in an algebraically equivalent way that does not have such dependencies -- an altogether different algorithm that produces the same results and is trivially parallelizable. At the risk of providing too big a hint, try writing out the first several terms of the results by hand, and see whether you recognize a simple pattern.

Updating values in an array with logical indexing with a non-constant value

A common problem I encounter when I want to write concise/readable code:
I want to update all the values of a vector matching a logical expression with a value that depends on the previous value.
For example, double all even entries:
weights = [10 7 4 8 3];
weights(mod(weights,2)==0) = weights(mod(weights,2)==0) * 2;
% weights = [20 7 8 16 3]
Is it possible to write the second line in a more concise fashion (i.e. avoiding the double use of the logical expression, something like i+=3 for i=i+3 in other languages). If I often use this kind of vector operation in different contexts/variables, and I have long conditionals, I feel that my code is less concise and readable than it could be.
Thanks!
How about
ind = mod(weights,2)==0;
weights(ind) = weights(ind)*2;
This way you avoid calculating the indices twice and it's easy to read.
Starting your other comment to Wauzl, such powerful operation capabilities is the Fortran side. This is purely matlab's design that is quickly getting obsolete. Let's use this horribleness further:
for i=1:length(weights),if (mod(weights(i),2)==0)weights(i)=weights(i)*2;end,end
It is even slightly faster than your two liner because you are doing the conditional indexing twice on both sides. In general, consider switching to Python3.
Well, I after more searching around, I found this link that deals with this issue (I used search before posting, I swear!), and there is interesting further discussion regarding this topic in the links in that thread. So apparently there are issues with ambiguity when introducing such an operator.
Looks like that is the price we have to pay in terms of syntactic limitations for having such powerful matrix operation capabilities.
Thanks a lot anyway, Wauzl!

How to implement switch with distinct cases?

Here in the followed program if last condition is true then unnecessarily we have to check all conditions before it.
Is there any possibility to implement switch case in the below program?
I've to convert very similar code to this into Arm assembly.
main()
{
int x;
if (x< 32768)
x<<15;
elseif(x<49152)
(x<<12)- 7;
elseif(x<53248)
(x<<11)- 13;
elseif(x<59392)
(x<<10)-27;
elseif(x<60928)
(x<<9)-61;
elseif(x<62208)
(x<<8)-139;
elseif(x<64128)
(x<<7)-225;
elseif(x<65088)
(x<<6)-414;
elseif(x<65344)
(x<<5)-801;
elseif(x<65488)
(x<<4)-1595;
elseif(x<65512)
(x<<3)-2592;
elseif(x<65524)
(x<<2)-4589;
elseif(x<65534)
(x<<1)-8586;
}
Hope someone will help me.
So first things first: are you concerned about performance? If so, do you have actual profiling data showing that this code is a hot-spot and nothing else shows up on the profile?
I doubt that. In fact, I am willing to bed that you haven't even benchmarked it. You are instead looking at code and trying to micro-optimize it.
If that's the case then the answer is simple: stop doing that. Write your code the way it makes sense to write it and focus on improving the algorithmic efficiency of your code. Let the compiler worry about optimizing things. If the performance proves inadequate then profile and focus on the results of the profiling. Almost always the answer to your performance problems will use: choose a better-performing algorithm. The answer will almost never be "tinker with an if statement".
Now, to answer your question: A switch isn't helpful in this scenario because there's no sane way to represent the concept x < 32768 in a case statement, short of writing one statement for every such value of x. Obviously this is neithe practical nor sane.
More importantly you seem to operate under the misconception that a switch would translate to fewer comparisons. It's possible in some rare cases for a compiler to be able to avoid comparisons, but most of the time a switch will mean as many comparisons as you have case statements. So if you need to check a variable against 10000 different possible values using a switch, you'll get 10000 comparisons.
In your case, you're checking for way more than 10,000 possible values, so the simple if construct combined with the "less than" operator makes a lot more sense and will be much more efficient than a switch.
You write that "Here in the followed program if last condition is true then unnecessarily we have to check all conditions before it." True, you do. You could rewrite it so that if the last condition were true you would only need two comparisons. But then you'd simply flip the problem on it's head: if x< 32768 you'd end up having to check all the other possible values so you'd be back where you started.
One possible solution would be to perform binary search. This would certainly qualify as an algorithmic improvement, but again without hard data that this is, indeed, a hotspot, this would be a rather silly exercise.
The bottom line is this: write correct code that is both easy to understand and easy to maintain and improve and don't worry about reordering if statements. The excellent answer by perreal shows a good example of simple and easy to understand and maintain code.
And on the topic of writing correct code, there's no such thing as elseif in C and C++. Which brings us to my last point: before micro-optimizing code at least try to run the compiler.
You can't do that with switches since you need to have constant values to compare to x, not boolean conditions. But you can use a struct like this:
struct {
int u_limit;
int shift_left;
int add;
} ranges[13] = { {32768, 15, 0}, {49152, 12, -7} /*, ...*/};
for (int i = 0; i < 13; i++) {
if (x < ranges[i].u_limit) {
x = x << ranges[i].shift_left + ranges[i].add; break;
}
}
Of course, you can replace the linear search with binary search for some speedup.

Differences between IF and SWITCH/CASE in C

The question is really simple: in a laboratory class I attended this year, professor presented the switch/case statement alongside the classic if/then/else statement without saying anything about which one was better in different programming situations.
Which one is better when checking a variable which can have at least 10/15 possible values?
Breifly (your question is vague), a switch compiles to a jump table in assembler and is therefore faster than if / then / else. Note that a switch statement in C has a 'follow-through' feature (google this) which can be circumvented with break statements.
You can only switch on things that evaluate to integral types. In particular this means that you cannot switch on strings: strings are not part of the natural C language in any case.
An if / then / else checks several conditions in succession. Comparison is not restricted to integral types as all you're testing is true (not zero) or false (zero).
That's probably enough to get you started.
I think
If then else is better in case only when you have 2 conditions only.
Otherwise its better to use switch case if conditions are more than 2
When the value to be compared has a type that is amenable to being switch'd, and it makes your code more readable, then go ahead and use a switch. For example,
if (val == 0) {
// do something
} else if (val == 1) {
// do something else
} else if (val == 2) {
// yet another option
} ...
is cluttered and hard to maintain compared to a switch. Imagine that some day, you don't want to switch on val but on validate(val); then you'd need to change all the conditions.
Also, switch may be faster than if/else sometimes, because a compiler may turn it into either a jump table or a binary search. Then again, a compiler might do the same to a series of if/else statements, although that's a more difficult optimization to make because the clauses order might matter and the compiler must be able to detect that it doesn't.
switch is better performance-wise too because it can be optimized in various ways by the compiler, depending on whether the values are consecutive. If yes, it can outright use the value as an index to an array of pointers. If not, it can sometimes use a binary search instead of a linear search, when it's faster.
switch looks better than lots of ifs. However it only works on numeric expressions (as a char is essentially a number, it can still be applied to it, however you cannot use it with strings).
If I may point you to here as it has a nice description of the switch statement. Note the opening sentence:
Switch case statements are a substitute for long if statements that
compare a variable to several "integral" values ("integral" values are
simply values that can be expressed as an integer, such as the value
of a char).

Crossover function for genetic

I am writing a Time table generator in java, using AI approaches to satisfy the hard constraints and help find an optimal solution. So far I have implemented and Iterative construction (a most-constrained first heuristic) and Simulated Annealing, and I'm in the process of implementing a genetic algorithm.
Some info on the problem, and how I represent it then :
I have a set of events, rooms , features (that events require and rooms satisfy), students and slots
The problem consists in assigning to each event a slot and a room, such that no student is required to attend two events in one slot, all the rooms assigned fulfill the necessary requirements.
I have a grading function that for each set if assignments grades the soft constraint violations, thus the point is to minimize this.
The way I am implementing the GA is I start with a population generated by the iterative construction (which can leave events unassigned) and then do the normal steps: evaluate, select, cross, mutate and keep the best. Rinse and repeat.
My problem is that my solution appears to improve too little. No matter what I do, the populations tends to a random fitness and is stuck there. Note that this fitness always differ, but nevertheless a lower limit will appear.
I suspect that the problem is in my crossover function, and here is the logic behind it:
Two assignments are randomly chosen to be crossed. Lets call them assignments A and B. For all of B's events do the following procedure (the order B's events are selected is random):
Get the corresponding event in A and compare the assignment. 3 different situations might happen.
If only one of them is unassigned and if it is possible to replicate
the other assignment on the child, this assignment is chosen.
If both of them are assigned, but only one of them creates no
conflicts when assigning to the child, that one is chosen.
If both of them are assigned and none create conflict, on of
them is randomly chosen.
In any other case, the event is left unassigned.
This creates a child with some of the parent's assignments, some of the mother's, so it seems to me it is a valid function. Moreover, it does not break any hard constraints.
As for mutation, I am using the neighboring function of my SA to give me another assignment based on on of the children, and then replacing that child.
So again. With this setup, initial population of 100, the GA runs and always tends to stabilize at some random (high) fitness value. Can someone give me a pointer as to what could I possibly be doing wrong?
Thanks
Edit: Formatting and clear some things
I think GA only makes sense if part of the solution (part of the vector) has a significance as a stand alone part of the solution, so that the crossover function integrates valid parts of a solution between two solution vectors. Much like a certain part of a DNA sequence controls or affects a specific aspect of the individual - eye color is one gene for example. In this problem however the different parts of the solution vector affect each other making the crossover almost meaningless. This results (my guess) in the algorithm converging on a single solution rather quickly with the different crossovers and mutations having only a negative affect on the fitness.
I dont believe GA is the right tool for this problem.
If you could please provide the original problem statement, I will be able to give you a better solution. Here is my answer for the present moment.
A genetic algorithm is not the best tool to satisfy hard constraints. This is an assigment problem that can be solved using integer program, a special case of a linear program.
Linear programs allow users to minimize or maximize some goal modeled by an objective function (grading function). The objective function is defined by the sum of individual decisions (or decision variables) and the value or contribution to the objective function. Linear programs allow for your decision variables to be decimal values, but integer programs force the decision variables to be integer values.
So, what are your decisions? Your decisions are to assign students to slots. And these slots have features which events require and rooms satisfy.
In your case, you want to maximize the number of students that are assigned to a slot.
You also have constraints. In your case, a student may only attend at most one event.
The website below provides a good tutorial on how to model integer programs.
http://people.brunel.ac.uk/~mastjjb/jeb/or/moreip.html
For a java specific implementation, use the link below.
http://javailp.sourceforge.net/
SolverFactory factory = new SolverFactoryLpSolve(); // use lp_solve
factory.setParameter(Solver.VERBOSE, 0);
factory.setParameter(Solver.TIMEOUT, 100); // set timeout to 100 seconds
/**
* Constructing a Problem:
* Maximize: 143x+60y
* Subject to:
* 120x+210y <= 15000
* 110x+30y <= 4000
* x+y <= 75
*
* With x,y being integers
*
*/
Problem problem = new Problem();
Linear linear = new Linear();
linear.add(143, "x");
linear.add(60, "y");
problem.setObjective(linear, OptType.MAX);
linear = new Linear();
linear.add(120, "x");
linear.add(210, "y");
problem.add(linear, "<=", 15000);
linear = new Linear();
linear.add(110, "x");
linear.add(30, "y");
problem.add(linear, "<=", 4000);
linear = new Linear();
linear.add(1, "x");
linear.add(1, "y");
problem.add(linear, "<=", 75);
problem.setVarType("x", Integer.class);
problem.setVarType("y", Integer.class);
Solver solver = factory.get(); // you should use this solver only once for one problem
Result result = solver.solve(problem);
System.out.println(result);
/**
* Extend the problem with x <= 16 and solve it again
*/
problem.setVarUpperBound("x", 16);
solver = factory.get();
result = solver.solve(problem);
System.out.println(result);
// Results in the following output:
// Objective: 6266.0 {y=52, x=22}
// Objective: 5828.0 {y=59, x=16}
I would start by measuring what's going on directly. For example, what fraction of the assignments are falling under your "any other case" catch-all and therefore doing nothing?
Also, while we can't really tell from the information given, it doesn't seem any of your moves can do a "swap", which may be a problem. If a schedule is tightly constrained, then once you find something feasible, it's likely that you won't be able to just move a class from room A to room B, as room B will be in use. You'd need to consider ways of moving a class from A to B along with moving a class from B to A.
You can also sometimes improve things by allowing constraints to be violated. Instead of forbidding crossover from ever violating a constraint, you can allow it, but penalize the fitness in proportion to the "badness" of the violation.
Finally, it's possible that your other operators are the problem as well. If your selection and replacement operators are too aggressive, you can converge very quickly to something that's only slightly better than where you started. Once you converge, it's very difficult for mutations alone to kick you back out into a productive search.
I think there is nothing wrong with GA for this problem, some people just hate Genetic Algorithms no matter what.
Here is what I would check:
First you mention that your GA stabilizes at a random "High" fitness value, but isn't this a good thing? Does "high" fitness correspond to good or bad in your case? It is possible you are favoring "High" fitness in one part of your code and "Low" fitness in another thus causing the seemingly random result.
I think you want to be a bit more careful about the logic behind your crossover operation. Basically there are many situations for all 3 cases where making any of those choices would not cause an increase in fitness at all of the crossed-over individual, but you are still using a "resource" (an assignment that could potentially be used for another class/student/etc.) I realize that a GA traditionally will make assignments via crossover that cause worse behavior, but you are already performing a bit of computation in the crossover phase anyway, why not choose one that actually will improve fitness or maybe don't cross at all?
Optional Comment to Consider : Although your iterative construction approach is quite interesting, this may cause you to have an overly complex Gene representation that could be causing problems with your crossover. Is it possible to model a single individual solution as an array (or 2D array) of bits or integers? Even if the array turns out to be very long, it may be worth it use a more simple crossover procedure. I recommend Googling "ga gene representation time tabling" you may find an approach that you like more and can more easily scale to many individuals (100 is a rather small population size for a GA, but I understand you are still testing, also how many generations?).
One final note, I am not sure what language you are working in but if it is Java and you don't NEED to code the GA by hand I would recommend taking a look at ECJ. Maybe even if you have to code by hand, it could help you develop your representation or breeding pipeline.
Newcomers to GA can make any of a number of standard mistakes:
In general, when doing crossover, make sure that the child has some chance of inheriting that which made the parent or parents winner(s) in the first place. In other words, choose a genome representation where the "gene" fragments of the genome have meaningful mappings to the problem statement. A common mistake is to encode everything as a bitvector and then, in crossover, to split the bitvector at random places, splitting up the good thing the bitvector represented and thereby destroying the thing that made the individual float to the top as a good candidate. A vector of (limited) integers is likely to be a better choice, where integers can be replaced by mutation but not by crossover. Not preserving something (doesn't have to be 100%, but it has to be some aspect) of what made parents winners means you are essentially doing random search, which will perform no better than linear search.
In general, use much less mutation than you might think. Mutation is there mainly to keep some diversity in the population. If your initial population doesn't contain anything with a fractional advantage, then your population is too small for the problem at hand and a high mutation rate will, in general, not help.
In this specific case, your crossover function is too complicated. Do not ever put constraints aimed at keeping all solutions valid into the crossover. Instead the crossover function should be free to generate invalid solutions and it is the job of the goal function to somewhat (not totally) penalize the invalid solutions. If your GA works, then the final answers will not contain any invalid assignments, provided 100% valid assignments are at all possible. Insisting on validity in the crossover prevents valid solutions from taking shortcuts through invalid solutions to other and better valid solutions.
I would recommend anyone who thinks they have written a poorly performing GA to conduct the following test: Run the GA a few times, and note the number of generations it took to reach an acceptable result. Then replace the winner selection step and goal function (whatever you use - tournament, ranking, etc) with a random choice, and run it again. If you still converge roughly at the same speed as with the real evaluator/goal function then you didn't actually have a functioning GA. Many people who say GAs don't work have made some mistake in their code which means the GA converges as slowly as random search which is enough to turn anyone off from the technique.

Resources