简体   繁体   English

数组通过void函数后未更改

[英]Array not changing after being passed through void function

I've written a program in C to compute the SVD of a matrix, using Jacobi's algorithm. 我已经用Jacobi的算法用C语言编写了一个程序来计算矩阵的SVD。 I've got 3 functions in the program: a function called jacobi_helper which will perform the SVD, a function called jacobi which calls jacobi_helper after initializing a few arrays, and the main function which calls jacobi. 我在程序中有3个函数:一个将执行SVD的名为jacobi_helper的函数,一个在初始化一些数组后调用jacobi_helper的名为jacobi的函数,以及一个调用jacobi的主要函数。

My problem lies in the fact that the SVD seems to be performed correctly while in jacobi_helper but those values don't seem to return to jacobi even though they are passed in a void function. 我的问题在于,在jacobi_helper中SVD似乎可以正确执行,但即使在void函数中传递了这些值,它们似乎也不会返回到jacobi。 In the end I'm trying to print the matrices U and V of an SVD and the vector of singular values, and my confusion arises from the fact that the vector of singular values is able to print well but the matrices are not. 最后,我试图打印SVD的矩阵U和V以及奇异值的向量,而我的困惑来自以下事实:奇异值的向量能够很好地打印,而矩阵却不能。

Here is my code: 这是我的代码:

    #include <stdio.h>
    #include <stdlib.h>
    #include <math.h>

    double dot_product(double *a, double *b, int n){
        double sum = 0;
        for(int i = 0; i < n; i++){
            sum = sum + a[i]*b[i];
        }
        return sum;
    }

    //Right matrix must be transpose of the matrix you want to multiply
    void matrix_multiplication(left, right, output, n)
    int n;
    double left[n][n];
    double right[n][n];
    double output[n][n];
    {
        for(int i = 0; i < n; i++){
            for(int j = 0; j < n; j++){
                output[i][j] = dot_product(left[i], right[j], n);
            }
        }
    }

    void transpose(a, n, a_transpose)
    int n;
    double a[n][n];
    double a_transpose[n][n];
    {

        for(int i = 0; i < n; i++){
            for(int j = 0; j < n; j++){
                a_transpose[i][j] = a[j][i];
            }
        }
    }


    void jacobi_helper(a, n, givens, givens_transpose, s, s_matrix, u, temp_u, u_output, v, temp_v, v_output)
    int n; //Dimension of Matrix
    double a[n][n]; //Input Matrix
    double givens[n][n]; //Givens matrix to be formed in each step
    double givens_transpose[n][n]; //Transpose of Givens Matrix
    double s[n]; //Vector of singular values
    double s_matrix[n][n]; //Matrix containing the singular values.
    double u[n][n]; //U Matrix in SVD. (A = USV)
    double temp_u[n][n]; //Temporary Matrix
    double u_output[n][n];
    double v[n][n];
    double temp_v[n][n];
    double v_output[n][n];
    {
        u = a;


        //Set V to Identity Matrix
        for(int i = 0; i < n; i++){
            for(int j = 0; j < n; j++){
                if(i == j){
                    v[i][j] = 1;
                }
                else{
                    v[i][j] = 0;
                }
            }
        }

        double n_squared = 0;
        double value = 0;
        double epsilon = 0.1;

        for(int i = 0; i < n; i++){
            for(int j = 0; j < n; j++){
                n_squared = n_squared + (u[i][j]*u[i][j]);
            }
        }

        do{
            value = 0;
            for(int i = 0; i < (n-1); i++){
                for(int j = (i+1); j < n; j++){

                    double tmp1 = 0, tmp2 = 0, tmp4 = 0;
                    for(int k = 0; k < n; k++){
                        tmp1 = tmp1 + (u[k][i]*u[k][i]);
                        tmp2 = tmp2 + (u[k][i]*u[k][j]);
                        tmp4 = tmp4 + (u[k][j]*u[k][j]);
                    }

                    double tau = (tmp4 - tmp1)/(2*tmp2);

                    double t;
                    double t1;
                    double t2;

                    t1 = -tau + sqrt(1 + (tau*tau));
                    t2 = -tau - sqrt(1 + (tau*tau));

                    if(fabs(t1) < fabs(t2)){
                        t = t1;
                    }else{
                        t = t2;
                    }

                    double cos = 1/(sqrt(1+(t*t)));
                    double sin = cos*t;


                    //Make Givens Matrix
                    for(int k = 0; k < n; k++){
                        for(int l = 0; l < n; l++){
                            if(k == i && l == i){
                                givens[k][l] = cos;
                            }
                            else if (k == j && l == j){
                                givens[k][l] = cos;
                            }
                            else if ((k == i && l == j) && i < j){
                                givens[k][l] = -sin;
                            }
                            else if ((k == i && l == j) && i > j){
                                givens[k][l] = sin;
                            }
                            else if ((k == j && l == i) && i < j){
                                givens[k][l] = sin;
                            }
                            else if ((k == j && l == i) && i > j){
                                givens[k][l] = -sin;
                            }
                            else if(k == l){
                                givens[k][l] = 1;
                            }
                            else{
                                givens[k][l] = 0;
                            }
                        }
                    }


                    //Set U <- U*Givens
                    matrix_multiplication(u, givens, temp_u, n);
                    u = temp_u;

                    //Set V <- V*Givens
                    matrix_multiplication(v, givens, temp_v, n);
                    v = temp_v;

                    double temp = 0;
                    for(int k = 0; k < n; k++){
                        temp = temp + (u[k][i]*u[k][j]);
                    }
                    value = value + temp*temp;
                }
            }

        }while(sqrt(value) >= (epsilon*epsilon)*(n_squared));

        for(int i = 0; i < n; i++){
            double sing_value = 0;
            for(int k = 0; k < n; k++){
                sing_value = sing_value + (u[k][i]*u[k][i]);
            }
            s[i] = sqrt(sing_value);
            s_matrix[i][i] = 1/sqrt(sing_value);
        }

        matrix_multiplication(u, s_matrix, temp_u, n);
        u = temp_u;

        printf("%.16f  %.16f  %.16f  %.16f\n",u[0][0],u[0][1],u[1][0],u[1][1]);
        printf("%.16f  %.16f  %.16f  %.16f\n",v[0][0],v[0][1],v[1][0],v[1][1]);
        printf("%.16f  %.16f\n\n", s[0], s[1]);
    }


    void jacobi(double *a, int n, double *s, double *u, double *v){
        static double s_matrix[5000000];
        static double givens[5000000];
        static double givens_transpose[5000000];
        static double temp_u[5000000];
        static double temp_v[5000000];
        static double u_output[5000000];
        static double v_output[5000000];


        jacobi_helper(a, n, givens, givens_transpose, s, s_matrix, u, temp_u, u_output, v, temp_v, v_output);
    }

    int main(int argc, const char * argv[]) {
        static double a[4] = {2,2,-1,1};
        int n = 2;
        static double s[2];
        static double u[4];
        static double v[4];


        jacobi(a, n, s, u, v);
        printf("%.16f  %.16f  %.16f  %.16f\n",u[0],u[1],u[2],u[3]);
        printf("%.16f  %.16f  %.16f  %.16f\n",v[0],v[1],v[2],v[3]);
        printf("%.16f  %.16f\n", s[0], s[1]);
        return 0;
    }

So the problem is that when I have the printf statements at the end, s[0] and s[1] are the same in both cases, but u[0] to u[3] and v[0] to v[3] are not the same. 因此,问题在于,当我在最后使用printf语句时,s [0]和s [1]在两种情况下都相同,但是u [0]至u [3]和v [0]至v [3 ]不一样。

From the print statement inside the jacobi_helper function I get (the correct values of): 从jacobi_helper函数内部的print语句中,我得到的正确值:

    u = 1.0000000000000000  0.0000000000000000  0.0000000000000000  1.0000000000000000
    v = 0.7071067811865475  -0.7071067811865475  0.7071067811865475  0.7071067811865475
    s = 2.8284271247461898  1.4142135623730949

But from the main function I get: 但是从主要功能我得到:

    u = 0.0000000000000000  0.0000000000000000  0.0000000000000000  0.0000000000000000
    v = 1.0000000000000000  0.0000000000000000  0.0000000000000000  1.0000000000000000
    s = 2.8284271247461898  1.4142135623730949

Can anyone help with this? 有人能帮忙吗? In case this is useful, the algorithm I was using was Algorithm 6 from this website: http://www.cs.utexas.edu/users/inderjit/public_papers/HLA_SVD.pdf 如果有用,我使用的算法是该网站上的算法6: http : //www.cs.utexas.edu/users/inderjit/public_papers/HLA_SVD.pdf

jacobi_helper is called with the argument double *u , which is a pointer to a memory address where the results may be stored, but the first thing jacobi_helper does is u = a which means: forget that memory address u and use a instead. 使用参数double *u调用jacobi_helper,这是一个指向可能存储结果的内存地址的指针,但是jacobi_helper所做的第一件事是u = a ,这意味着: 忘记该内存地址u并使用a来代替。 You set some values in the array pointed to be the argument v , but later you carry on with v = temp_v . 您在数组中设置了一些指向参数v ,但随后继续使用v = temp_v

An array variable is only a pointer to a memory address, assigning a value to that array variable will replace that memory address by another address. 数组变量只是指向内存地址的指针,为该数组变量分配一个值会将该内存地址替换为另一个地址。 If you want to change the memory pointed to by the array variable, you have do dereference the address. 如果要更改数组变量指向的内存,则必须取消引用地址。

The code 编码

u[0] = 123;
u[1] = 345;
u[2] = 678;

changes the data hold by the memory pointed to by u. 更改由u指向的内存的数据保留。 On the other hand, 另一方面,

u = a;

will just change u, and all subsequent access to u[0] will in fact access the same memory as a[0] . 只会更改u,随后对u[0]所有访问实际上将访问与a[0]相同的内存。

Also the type of the argument double *u and the parameter double u[n][n] do not match. 同样,参数double *u的类型和参数double u[n][n]也不匹配。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM