Work out the overall progress (%) of three nested for loops - c

I have three nested for loops, each of which obviously have a limit. To calculate the progress of any one of the three for loops, all that I need to do is to divide the current iteration by the total number of iterations that the loop will make. However, given that there are three different for loops, how can I work out the overall percentage complete?
int iLimit = 10, jLimit = 24, kLimit = 37;
for (int i = 0; i < iLimit; i++) {
for (int j = 0; j < jLimit; j++) {
for (int k = 0; k < kLimit; k++) {
printf("Percentage Complete = %d", percentage);
}
}
}
I tried the following code, but it reset after the completion of each loop, reaching a percentage greater than 100.
float percentage = ((i + 1) / (float)iLimit) * ((j + 1) / (float)jLimit) * ((k + 1) / (float)kLimit) * 100;

You can easily calculate the "change in percentage per inner cycle"
const double percentChange = 1.0 / iLimit / jLimit / kLimit;
Note, this mathematically equivalent to 1/(iLimit*jLimit*kLimit), however if iLimitjLimitkLimit is sufficiently large, you'll have an overflow and unexpected behavior. It's still possible to have an underflow with the 1.0/... approach, but its far less likely.
int iLimit = 10, jLimit = 24, kLimit = 37;
const double percentChange = 1.0 / iLimit / jLimit / kLimit;
double percentage = 0;
for (int i = 0; i < iLimit; i++) {
for (int j = 0; j < jLimit; j++) {
for (int k = 0; k < kLimit; k++) {
percentage += percentChange;
printf("Percentage Complete = %d\n", (int)(percentage * 100));
}
}
}

If I do understand your question right, then I think the counter variables at each level (i.e. i, j, k) should have a different weightage in the %age formula. Let me explain what I mean: Each increment of j corresponds to kLimit iterations of the innermost loop. So, if you have only one level of nesting (say the outermost loop using i is not present), total number of loop iterations would be kLimit*jLimit and the percentage:
percentage = (100.0 * (j*kLimit + k + 1)) / (float)(kLimit*jLimit)
You got the idea? Its very easy to generalize this concept to the required level of nesting. I hope you can very well figure out the needed equation for your case. Anyways here is the final formula:
percentage = 100.0 * (kLimit * (i * jLimit + j) + k + 1) / (iLimit * jLimit * kLimit)

The total number of loops is iLimit * jLimit * kLimit, and so if you have an incrementing percentage in the inner loop, you can just print
100 * percentage / (iLimit * jLimit * kLimit)
Since you are using %d to print the percentage, you can limit everything to integer calculations. (And it avoids seeing meaningless 'exact' values such as 0.011261 for the first step.)
If you want to see properly rounded values, you can also use this:
printf("Percentage Complete = %d%%\r", (counter*200+iLimit * jLimit * kLimit) /
(2 * iLimit * jLimit * kLimit));
The \r at the end is a small refinement so each line will overprint the previous one.

Try this one:
int iLimit = 10, jLimit = 24, kLimit = 37;
float percentage;
for (int i = 0; i < iLimit; i++) {
for (int j = 0; j < jLimit; j++) {
for (int k = 0; k < kLimit; k++) {
percentage = ((k+1) + j * kLimit + i*jLimit*kLimit)/(float)(iLimit*jLimit*kLimit) * 100;
printf("Percentage Complete = %f\n", percentage);
}
}
}
This solution is very simmilar to the counter incrementation solution posted here.
The advantage for this solution is that I supplied a formula for the counter which depends on the i,j,k and the limits iLimit, jLimit, kLimit:
counter = (k+1) + j * kLimit + i*jLimit*kLimit
This way, you can find out the percentage when you know i, j, k without iterating through the loops.
Thus you can possibly reduce a O(iLimit * jLimit * kLimit) problem to a O(1) problem.

Remember that percentage is parts of 100.
To get 100 you need to do e.g. (iLimit * jLimit * kLimit) / (iLimit * jLimit * kLimit) * 100.
Each iteration of the loop takes 1 / (iLimit * jLimit * kLimit) parts of the whole.
To get the percentage, "simply" do e.g.
float percentage = ++counter / (float) (iLimit * jLimit * kLimit) * 100.0;
Remember to declare and initialize the counter variable before the loops.

Related

I'm designing a guitar tuner through ATmega16p and CodeVisionAVR and i just can't get my code to run

I'm designing a guitar tuner through an atmel mega16 processor and CodeVisionAVR for my university's second project. I have connected a mono jack to the processor's PINA.7 (ADC converter) and GND. I have 7 LEDs (PORTB.0..6) that should turn on through a series of if/elseif based on the frequency of the fundamental of the signal.
I'm taking the fundamental of the signal through a DFT (i know there are faster FTs but our university told us we should use a DFT, they know why) of 800 samples. Out of the 800 samples selected, it calculates the frequency spectrum. Then the next for is used to calculate the absolute value of each frequency, and picks the largest, so it can be a good refrence point for a guitar tuner.
Momentairly, i have included in the main function just a large frequency condition to see if the LED lights up, but it doesn't.
I have tried switching on LEDs from 0 to 6 throughout the code and it seems to stop at F = computeDft();, so i removed the variable, and just let the computeDft(); run, but the next leds did not light up. Is the function never getting called? I have tried the function in Visual Studio with a generated cosine function and it works perfectly. It always detects the fundamental. Why doesn't it work in CVAVR?
#define M_PI 3.1415926f
#define N 800
unsigned char read_adc(void)
{
ADCSRA |= 0x40; //start conversion;
while (ADCSRA&(0x40)); //wait conversion end
return (float)ADCH;
}
typedef struct
{
float re;
float im;
} Complex;
float computeDft()
{
unsigned char x[N] = {0};
float max = 0;
float maxi = 0;
float magnitude = 0;
Complex X1[N] = {0};
int n = N;
int k;
for (n = 0; n < N; ++n)
{
for (k = 0; k < n; k++)
{
x[k] = read_adc();
X1[n].re += x[k] * cos(n * k * M_PI / N);
X1[n].im -= x[k] * sin(n * k * M_PI / N);
}
}
for (k = 0; k < n; k++)
{
magnitude = sqrt(X1[k].re * X1[k].re + X1[k].im * X1[k].im);
if (magnitude > maxi)
{
maxi = magnitude;
max = k;
}
}
return max;
}
/*
* main function of program
*/
void main (void)
{
float F = 0;
Init_initController(); // this must be the first "init" action/call!
#asm("sei") // enable interrupts
LED1 = 1; // initial state, will be changed by timer 1
L0 = 0;
L1 = 0;
L2 = 0;
L3 = 0;
L4 = 0;
L5 = 0;
L6 = 0;
ADMUX = 0b10100111; // set ADC0
ADCSRA = 0b10000111; //set ADEN, precale by 128
while(TRUE)
{
wdogtrig(); // call often else processor will reset ;
F = computeDft();
if (F > 50 && F < 200)
{
L3 = 1;
}
}
}// end main loop
The result i'm trying to achieve is a signal from a phone or a computer (probably a YouTube video of a guy tuning his guitar) is sent through the jack to the processor in the AD converter (PINA.7). The main function calls the computeDft; function, which will ask the read_adc(); to add to x[k] the value of the voltage that is being sent through the cable, then compute it's Dft. The same function then selects the frequency of the fundamental (the one with the highest absolute value), then returns it. Inside the main function, a variable will be assigned the value of the fundamental, and through a series of ifs, it will compare it's value to the standard guitar strings frequencies of 82.6, 110, etc...
1. First of all: just picking the bigger harmonic in DFT, is not good as a tuner, since, depending on the instrument played, overtones may have a larger amplitude. The decent tuner may be done by using e.g. auto-correlation algorithm.
2. I see this line in your project:
wdogtrig(); // call often else processor will reset ;
Why you need the watchdog in the first place? Where it is configured? What timeout it is set for? How you think, how long would it take to perform both nested loops in computeDft()? With a lot of floating point operations inside including calculation of sine and cosine at each step? On a 16MHz 8-bit MCU? I think that will take several seconds at least, so do not use the watchdog at all, or reset it more often.
3. Look at
cos(n * k * M_PI / N);
(by the way, are you sure it is cos(n * k * M_PI / N); not cos(n * k * 2 * M_PI / N);?)
since cos(x) = cos(x + 2 * M_PI), you can see this formula can be expressed as cos((n * k * 2) % (2 * N) * M_PI / N). I.e. you can precalculate all 2*N possible values and put them as a constant table into the flash memory.
4. Look at nested loops in computeDft()
Inside the inner loop, you are calling read_adc() each time!
You want to pick the signal into the buffer once, and then perform DFT over the saved signal. I.e. first you read ADC values into x[k] array:
for (k = 0; k < N; k++)
{
x[k] = read_adc();
}
and only then you perform DFT calculations over it:
for (n = 0; n < N; ++n)
{
for (k = 0; k < n; k++)
{
X1[n].re += x[k] * cos(n * k * M_PI / N);
X1[n].im -= x[k] * sin(n * k * M_PI / N);
}
}
5. Look carefully at two cycles:
for (n = 0; n < N; ++n)
..
X1[n].re += x[k] * cos(n * k * M_PI / N);
X1[n].im -= x[k] * sin(n * k * M_PI / N);
}
Here at each step, you are calculating the value of X1[n], none of the previous X1 values are used.
And another loop below:
for (k = 0; k < n; k++)
{
magnitude = sqrt(X1[k].re * X1[k].re + X1[k].im * X1[k].im);
...
}
here you are calculating the magnitude of X1[k] and no previous of next values of X1 are used. So, you can simply combine them together:
for (n = 0; n < N; ++n)
{
for (k = 0; k < n; k++)
{
X1[n].re += x[k] * cos(n * k * M_PI / N);
X1[n].im -= x[k] * sin(n * k * M_PI / N);
}
magnitude = sqrt(X1[n].re * X1[n].re + X1[n].im * X1[n].im);
if (magnitude > maxi)
{
maxi = magnitude;
max = k;
}
}
Here you can clearly see, you need no reason to store X1[n].re and X1[n].im in any array. Just get rid of them!
for (n = 0; n < N; ++n)
{
float re = 0;
float im = 0;
for (k = 0; k < n; k++)
{
re += x[k] * cos(n * k * M_PI / N);
im -= x[k] * sin(n * k * M_PI / N);
}
magnitude = sqrt(re * re + im * im);
if (magnitude > maxi)
{
maxi = magnitude;
max = k;
}
}
That's all! You have saved 6 KB by removing pointless Complex X1[N] array
6. There is a error in your initialization code:
ADMUX = 0b10100111; // set ADC0
I don't know what is "ATmega16P", I assume it works the same as "ATmega16". So most significant bits of this register, called REFS1 and REFS0 are used to select the reference voltage. Possible values are:
00 - external voltage from AREF pin;
01 - AVCC voltage taken as reference
11 - internal regulator (2.56V for ATmega16, 1.1V for ATmega168PA)
10 is an incorrect value.
7. the guitar output is a small signal, maybe several dozens of millivolts. Also, it is an AC signal, which can be as positive, so negative as well. So, before putting the signal onto MCU's input you have to shift it (otherwise you'll see only the positive half wave) and amplify it.
I.e. it is not enough just to connect jack plug to GND and ADC input, you need some schematics which will make the signal of the appropriate level.
You can google for it. For example this:
(from This project)

Need a formula to calculate (i->0 to n-1 )π(n!/i!)

I need a formula to calculate the expression multiplication of (n!/i!) where i varies from 0 to n-1. So that I can implement it to a Code. trivial way exceed time limit.Any quick suggestions are welcome
x = (n!/i!) = (i+1) * (i+2) * ... * (n)
So, in pseudo-code (doing it in reverse order for increased efficiency):
x = 1;
result = 1;
for (j = n; j > 0; j--) {
x = x * j;
result = result * x; // Or + if you want the sum instead of the product
}
return result;
Note that you may need a bigint representation for x and result as they will overflow quickly.

The outermost for loop does not work as intended

I have been using Ubuntu 12.04 LTS with GCC to compile my the codes for my assignment for a while. However, recently I have run into two issues as follows:
The following code calculates zero for a nonzero value with the second formula is used.
There is a large amount of error in the calculation of the integral of the standard normal distribution from 0 to 5 or larger standard deviations.
How can I remedy these issues? I am especially obsessed with the first one. Any help or suggestion is appreciated. thanks in advance.
The code is as follows:
#include <stdio.h>
#include <math.h>
#include <limits.h>
#include <stdlib.h>
#define N 599
long double
factorial(long double n)
{
//Here s is the free parameter which is increased by one in each step and
//pro is the initial product and by setting pro to be 0 we also cover the
//case of zero factorial.
int s = 1;
long double pro = 1;
//Here pro stands for product.
if (n < 0)
printf("Factorial is not defined for a negative number \n");
else {
while (n >= s) {
pro *= s;
s++;
}
return pro;
}
}
int main()
{
// Since the function given is the standard normal distribution
// probability density function we have mean = 0 and variance = 1.
// Hence we also have z = x; while dealing with only positive values of
// x and keeping in mind that the PDF is symmetric around the mean.
long double * summand1 = malloc(N * sizeof(long double));
long double * summand2 = malloc(N * sizeof(long double));
int p = 0, k, z[5] = {0, 3, 5, 10, 20};
long double sum1[5] = {0}, sum2[5] = {0} , factor = 1.0;
for (p = 0; p <= 4; p++)
{
for (k = 0; k <= N; k++)
{
summand1[k] = (1 / sqrtl(M_PI * 2) )* powl(-1, k) * powl(z[p], 2 * k + 1) / ( factorial(k) * (2 * k + 1) * powl(2, k));
sum1[p] += summand1[k];
}
//Wolfamalpha site gives the same value here
for (k = 0; k <= N; k++)
{
factor *= (2 * k + 1);
summand2[k] = ((1 / sqrtl(M_PI * 2) ) * powl(z[p], 2 * k + 1) / factor);
//printf("%Le \n", factor);
sum2[p] += summand2[k];
}
sum2[p] = sum2[p] * expl((-powl(z[p],2)) / 2);
}
for (p = 0; p < 4; p++)
{
printf("The sum obtained for z between %d - %d \
\nusing the first formula is %Lf \n", z[p], z[p+1], sum1[p+1]);
printf("The sum obtained for z between %d - %d \
\nusing the second formula is %Lf \n", z[p], z[p+1], sum2[p+1]);
}
return 0;
}
The working code without the outermost for loop is
#include <stdio.h>
#include <math.h>
#include <limits.h>
#include <stdlib.h>
#define N 1200
long double
factorial(long double n)
{
//Here s is the free parameter which is increased by one in each step and
//pro is the initial product and by setting pro to be 0 we also cover the
//case of zero factorial.
int s = 1;
long double pro = 1;
//Here pro stands for product.
if (n < 0)
printf("Factorial is not defined for a negative number \n");
else {
while (n >= s) {
pro *= s;
s++;
}
return pro;
}
}
int main()
{
// Since the function given is the standard normal distribution
// probability density function we have mean = 0 and variance = 1.
// Hence we also have z = x; while dealing with only positive values of
// x and keeping in mind that the PDF is symmetric around the mean.
long double * summand1 = malloc(N * sizeof(long double));
long double * summand2 = malloc(N * sizeof(long double));
int k, z = 3;
long double sum1 = 0, sum2 = 0, pro = 1.0;
for (k = 0; k <= N; k++)
{
summand1[k] = (1 / sqrtl(M_PI * 2) )* powl(-1, k) * powl(z, 2 * k + 1) / ( factorial(k) * (2 * k + 1) * powl(2, k));
sum1 += summand1[k];
}
//Wolfamalpha site gives the same value here
printf("The sum obtained for z between 0-3 using the first formula is %Lf \n", sum1);
for (k = 0; k <= N; k++)
{
pro *= (2 * k + 1);
summand2[k] = ((1 / sqrtl(M_PI * 2) * powl(z, 2 * k + 1) / pro));
//printf("%Le \n", pro);
sum2 += summand2[k];
}
sum2 = sum2 * expl((-powl(z,2)) / 2);
printf("The sum obtained for z between 0-3 using the second formula is %Lf \n", sum2);
return 0;
}
I'm quite certain that the problem is in factor not being set back to 1 in the outer loop..
factor *= (2 * k + 1); (in the loop that calculates sum2.)
In the second version provided the one that works it starts with z=3
However in the first loop since you do not clear it between iterations on p by the time you reach z[2] it already is a huge number.
EDIT: Possible help with precision..
Basically you have a huge number powl(z[p], 2 * k + 1) divided by another huge number factor. huge floating point numbers lose their precision. The way to avoid that is to perform the division as soon as possible..
Instead of first calculating powl(z[p], 2 * k + 1) and dividing by factor :
- (z[p]z[p] ... . * z[p]) / (1*3*5*...(2*k+1))`
rearrange the calculation: (z[p]/1) * (z[p]^2/3) * (z[p]^2/5) ... (z[p]^2/(2*k+1))
You can do this in sumand2 calculation and a similar trick in summand1

complexity for a nested loop with varying internal loop

Very similar complexity examples. I am trying to understand as to how these questions vary. Exam coming up tomorrow :( Any shortcuts for find the complexities here.
CASE 1:
void doit(int N) {
while (N) {
for (int j = 0; j < N; j += 1) {}
N = N / 2;
}
}
CASE 2:
void doit(int N) {
while (N) {
for (int j = 0; j < N; j *= 4) {}
N = N / 2;
}
}
CASE 3:
void doit(int N) {
while (N) {
for (int j = 0; j < N; j *= 2) {}
N = N / 2;
}
}
Thank you so much!
void doit(int N) {
while (N) {
for (int j = 0; j < N; j += 1) {}
N = N / 2;
}
}
To find the O() of this, notice that we are dividing N by 2 each iteration. So, (not to insult your intelligence, but for completeness) the final non-zero iteration through the loop we will have N=1. The time before that we will have N=a(2), then before that N=a(4)... where 0< a < N (note those are non-inclusive bounds). So, this loop will execute a total of log(N) times, meaning the first iteration we see that N=a2^(floor(log(N))).
Why do we care about that? Well, it's a geometric series which has a nice closed form:
Sum = \sum_{k=0}^{\log(N)} a2^k = a*\frac{1-2^{\log N +1}}{1-2} = 2aN-a = O(N).
If someone can figure out how to get that latexy notation to display correctly for me I would really appreciate it.
You already have the answer to number 1 - O(n), as given by #NickO, here is an alternative explanation.
Denote the number of outer repeats of inner loop by T(N), and let the number of outer loops be h. Note that h = log_2(N)
T(N) = N + N/2 + ... + N / (2^i) + ... + 2 + 1
< 2N (sum of geometric series)
in O(N)
Number 3: is O((logN)^2)
Denote the number of outer repeats of inner loop by T(N), and let the number of outer loops be h. Note that h = log_2(N)
T(N) = log(N) + log(N/2) + log(N/4) + ... + log(1) (because log(a*b) = log(a) + log(b)
= log(N * (N/2) * (N/4) * ... * 1)
= log(N^h * (1 * 1/2 * 1/4 * .... * 1/N))
= log(N^h) + log(1 * 1/2 * 1/4 * .... * 1/N) (because log(a*b) = log(a) + log(b))
< log(N^h) + log(1)
= log(N^h) (log(1) = 0)
= h * log(N) (log(a^b) = b*log(a))
= (log(N))^2 (because h=log_2(N))
Number 2 is almost identical to number 3.
(In 2,3: assuming j starts from 1, not from 0, if this is not the case #WhozCraig giving the reason why it never breaks)

C for/while loop not summing

for (i = 0; i < n; i++)
{
x[i] = (float) (i * step);
k = 5;
sum = 0;
while(k > 0)
{
sum = sum + (1/k) * sin((k*PI*x[i])/5);
k = k - 2;
}
y1[i] = (4/PI)*sum;
y2[i] = 0*(4/PI)*sin((PI*x[i])/5);
}
When debugging for each value of k other than 1 the sum shows as being equal to 0, am I implementing the loop correctly?
EDIT 1:
int k;
double sum;
Since both 1 and k are ints -- 1/k is integer division, its always going to be 0 if k > 1. Therefore nothing is added to sum. You want 1/k to perform floating point division. Try 1.0 / k instead of 1/k.
1/k will give 0. Since it is Integer Division.
You will have to give 1.0/k or 1/(float)k

Resources