Backward Analysis of Expression - c

Suppose I have following code segment in C.
i = j = k = 1;
j = (i++) + (++k);
result = i + j + k; //POI
//Expected result = 7
Here, I want to find value of result through backward analysis. When I perform backward analysis, I will go through following expressions in order.
j = (i++) + (++k);
++k;
i++;
i = j = k = 1;
j = k = 1;
k = 1;
During backward analysis I will replace each variable by corresponding expression, whenever it is applicable. But I'm confused how to deal with increment/decrement operations.
My current strategy will produce following result
result = i + j + k
//after j = i++ + ++k
result = (i+(i+(k+1)))+k
//after ++k
result = (i+(i+((k+1)+1)))+(k+1)
//after i++
result = ((i+1)+((i+1)+((k+1)+1)))+(k+1)
//after i = j = k = 1
result = ((1+1)+((1+1)+((k+1)+1)))+(k+1)
//after k = 1
result = (((1+1)+((1+1)+((1+1)+1)))+(1+1))
//Simplifying
result = 9
which is ofcourse not true.
Can anyone help me with this?

I think it should be more like this
result = i + j + k
//after j = X + Y // You didn't analyse ++k and i++ yet
result = i+(X+Y)+k
//after Y = ++k
result = (i+(X+(k+1))+(k+1)
//after X = i++
result = ((i+1)+(i+(k+1))+(k+1)
//after i = j = k = 1
result = ((1+1)+(1+(k+1))+(k+1)
//after k = 1
result = ((1+1)+(1+(1+1))+(1+1)
//Simplifying
result = 7

The thing to notice here is i++ increases after evaluating, not before.
i=j=k=1
++k //happens before expression
//k=2,i=j=1
j = k + i
//k=2,i=1,j=3
i++ //happens after expression
//k=2,i=2,j=3
result = i+ j + k
//result = 7
Your mistake was increasing i before ealuation of j, and then getting j=4, instead of j=3
If you want to analyze it backward, something along the lines of
result = i + j + k
i = i+1 = 1 + 1
//result = (1+1) + j + k
j = i + k
k = k+1 = 1+1
//j = 1 + (1+1)
//result = (1+1) + (1+(1+1)) + (1+1)

I suggest that you first decompose the statements into elementary ones as a compiler would do. For instance, using Frama-C to decompose the statements would give something like:
k = 1;
j = k;
i = j;
tmp = i;
i ++;
k ++;
j = tmp + k;
result = (i + j) + k;
It is then a lot easier to do the analysis.
Consider the sequence stating from the bottom :
// 1 + 1 + 1 + 1 + 1 + 1 + 1
k = 1;
// k + 1 + k + k + 1 + k + 1
j = k;
// j + 1 + j + k + 1 + k + 1
i = j;
// i + 1 + i + k + 1 + k + 1
tmp = i;
// i + 1 + tmp + k + 1 + k + 1
i ++;
// i + tmp + k + 1 + k + 1
k ++;
// i + tmp + k + k
j = tmp + k;
// i + j + k
result = (i + j) + k;
// result ?
Which gives you 7 as expected.

Related

nested loops in a program not sure what is being printed

What will be printed?
Given:
for (int i = 2; i < 4; i++) {
for (int j = 0; j < 4; j += 2) {
System.out.println("i = " + i + ", j = " + j);
}
}
This is something you can easily do yourself through a compiler or even by counting on your fingers. Here is your output:
i = 2, j = 0
i = 2, j = 2
i = 3, j = 0
i = 3, j = 2
If you need to compile anything and you dont have a Java IDE to do so, you can do it online with https://www.tutorialspoint.com/compile_java_online.php

Double sum optimization

Recently I got this question in one of my interviews, which I unfortunately skipped, but I'm very curious to get the answer. Can you help me?
int sum = 0;
int num = 100000000;
for (int i = 0; i < num; i++){
for (int j = 0; j < num; j++ ){
sum += m_DataX[i] * m_DataX[j];
}
}
EDITED: Also I would like to see if it is possible to optimize if we have the following expression for sum:
sum += m_DataX[i] * m_DataY[j];
Simply, square of sum of the numbers.
Why?
Let, an array is, |1|2|3|
Then, the code produces
1*1 + 1*2 + 1*3
2*1 + 2*2 + 2*3
3*1 + 3*2 + 3*3
That is,
(1*1 + 1*2 + 1*3) + (2*1 + 2*2 + 2*3) + (3*1 + 3*2 + 3*3)
=>1(1+2+3) + 2(1+2+3) + 3(1+2+3)
=>(1+2+3)*(1+2+3)
Therefore, the code will be
int tempSum = 0;
for (int i = 0; i < num ; i ++){
tempSum+=m_DataX [i];
}
sum=tempSum*tempSum;
Update:
What if, sum += m_DataX[i]*m_DataY[j]
Let, two arrays are, |1|2|3| and |4|5|6|
Therefore,
1*4 + 1*5 + 1*5
2*4 + 2*5 + 2*6
3*4 + 3*5 + 3*6
=> 1*4 + 2*4 + 3*4 + 1*5 + 2*5 + 3*5 + 1*6 + 2*6 + 3*6
=> (1+2+3)*(4+5+6)
First, instantiate i and j outside the for loop. Then sum of all the elements and compute the square of it that will be your result.
int tempSumX = 0;
int tempSumY = 0;
for (int i = 0; i < num; i++) {
tempSumX += m_deltaX[i];
tempSumY += m_deltaY[i];
}
sum = tempSumX * tempSumY;
For the 2nd case

unswitch while loop optimization in c

I'm having a hard time optimizing the following while loop by means of Loop Unswitching. I have tried applying the example from wiki, however I am having a hard time applying it to a while loop. I have the following code:
int n = 5,
m = 5,
i = 0,
val = 0;
while (i < n ) {
j = 0;
while (j < m ) {
if (i < j ) {
val = val + i ;
}
else if ( j == i ) {
val = val - 1;
}
else {
val = val + j ;
}
j = j + 1;
}
i = i + 1;
}
And have tried unswitching it the following way:
while (i < n ) {
j = 0;
if (i < j ) {
while (j < m ) {
val = val + i;
j = j + 1;
}
}
if ( j == i ) {
while (j < m) {
val = val - 1;
j = j + 1;
}
}
if (i > j) {
while (j < m) {
val = val + j;
j = j + 1;
}
}
i = i + 1;
}
What could I be doing wrong.
Such loops are best unrolled with the help of pencil and paper. You want the sum of the following grid:
0 1 2 3 4 | 5 n
0 -1 0 0 0 0 | 0 0
1 0 -1 1 1 1 | 1 1
2 0 1 -1 2 2 | 2 2
3 0 1 2 -1 3 | 3 3
m 0 1 2 3 -1 | 4 4
The grid can be subdivided into three parts: the diagonal, the upper and lower triangles next to the diagonal in the square part and the rectangular block when n and m differ.
Let's represent the dimension of the grid by means of the square part, k² and the rectangular part, k·r:
k = min(n, m)
r = max(m, n) - k
Now you can see which sums the three parts contribute:
val = 2·∑(k - i - 1)·i # two triangles
+ r·∑(i) # rectangle
- k # diagonal
(All sums run from i = 0; i < n; i++.) This sum can be rearranged to:
val = 2·(k - 1)·∑(i) - 2*∑(i²) + r·(i) - k
= (2·k + r - 2)·∑(i) - 2*∑(i²) - k
This reduces your two nested loops two two independent loops to do the sums of the natural numbers and of their squares. Fortunately, these sums can be expressed by simple relations:
∑(i) = (n - 1)·n / 2
∑(i²) = (2·n - 1)·(n - 1)·n / 6
You now have a constant-time formula for your resulting sum:
int val(int n, int m)
{
int k = (n < m) ? n : m;
int r = ((n > m) ? n : m) - k;
return (2*k + r - 2) * (k - 1) * k / 2
- (2*k - 1) * k * (k - 1) / 3 - k;
}
All this doesn't have anything to do with loop unrolling, of course.
Loop unswitching according to wikipedia is a compiler optimization so I'm a little confused about why you'd need to do this yourself, but I think this is as good as it gets in terms of breaking apart the for..ifs
for (i = 0; i < n; ++i) {
// j < i
for (j = 0; j < i; ++j) {
val = val + j;
}
// j == i
val = val - 1;
// j > i
for (j = i + 1; j < m; ++j) {
val = val + i;
}
}
This is not a loop you can traditionally unswitch because the conditional variable here is the loop variable.

3-D Loop comparison in 7-pt Stencil

I carry out a 7-pt stencil update on two 3-D domains. The first one is 258x130x258and the second one is 130x258x258. Both of them have the same number of elements being updated. In C they are represented as contiguous arrays : a1[258][130][258] and x1[130][258][258]. Simply stated their x-dimension and y-dimension are exchanged but z-dimension (fastest changing index) is equal.
Loop 1:
for(i = 1; i <= 256 ; i++)
for(j = 1; j <= 128 ; j++)
for(k = 1; k <= 256; k++)
a1[i][j][k] = alpha * b1[i][j][k] + (Omega_6) *(b1[i-1][j][k] + b1[i+1][j][k] +
b1[i][j-1][k] + b1[i][j+1][k] +
b1[i][j][k-1] + b1[i][j][k+1] +
c1[i][j][k] * H);
Loop 2:
for(i = 1; i <= 128 ; i++)
for(j = 1; j <= 256 ; j++)
for(k = 1; k <= 256; k++)
x1[i][j][k] = alpha * y1[i][j][k] + (Omega_6) *(y1[i-1][j][k] + y1[i+1][j][k] +
y1[i][j-1][k] + y1[i][j+1][k] +
y1[i][j][k-1] + y1[i][j][k+1] +
z1[i][j][k] * H);
a1, b1, c1 all have same dimensions and x1, y1, z1 have the same dimensions. alpha and Omega_6 are constants. Loop 1 runs 0.5 seconds faster than Loop 2. Why does this happen ?

C pointer to array not assigning value

I'm working on a neural network, so I have very large data structures. Thus I'm using a pointer to an array in the heap. I have an assignment statement that is always assigning 0
Nothing is out of bounds, and everything is type double
The code snippet looks like:
for( j = 0 ; j < NumHidden ; j++ ) { /* compute hidden unit activations */
*(SumH + p + j) = *(WeightIH + 0) ;
for( i = 0 ; i <= NumInput ; i++ ) {
temp1 = *(Input + game + 0 + i) * *(WeightIH + i + j) ;
temp2 = *(Input + game + 1 + i) * *(WeightIH + i + j) ;
*(SumH + p + j) += temp1 - temp2 ;
}
*(Hidden + p + j) = 1.0/(1.0 + exp(-*(SumH + p + j))) ;
}
in gdb I can prove that the values are non-zero:
117 temp1 = *(Input + game + 0 + i) * *(WeightIH + i + j) ;
(gdb) p *Input
$1 = 0.75454545500000003
(gdb) p *WeightIH
$2 = 0.5
(gdb) n
118 temp2 = *(Input + game + 1 + i) * *(WeightIH + i + j) ;
(gdb) p temp1
$3 = 0
...but as you can see, temp1 is equal to zero after the assignment. What am I missing?
UPDATE
per request:
Breakpoint 1, main () at nn.c:117
117 temp1 = *(Input + game + 0 + i) * *(WeightIH + i + j) ;
(gdb) p *(WeightIH + i + j)
$1 = 0.5
(gdb) p *(Input + game + 0 + i)
$2 = 0.75454545500000003
Here is the entire code:
Some psuedocode:
read in all the inputs into a 3d array
define all structures (all are correct, none go out of bounds)
loop number of patterns
loop number of games (this is a sports model)
compute activation values
compute output values
compute error
back propagate
update weights
/*******************************************************************************
* nn.c 1.0 � JOHN BULLINARIA 2004 *
*******************************************************************************/
/* To compile use "cc nn.c -O -lm -o nn" and then run using "./nn" */
/* For explanations see: http://www.cs.bham.ac.uk/~jxb/NN/nn.html */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <math.h>
#include <fcntl.h>
#define NUMPAT 101
#define NUMIN 24
#define NUMHID 100
#define NUMOUT 55
#define rando() ((double)rand()/(RAND_MAX+1))
int main() {
int i, j, k, p, np, op, ranpat[NUMPAT], epoch, game;
int NumPattern = NUMPAT, NumInput = NUMIN, NumHidden = NUMHID, NumOutput = NUMOUT;
double temp1, temp2;
double *Input = (double *)malloc(NumOutput*2*NumInput*sizeof(double));
char line[128];
double num;
FILE *csvFile = fopen("inputs.csv", "r");
int oned_count = 0;
int twod_count = 0;
int threed_count = 0;
int count = 0;
if (csvFile){
char *token;
while (fgets(line, 1024, csvFile)){
token = strtok(&line[0], ",");
while(token){
num = atof(token);
*(Input + oned_count + twod_count + threed_count) = num;
token = strtok(NULL, ",");
threed_count++;
}
count++;
if ((count % 2) == 0){
oned_count++;
}
twod_count++;
if (twod_count == 2){
twod_count = 0;
}
}
fclose(csvFile);
}
double Target[55] = {-5 ,25, -3, 2 ,5 ,17, 10, 10 ,3 ,-8, 11 ,-2, -5, 17 ,4 ,4 ,2 ,12, 5 ,-11 ,-4, -9 ,13, -1, 5 ,7 ,5 ,4, 8 ,12 ,-13 ,-2, 3 ,34, -19 ,6, 7 ,-9 ,14, 4 ,3 ,-17 ,3, 6 ,-5, -2, -1, -7, 11, -1, 15, -7 ,7 ,19, 1};
double *SumH =(double *)malloc(NumPattern*NumHidden*sizeof(double));
double *WeightIH =(double *)malloc(NumInput*NumHidden*sizeof(double));
double *Hidden =(double *)malloc(NumPattern*NumHidden*sizeof(double));
double *SumO =(double *)malloc(NumPattern*NumOutput*sizeof(double));
double *WeightHO =(double *)malloc(NumHidden*NumOutput*sizeof(double));
double *Output =(double *)malloc(NumPattern*NumOutput*sizeof(double));
double *DeltaWeightIH =(double *)malloc(NumInput*NumHidden*sizeof(double));
double *DeltaWeightHO = (double *)malloc(NumHidden*NumOutput*sizeof(double));
double DeltaO[NumOutput];
double SumDOW[NumHidden];
double DeltaH[NumHidden];
double Error, eta = 0.10, alpha = 0.9;
//double temps[24] = {-0.901337 -0.872058 -0.765912 -0.904485 -1.01524 ,-1.00116, -1.02088, -0.849757, -0.777824, -0.967258 ,-1.02125, -0.773202, -0.622447 ,-0.576088 ,-0.76714, -0.741354 ,-0.669561, -0.606497 ,-0.670834 ,-0.85477, -0.980444, -1.00685, -0.0365572, -0.000114586};
for( j = 0 ; j < NumHidden ; j++ ) { /* initialize WeightIH and DeltaWeightIH */
for( i = 0 ; i < NumInput ; i++ ) {
*(DeltaWeightIH + i + j) = 0;
// *(WeightIH + i) = test_weights[i] ;
*(WeightIH + i + j) = .5 ;
}
}
for( k = 0 ; k < NumOutput ; k ++ ) { /* initialize WeightHO and DeltaWeightHO */
for( j = 0 ; j < NumHidden ; j++ ) {
*(DeltaWeightHO + j + k) = 0.0 ;
*(WeightHO + j + k) = 1;
}
}
for( epoch = 0 ; epoch < 500000 ; epoch++) { /* iterate weight updates */
for( p = 0 ; p < NumPattern ; p++ ) { /* randomize order of individuals */
ranpat[p] = p ;
}
for( p = 0 ; p < NumPattern ; p++) {
np = rand() % NUMPAT ;
op = ranpat[p] ;
ranpat[p] = ranpat[np] ;
ranpat[np] = op ;
}
Error = 0.0 ;
for( np = 0 ; np < NumPattern ; np++ ) { /* repeat for all the training patterns */
p = ranpat[np];
for (game = 0; game < 55; game++){
for( j = 0 ; j < NumHidden ; j++ ) { /* compute hidden unit activations */
*(SumH + p + j) = *(WeightIH + 0) ;
for( i = 0 ; i < NumInput ; i++ ) {
temp1 = *(Input + game + 0 + i) * *(WeightIH + i + j) ;
temp2 = *(Input + game + 1 + i) * *(WeightIH + i + j) ;
*(SumH + p + j) += temp1 - temp2 ;
}
*(Hidden + p + j) = 1.0/(1.0 + exp(-*(SumH + p + j))) ;
}
for( k = 0 ; k < NumOutput ; k++ ) { /* compute output unit activations and errors */
*(SumO + p + k) = *(WeightHO + 0 + k) ;
for( j = 0 ; j < NumHidden ; j++ ) {
*(SumO + p + k) += *(Hidden + p + j) * *(WeightHO + j + k) ;
}
*(Output + p + k) = 1.0/(1.0 + exp(-*(SumO + p + k))) ; /* Sigmoidal Outputs */
//*(Output + p + k) = (exp(*(Output + p + k)) - exp(-*(Output + p + k))) / (exp(*(Output + p + k)) + exp(-*(Output + p + k))); //TANH
//*(Output + p + k) = (2.0/(1.0 + exp(-*(SumO + p + k)))) - 1 ; //bipolar sigmoid
//*(Output + p + k) = .5 * (1 + 1.0/(1.0 + exp(-*(SumO + p + k)))) * (1 - 1.0/(1.0 + exp(-*(SumO + p + k)))); //derivative sigmoid
//*(Output + p + k) = .5 * (1 + ((2.0/(1.0 + exp(-*(SumO + p + k)))) - 1)) * (1 - ((2.0/(1.0 + exp(-*(SumO + p + k)))) - 1)); //derivative bioolar sigmoid
/* Output[p][k] = SumO[p][k]; L
ear Outputs */
Error += 0.50 * (Target[game] - *(Output + p + k)) * (Target[game] - *(Output + p + k)) ; /* SSE */
//Error -= ( Target[game] * log( *(Output + p + k) ) + ( 1.0 - Target[k] ) * log( 1.0 - *(Output + p + k) ) ) ;
DeltaO[k] = (Target[game] - *(Output + p + k)) * *(Output + p + k) * (1.0 - *(Output + p + k)) ; /* Sigmoidal Outputs, SSE */
//DeltaO[k] = (exp(Target[game]) - exp(-*(Output + p + k))) / (exp(Target[game]) + exp(-*(Output + p + k)))
//DeltaO[k] = Target[k] - *(Output + p+k);
//DeltaO[k] = Target[game] - *(Output +p + k);
}
for( j = 0 ; j < NumHidden ; j++ ) { /* 'back-propagate' errors to hidden layer */
SumDOW[j] = 0.0 ;
for( k = 0 ; k < NumOutput ; k++ ) {
SumDOW[j] += *(WeightHO + j + k) * DeltaO[k] ;
}
DeltaH[j] = SumDOW[j] * *(Hidden + p + j) * (1.0 - *(Hidden + p + j)) ;
}
for( j = 0 ; j < NumHidden ; j++ ) { /* update weights WeightIH */
*(DeltaWeightIH + 0 + j) = eta * DeltaH[j] + alpha * *(DeltaWeightIH + 0 + j) ;
*(WeightIH + 0 + j) += *(DeltaWeightIH + 0 + j) ;
for( i = 0 ; i < NumInput ; i++ ) {
*(DeltaWeightIH + i + j) = eta * *(Input + game + 0 + i) * DeltaH[j] + alpha * *(DeltaWeightIH + i + j);
*(WeightIH + i + j) += *(DeltaWeightIH + i + j) ;
}
}
for( k = 0 ; k < NumOutput ; k ++ ) { /* update weights WeightHO */
*(DeltaWeightHO + 0 + k) = eta * DeltaO[k] + alpha * *(DeltaWeightHO + 0 + k) ;
*(WeightHO + 0 + k) += *(DeltaWeightHO + 0 + k) ;
for( j = 0 ; j < NumHidden ; j++ ) {
*(DeltaWeightHO + j + k) = eta * *(Hidden + p + j) * DeltaO[k] + alpha * *(DeltaWeightHO + j + k) ;
*(WeightHO + j + k) += *(DeltaWeightHO + j + k) ;
}
}
}
}
//if( epoch%10 == 0 ){
fprintf(stdout, "\nEpoch %-10d : Error = %f\n", epoch, Error) ;
// fprintf(stdout, "\nEpoch %-10d : weight1 example = %f", epoch, *(WeightIH)) ;
printf("Input weights:\n");
printf("-------------------\n");
for (i = 0; i < 24; i++){
printf("%G\n", *(WeightIH + i + 100));
}
printf("Hidden weights:\n");
printf("-------------------\n");
for (i = 0; i < NumHidden; i++){
printf("%G\n", *(WeightHO + i + 55));
}
//}
if( Error < 0.0004 ) break ; /* stop learning when 'near enough' */
}
return 1 ;
}
/*******************************************************************************/
temp1 and temp2 are ints.....
As a rule of thumb, declare variables the innermost scope they are used.
This question baffles me a bit, as I cannot see what is really wrong. I have two ideas to check:
I think the line temp1 = *(Input + game + 0 + i) * *(WeightIH + i + j) ; is correct, but - just for laughs - try to add another set of parentheses:
temp1 = (*(Input + game + 0 + i)) * (*(WeightIH + i + j)) ;
it could be you get memory corruption somewhere before that line (although I don't see where). M.M is right though with all your indexing probably being wrong. Consider how a two-dimensional array is build, and which element you are trying to access - for example *(WeightIH + i + j) is not accessing 'line' i, row 'j' - you need to multiply the row index with the col length (or the other way around, however you like, just consistent): *(WeightIH + i*NumHidden + j). Consider that the row for i = 1 does not start at index 1+0, but after all NumHidden elements of j are done, so it starts at index NumHidden+0, etc. Fix this, and try if the problem goes away.

Resources