multiple if conditions optimisation - c

I am building a simple C project (for arduino) and I have come across this question.It's not actually that language specific, it's more of an algorithm optimisation thing.
So, I need to check a value of X against a sensor reading.
If X <5 ...
else if x<10...
else if x<15...
else if x<20...
Then in each clause I have the same for loop,but the iterations change depending on the value of X.
In a general sense, how can these if conditions be replaced by something unified?I remember these "gradation" or "leveling" problems in highschool, but we still used if clauses.

In a comment below you've said (in reference to the second solution under the bar using an array):
I actually do not need the second dimension,as the value ranges are defined in the first dimension/column (5 10 15 20 etc)
In that case, it's really much simpler than the solutions below:
int loops = ((X / 5) + 1) * 5;
...assuming X is an int. That uses integer division, which truncates (e.g., 4 / 5 is 0), adds one, then multiplies the result by 5. Here's the same thing in JavaScript just for an on-site example (in JavaScript, since numbers are always floating point, we have to add in a flooring method, but you don't need that in Java):
var X;
for (X = 0; X < 25; ++X) {
var loops = (Math.floor(X / 5) + 1) * 5;
console.log("X = " + X + ", loops = " + loops);
}
Then in each clause I have the same for loop,but the iterations change depending on the value of X.
I'd set a variable to the number of iterations, then put the for loop after the if/else sequence.
int loops;
if (X < 5) {
loops = /*whatever*/;
} else if (X < 10) {
loops = /*whatever*/;
} else if (X < 15) {
loops = /*whatever*/;
// ...and so on...
} else {
loops = /*whatever for the catch-all case*/;
}
for (int i = 0; i < loops; ++i) {
// ...
}
If you're trying to avoid the if/else, if there are only a small number of possible sensor values, you could use a switch instead, which in some languages is compiled to a jump table and so fairly efficient.
If you want to have the ranges held as data rather than in an if/else sequence, you could use an array of values:
int[][] values = {
{5, 500},
{10, 700},
{15, 800},
{20, 1200},
{0, 1500} // 0 is a flag value
};
(There I'm using an array of int[], but it could be a nice clean class instance instead.)
Then loop through the array looking for the first entry where X < entry[0] is true (or where entry[0] is 0, to flag the last entry).
int loops = 0; // 0 will never be used, but the compiler doesn't know that
for (int[] entry : values) {
if (entry[0] == 0 || X < entry[0]) {
loops = entry[1];
break;
}
}
...followed by the for loop using loops.

Since your intervals are products of 5, it may be possible to just divide X by 5 and use the result as index in an array.
const size_t loops[] = {someval, anotherval, ..., lastval};
size_t i, nloops = loops[X / 5];
for (i = 0; i < nloops; i++) {
...
}

Related

I don't know what I'm doing wrong with this Array

I'm trying to separate the numbers of a sequence, and store them all in an array.
For what the little I have seen of C, I am doing nothing wrong, and the program compiles perfectly, but the moment it goes to print the numbers, it just doesn't work.
The explanation of what I'm trying to do is in the end.
long int number;
do
{
number = get_long("number:\n");
}
while (number<1 || number>9999999999999999);
int numbers[16], n;
//We separate the numbers, from right to left
for (long int I=10; I>100000000000000000; I*=10)
{
for (long int J=1; J>100000000000000000; J*=10)
{
for (n=0; n>16; n++)
{
numbers[n]=(number%I)/J;
}
}
}
printf("%i\n", numbers[1]);
It is supposed to accept numbers of 1 digit up until 16 digits, and separate each digit.
For example, if we had 16, it would separate 1 and 6 into two digits, making the 6 the first digit, and the 1 the second, so it would start counting from right to left. It's supposed to store each digit in an array of 16 spaces. Then I would just print the second digit, just to make sure it does work, but when I run it, it just gives me 0; meaning it doesn't work, but I see no problem with it.
It probably is that I'm either too inexperienced, or I don't have the necessary knowledge, to be able to see the problem in the code.
You have incorrect loop termination checks, so the loops are never entered.
After reversing > to <, you end up evaluating the body of the inner loop 16*16*16 = 4096 times even though there are only 16 digits. There should only be one loop of 16 iterations.
A long int is not is only guaranteed to support numbers up to 2,147,483,647. Instead, use one of long long int, int_least64_t or int64_t, or one of their unsigned counterparts.
You were attempting to write the following:
uint64_t mod = 10; // Formerly named I
uint64_t div = 1; // Formerly named J
for (int n=0; n<16; ++n) {
numbers[n] = ( number % mod ) / div;
mod *= 10;
div *= 10;
}
Demo
But that's a bit more complicated than needed. Let's swap the order of the division and modulus.
uint64_t div = 1;
for (int n=0; n<16; ++n) {
numbers[n] = ( number / div ) % 10;
div *= 10;
}
Demo
Finally, we can simplify a bit more if we don't mind clobbering number in the process.
for (int n=0; n<16; ++n) {
numbers[n] = number % 10;
number /= 10;
}
Demo
All of your for loops are using operator> when they should be using operator< instead. Thus the loop conditions are always false (10 is not > than 100000000000000000, 1 is not > than 100000000000000000, 0 is not > than 16), so the loops don't get entered at all, and thus numbers[] is left unfilled.
Fixing that, you still have a logic problem. Think of what the result of (number%I)/J is when number is 16 and I and J are large values. The result of operator/ is typically 0! On some loop iterations, numbers[] gets populated with correct values. But other iterations will then overwrite numbers[] with 0s. Once all of the loops are finished, only the 0s are left.
This Online Demo demonstrates this in action.
If using a long variable, the value ranges are: -2147483648 to 2147483647 (in most C implementations, as noted by #Eric P in comments)
So the expression while (number<1 || number>9999999999999999); (and similar) do not make sense. As a number, number will never approach 9999999999999999. Same for expression: ...J>100000000000000000; J*=10). (and its really moot at this point, but > should be <)
Consider using a string approach:
Using a null terminated char array (C string) to hold initial value, the essential steps are pretty straight forward and could include the following:
char number[17];//room for 16 characters + null terminator
scanf("%16s", number);//string comprised of maximum of 16 digits
len = strlen(number);
int num_array[len];//using VLA
memset(num_array, 0, sizeof num_array);//zero array
for(int i = 0;i < len; i++)
{
if(number[i] < '0' || number[i] > '9') break;//qualify input. Break if non-numeric
num_array = number[i] - '0';
}

Finding derivative of a function stored in a character array

What I need to do is read a file which contains equations. I need to take the derivative of each equation and then write those derivative equations in a different .txt file. I've read all the equations into an array of character arrays and now I don't know what to do once I've stored them into the array. I really don't need help writing the equations into another file; I know I can figure that out.
What I need help on is finding a way to taking the derivative of the functions. The type of equations that are going to be read are not that complicated; they're going to be polynomials that don't need the chain rule or quotient rule. There will be, however, sin x, cos x and tan x. Some sample equations that would be read are.
-2x^2+2x-3
-2x+sinx-3
-x+sin2x-tanx
The trig functions will not have parenthesis and the variable will always be "x".
I just need a push in the right direction, please.
What you're really asking for is a parser.
A parser is basically a set of rules to read those equations and change/read (parse) each of them.
I'd try to iterate over each line of the file, and differentiate it considering you have a specific character set (i.e ^ means power, x is the parameter, etc.);
For example, some pseudo code:
Open the file.
While there's lines to read:
Read a line -
Seperate it by the operands (+,-,/,*)
For each part:
Find the power of x,
Reduce it by one,
...(derivating rules) // no way around, you have to implement each function if you want this to work as others mentioned in the comments.
Reconnect the parts into a string,
Add it to a list.
Print each element of the list.
If you need help translating that into C, just ask for it; I'll happily help you.
What you need to do, by the looks of things, is separate the expression into individual terms so that you can find the derivative of each in turn.
You can define a term as the largest sequence of characters not containing term separators such as (in your examples) + and -.
Hence the terms for your examples are:
-2x^2+2x-3 => 2x^2 2x 3
-2x+sinx-3 => 2x sinx 3
-x+sin2x-tanx => x sin2x tanx
For each term, you then need to evaluate the form of the term. The form will dictate how you create the derivative.
For example, you can detect if it contains a trigonometric function of the form [n]sin[m]x where n and m are optional numbers. To simplify things, you could add in those terms if they're not there, such as sinx becoming 1sin1x (I'll call this the full-form of the term). Being able to assume all subterms are present will greatly ease the derivative calculation.
Let's say the term is sin4x. Expanding that will give you 1sin4x which you can then split into term-multiplier 1, function sin and x-multiplier 4. Then using standard derivative knowledge nsinmx => (n*m)cosmx, this would become 4cos(4x) and that term would be done.
If it doesn't contain a trigonometric function, you can use the same full-form trick to cover all of the power/constant expressions with the following rules in turn:
if it's a constant (all numeric), append x^0 (multiply by 1).
if it ends with x, append ^1, so 4x becomes 4x^1.
if it starts with x, prefix it with 1, so x^3 becomes 1x^3.
Once that's done, you will have a full-form of ax^b and you can then create the derivative (ab)x^(b-1) and post-process it:
if the bit after x is ^0, remove the whole x^0.
if the bit after x is ^1, remove the ^1.
if the bit before the x is 1, remove it.
if the bit before the x is 0, remove the entire term (and preceding term separator, if any).
So, taking a complex combination of your test data:
-2x^2 + 5x + 4sin3x - 3
which can be treated as:
0 - 2x^2 + 5x + 4sin3x - 3
The following actions happen to each term:
0 [0x^1] (derives as) 0, remove it.
2x^2 [2x^2] (derives as) (2*2)x^(2-1) => 4x^1 => 4x
5x [5x^1] (derives as) (5x1)x^(1-1) => 5x^0 => 5
4sin3x [4sin3x] (derives as) 12cos3x
3 [3x^0] (derives as) 0, remove it and preceding '-'
Thus you end up with - 4x + 5 + 12cos3x which, although my calculus education is some thirty years in the past (and I don't think I've used it since, though I will no doubt be using it next year when my eldest hits secondary school), Wolfram Alpha appears to agree with me :-)
This function will parse the text, cut it in to different parts identified by type[i], stores in a structure. It recognizes x, +, -, and numbers. It can be expand it to include other operators etc.
#define maxlen 50
#define idx 0 //X variable
#define idnumber 1 //number
#define idplus 2 //+ sign
#define idminus 3 //- sign
struct foo
{
int type[10];//each type can be a number (idnum), +, -, etc.
int num[10];//if type[i] is number then num[i] identifies that number
int count;//total number of parts
};
void parse_one_line(struct foo *v, const char *s)
{
char buf[maxlen];
memset(buf, 0, maxlen);
int j = 0;
//remove white spaces
for (int i = 0, len = strlen(s); i < len; i++)
{
if (s[i] == ' ') continue;
buf[j] = s[i];
j++;
}
char part[maxlen];
v->count = 0;
for (int i = 0, len = strlen(buf); i < len; i++)
{
char c = buf[i];
if (c == 'x')
{
v->type[v->count] = idx;
v->count++;
}
else if (c == '+')
{
v->type[v->count] = idplus;
v->count++;
}
else if (c == '-')
{
v->type[v->count] = idminus;
v->count++;
}
else if (c >= '0' && c <= '9')
{
int j = 0;
memset(part, 0, maxlen);
for (; i < len; i++)
{
c = buf[i];
if (c >= '0' && c <= '9')
{
part[j] = c;
j++;
}
else
{
break;
}
}
i--;
v->num[v->count] = atoi(part);
v->type[v->count] = idnumber;
v->count++;
}
}
for (int i = 0; i < v->count; i++)
{
switch (v->type[i])
{
case idnumber: printf("%d", v->num[i]); break;
case idx: printf("X"); break;
case idplus: printf("+"); break;
case idminus: printf("-"); break;
default:break;
}
}
printf("\n");
}
int main()
{
struct foo st;
parse_one_line(&st, "-23x + 2 + 2x - 3");
return 0;
}

Losing dependency on loop variables - loop optimization

I have the following nested loop computation:
int aY=a*Y,aX=a*X;
for(int i=0; i<aY; i+=a)
{
for(int j=0; j<aX; j+=a)
{
xInd=i-j+offX;
yInd=i+j+offY;
if ((xInd>=0) && (xInd<X) &&
(yInd>=0) && (yInd<Y) )
{
z=yInd*X+xInd;
//use z
}
}
}
I want to lose the dependency on i,j,xInd and yInd as much as possible. In other words, I want to "traverse" all of the values z receives while running through the loop, but without involving helping variables i,j,xInd and yInd - or at least have a minimal number of computations involved (most importantly to have no multiplications). How can I do that? Other hints to possible ways to make the loop more efficient would be welcome. Thanks!
If we read the question as how to mimimize the number of iterations around the loop, we can take the following approach.
The constraints:
(xInd>=0) && (xInd<X)
(yInd>=0) && (yInd<Y)
allow use to tighten the bound of the for loop. Expanding xInd and yInd gives:
0 <= i - j + offX <= X
0 <= i + j + offY <= Y
Fixing i allows us to rewrite the second loop bounds as:
for(int i=0; i<aY; i+=a) {
int lower = (max(i + offX - X, -i - offY) / a) * a; //factored out for clarity.
int upper = min(i + offX, Y - i -offY);
for(int j=lower; j<=upper; j+=a) {
If you know more about the possible values of offX, offY, a, X and Y further reductions may be possible.
Note that in reality you probably wouldn't want to blindly apply this type of optimisation without profiling first (it may prevent the compiler from doing this for you e.g. gcc graphite).
Use as index
if the value z=yInd*X+xInd is being used to index memory, a bigger win is achieved by ensuring that the memory accesses are sequential to ensure good cache behaviour.
Currently yInd changes for each iteration so poor cache performance will potentially result.
A solution to this issue would be to first compute and store all the indicies, then do all the memory operations in a second pass using these indicies.
int indicies[Y * X];
int index = 0;
for(...){
for(...){
...
indicies[index++] = z;
}
}
// sort indicies
for(int idx = 0; idx < index; idx++){
z = indicies[idx];
//do stuff with z
}
If we assume that offX and offY are 0, and replace your '<'s with '<='s, we can get rid of i and j by doing this:
for (yInd = 0; yInd <= aX + aY; ++yInd)
for (xInd = max(-yInd, -aX); xInd <= min(yInd, aY); ++xInd)

Decrementing while loop in c

Is it possible to decrement the array size in a while loop in C by more than x--. For example, can you decrement an array by a third of the array size with each iteration?
int n = 10;
while (n < 0)
// do something
(round(n/3))-- // this doesn't work, but can this idea be expressed in C?
Thank you for the help!
You can use any expression:
int n = 10;
while (n > 0) // Note change compared with original!
{
// Do something
n = round(n/3.0) - 1; // Note assignment and floating point
}
Note that you can only decrement variables, not expressions.
You could also use a for loop:
for (int n = 10; n > 0; n = round(n/3.0) - 1)
{
// Do something
}
In this case, the sequence of values for n will be the same (n = 10, 2) whether you round using floating point or not, so you could write:
n = n / 3 - 1;
and you'd see the same results. For other upper limits, the sequence would change (n = 11, 3). Both techniques are fine, but you need to be sure you know what you want, that's all.
Yes, it is possible to add or subtract any number to your variable n.
Usually, if you want to do something a very predictable number of times, you would use a for loop; when you aren't sure how many times something will happen, but rather you are testing some sort of condition, you use a while loop.
The rarest loop is a do / while loop, which is only used when you want to execute a loop one time for certain before the first time the while check occurs.
Examples:
// do something ten times
for (i = 0; i < 10; ++i)
do_something();
// do something as long as user holds down button
while (button_is_pressed())
do_something();
// play a game, then find out if user wants to play again
do
{
char answer;
play_game();
printf("Do you want to play again? Answer 'y' to play again, anything else to exit. ");
answer = getchar();
} while (answer == 'y' || answer == 'Y');
There is no array in your code. If you wan't n to have a third of its value on each iteration, you can do n /= 3;. Note that since n is integral then the integral division is applied.
Just like K-Ballo said there is no array in your example code but here is an example with an integer array.
int n = 10;
int array[10];
int result;
// Fill up the array with some values
for (i=0;i<n;i++)
array[i] = i+n;
while(n > 0)
{
// Do something with array
n -= sizeof(array)/3;
}
But be careful in the example code you gave the while loop is checking if n is less than zero. As n is intialised to 10 the while loop will never be executed. I have changed it in my example.

Several basic C questions

I am a person who is trying to learn C, but I got stuck at a few points while doing my projects:
1) How exactly can I implement random integer generation? I have Googled and found the code for 0 to x generation with the code below, yet how about between 2 integers that I decide (like between X and Y)?
int random;
random = random(100);
2) How can I set a variable to NULL in the beginning (like in Java) and manipulate it if it is NULL? For instance I want to achieve the following:
int a = null;
if (a == null){
a = 3;
}
1)
int r = random(Y - X) + X;
2)
Integers can't be null in either C or Java. In C only pointers can be null, represented by pointing them to zero. However, I suggest you don't get into the whole pointer mess before getting the basics down.
1- How exactly can I implement a random integer generation [...]
See FAQ 13.15 and FAQ 13.16 -- the latter explicitly answers this question.
2- How can I set a variable null in the begining
For floats and integral types you assign them to the magic value 0. For pointers you can assign them to 0 (again) or the macro NULL.
To get the range you want (y-x) multiply each random numberby (y-x). To make them start at x and end at y add x to each number (already multiplied by (y-z)). Assume that y > x.
int i;
for (i = 0; i < NrOfNumers; i++)
{
randomNumberSequence[i] = randomNumberSequence[i]*(y-x) + x;
}
In C you often see the following:
int x = -1;
if (x == -1) { x = 3; } else { /* do nothing */ }
This assumes that the value type is actually unsigned or at least that -1 is not a valid value. You also can do:
#define UNINITIALIZED ((int8_t) -128) /* -128 has no inverse with 8-bit */
...
int8_t x = UNINITIALIZED;
if (x == UNINITIALIZED) { x = 3; } else { /* do nothing */ }

Resources