-3

I just finished spending ~4hours debugging an issue I had with a larger program, and even after fixing it, I still can't figure out why it was causing an issue.

EDIT:

MAIN DIFFERENCES between the two versions.

Version 1 (Wrong):

for (int u=0;u<8;u++){
        for (int v=0;v<8;v++){
            temp += input_data[u][v] * fcosine[x/8][u] * fcosine[x%8][v];
            if (!u){
                temp /= (double) sqrt(2);
            }
            if (!v){
                temp /= (double) sqrt(2);
            }
        }    
    }
    //Produces wrong result
out[x/8][x%8] = temp/4;

CORRECT OUTPUT:

for (int u=0;u<8;u++){
        for (int v=0;v<8;v++){
            temp = input[u][v] * fcosine[x/8][u] * fcosine[x%8][v];
            if (!u){
                temp /= (double) sqrt(2);
            }
            if (!v){
                temp /= (double) sqrt(2);
            }
            sum +=temp;
        }
    }      
out[x/8][x%8] = (sum/4);

Here's the mini version of the code:

#include <cstdlib>
#include<iostream>
#include <math.h>
#define PI 3.1415926535897932384626433832795 // the value of PI
void calculate_idct(double input_data[8][8], double out[8][8], double fcosine[8][8]){
double temp;

for (int x=0;x<=64;x++){
    temp = 0.0;

    for (int u=0;u<8;u++){
        for (int v=0;v<8;v++){
            temp += input_data[u][v] * fcosine[x/8][u] * fcosine[x%8][v];
            if (!u){
                temp /= (double) sqrt(2);
            }
            if (!v){
                temp /= (double) sqrt(2);
            }
        }    
    }
    //Produces wrong result
    out[x/8][x%8] = temp/4;
    }

}

void calculate_idct2(double input[8][8], double out[8][8], double fcosine[8][8]){
double temp, sum;
for (int x =0;x<=64;x++){
    sum = 0;

    for (int u=0;u<8;u++){
        for (int v=0;v<8;v++){
            temp = input[u][v] * fcosine[x/8][u] * fcosine[x%8][v];
            if (!u){
                temp /= (double) sqrt(2);
            }
            if (!v){
                temp /= (double) sqrt(2);
            }
            sum +=temp;
        }
    }

    out[x/8][x%8] = (sum/4);
    }
}

void calculate_dct(double input_data[8][8], double out64[8][8], double fcosine[8][8]) {
unsigned char   u, v, x, y;
double  temp;

// do forward discrete cosine transform
for (u = 0; u < 8; u++)
    for (v = 0; v < 8; v++) {
        temp = 0.0;
        for (x = 0; x < 8; x++)
            for (y = 0; y < 8; y++)
                temp += input_data[x][y] * fcosine[x][u] * fcosine[y][v];
        if ((u == 0) && (v == 0))
            temp /= 8.0;
        else if (((u == 0) && (v != 0)) || ((u != 0) && (v == 0)))
            temp /= (4.0*sqrt(2.0));
        else
            temp /= 4.0;
        out64[u][v] = temp;
        }
}


void make_cosine_tbl(double cosine[8][8]) {
// calculate the cosine table as defined in the formula
for (unsigned char i = 0; i < 8; i++)
    for (unsigned char j = 0; j < 8; j++)
        cosine[i][j] = cos((((2*i)+1)*j*PI)/16);
}

using namespace std;

int main(int argc, char** argv) {

double cosine[8][8];
make_cosine_tbl(cosine);

double input_data[8][8] = {{255, 0, 255, 0, 255, 0, 255, 0},
                    {0, 255, 0, 255, 0, 255, 0, 255},
                    {255, 0, 255, 0, 255, 0, 255, 0},
                    {0, 255, 0, 255, 0, 255, 0, 255},
                    {255, 0, 255, 0, 255, 0, 255, 0},
                    {0, 255, 0, 255, 0, 255, 0, 255},
                    {255, 0, 255, 0, 255, 0, 255, 0},
                    {0, 255, 0, 255, 0, 255, 0, 255} };

double out64[8][8];        

calculate_dct(input_data, out64, cosine);

double out5[8][8];

cout << "Input" << endl;
for (int i = 0;i<8;i++){
    for (int j=0;j<8;j++){
        cout << input_data[i][j] << " ";
    }
    cout << endl;
}

cout << "\n Version 1 \n " << endl;
calculate_idct(out64,out5,cosine);
for (int i = 0;i<8;i++){
    for (int j=0;j<8;j++){
        cout << out5[i][j] << " ";
    }
    cout << endl;
}



cout << "\n Version 2 \n " << endl;
calculate_idct2(out64,out5,cosine);
for (int i = 0;i<8;i++){
    for (int j=0;j<8;j++){
        cout << out5[i][j] << " ";
    }
    cout << endl;
    }


}

Here's the output:

 Version 1 

60.7617 -58.7695 60.7617 -58.7695 60.7617 -58.7695 60.7617 -58.7695 
-116.404 118.396 -116.404 118.396 -116.404 118.396 -116.404 118.396 
135.3 -133.308 135.3 -133.308 135.3 -133.308 135.3 -133.308 
-139.93 141.922 -139.93 141.922 -139.93 141.922 -139.93 141.922 
141.922 -139.93 141.922 -139.93 141.922 -139.93 141.922 -139.93 
-133.308 135.3 -133.308 135.3 -133.308 135.3 -133.308 135.3 
118.396 -116.404 118.396 -116.404 118.396 -116.404 118.396 -116.404 
-58.7695 60.7617 -58.7695 60.7617 -58.7695 60.7617 -58.7695 60.7617 

 Version 2 

255 -1.42109e-14 255 -7.10543e-15 255 2.13163e-14 255 -7.10543e-14 
3.55271e-15 255 -1.13687e-13 255 -9.9476e-14 255 1.7053e-13 255 
255 -5.68434e-14 255 0 255 -2.84217e-14 255 -1.91847e-13 
6.39488e-14 255 0 255 -5.68434e-14 255 1.56319e-13 255 
255 -5.68434e-14 255 -5.68434e-14 255 -2.84217e-14 255 -1.27898e-13 
7.10543e-15 255 0 255 0 255 2.13163e-13 255 
255 2.98428e-13 255 2.55795e-13 255 2.13163e-13 255 1.52767e-13 
3.55271e-15 255 -4.9738e-14 255 -2.84217e-14 255 1.74083e-13 255 

Version 2 is right, but Version 1 is no where close to being correct.

I got the program working, but I am curious as to why there was such a big difference.

M.M
  • 138,810
  • 21
  • 208
  • 365
The Muffin Boy
  • 314
  • 4
  • 14
  • 5
    You know that c and c++ are different languages, don't you? Also, your code is to ugly to read it. Format it with more whitespace and try to nest less `for` loops use functions for that instead and one might find the problem. But as it is it's too hard to find the problem and it seems to be caused by a typo or something similar, so no interest for now. – Iharob Al Asimi Feb 16 '16 at 01:11
  • What is the problem? SO is no debugging service. – too honest for this site Feb 16 '16 at 01:14
  • And this is not C code! Use correct tags! – too honest for this site Feb 16 '16 at 01:35
  • My apologizes, Didn't realized I used C instead of C++ I also went ahead and tried to highlight the differences in my code revisions. I guess like iharob mentioned, there's probably a typo somewhere. – The Muffin Boy Feb 16 '16 at 01:45
  • 2
    In the first one you are dividing the entire result so far by sqrt(2) each time... in the second one you are only dividing the piece you are adding in that iteration. (Presumably the second one is the correct algorithm) – M.M Feb 16 '16 at 02:19
  • 1
    `(double) sqrt(2)` might not get what you expected. `sqrt(2.0)` is better, and you should store it in a constant instead of calculating it again and again – phuclv Feb 16 '16 at 02:38

1 Answers1

2
            temp = input[u][v] * fcosine[x][u] * fcosine[y][v];
            //I don't get it at all, but making the above line a 
                //                         += gives the wrong result

Simplified:

temp = 0;
for (i = 1; i < 3; i++) {
  temp = 1;
}
// temp is 1

temp = 0;
for (i = 1; i < 3; i++) {
  temp += 1;
}
// temp is 2

Why would you expect the code to work the same with + and +=?

Also, you are (supposed to be) summing up stuff in temp then dividing it before adding to sum; but if you don't empty out temp in between, your division gets applied multiple times to earlier x and y results:

100 / 4 + 100 / 4

is different from

(100 / 4 + 100) / 4
Amadan
  • 191,408
  • 23
  • 240
  • 301
  • No they should be happening at the same time. Something like: Summation (AxBxC/(ExF)) – The Muffin Boy Feb 16 '16 at 01:49
  • 1
    There is no A, B, C, E or F in your code. Let's name the first iteration `temp` in the correct code after the marked line as `temp1`; second iteration `temp2`. Your `sum` after two iterations is `temp1/sqrt(2) + temp2/sqrt(2)`. In your wrong code, your `temp` in the second iteration is actually `(temp1/sqrt(2) + temp2)/sqrt(2)`. Just follow the code. – Amadan Feb 16 '16 at 02:03