以下の行列計算処理のプログラムをコンパイルしました。

```

    #include <stdio.h>
    #include <stdlib.h>
    #include <math.h>
    #include <float.h>
    #include "rc.h"
    #include "memory_manager.h"
    #include "math_utl.h"
    
    /** このファイルの関数のプロトタイプ宣言をしたヘッダファイル **/
    #include "ファイル名.h"
    
    
    /** 可能な限り RC 型の関数を定義すること． **/
    /** ここでは，全ての関数を RC 型としている． **/
    
    static RC mul_matrix_omp_sub(int l, int m, int n, double **A, double **B, double **C,
                                 int i, int j, int k);
    
    
    /* ベクトル vect[n] を確保 */
    RC allocate_vector(int n, double **vect)
    {
        int ii1;
    
        /** 想定外の引数が与えられた場合は ARG_ERROR_RC を返却 **/
        if(n <= 0) return(ARG_ERROR_RC);
    
        /** NULL ポインタのチェックは RC_NULL_CHK() マクロを使用 **/
        RC_NULL_CHK(vect);
    
        /** メモリーの確保には mm_alloc() を使用 **/
        /** azlib には無いかも．malloc() で代用可能 **/
        *vect = mm_alloc(n*sizeof(double));
        RC_NULL_CHK(vect);
    
        for(ii1=0; ii1<n; ii1++) (*vect)[ii1] = 0.0;
    
        return(NORMAL_RC);
    }
    
    
    /* ベクトル vect[n] を解放 */
    RC free_vector(int n, double **vect)
    {
        int ii1;
    
        if(n <= 0) return(ARG_ERROR_RC);
        RC_NULL_CHK(vect);
    
        for(ii1=0; ii1<n; ii1++) (*vect)[ii1] = 0.0;
    
        /** メモリーの解放には mm_free() を使用 **/
        /** azlib には無いかも．free() で代用可能 **/
        RC_TRY( mm_free(*vect) );
        *vect = NULL;
    
        return(NORMAL_RC);
    }
    
    
    /* 行列 matrix[m][n] を確保 */
    RC allocate_matrix(int m, int n, double ***matrix)
    {
        int ii1;
    
        if(m <= 0) return(ARG_ERROR_RC);
        if(n <= 0) return(ARG_ERROR_RC);
        RC_NULL_CHK( matrix );
    
        *matrix = mm_alloc(m*sizeof(double *));
        RC_NULL_CHK( *matrix );
    
        for(ii1=0; ii1<m; ii1++){
            RC_TRY( allocate_vector(n, &((*matrix)[ii1])) );
        }
    
        return(NORMAL_RC);
    }
    
    
    /* 行列 matrix[m][n] を解放 */
    RC free_matrix(int m, int n, double ***matrix)
    {
        int ii1;
    
        if(m <= 0) return(ARG_ERROR_RC);
        if(n <= 0) return(ARG_ERROR_RC);
        RC_NULL_CHK( matrix );
    
        for(ii1=0; ii1<m; ii1++){
            RC_TRY( free_vector(n, &((*matrix)[ii1])) );
        }
    
        RC_TRY( mm_free(*matrix) );
        *matrix = NULL;
    
        return(NORMAL_RC);
    }
    
    
    /* ベクトル vect[n] を fp に出力 */
    RC print_vector(int n, const double vect[])
    {
        int ii1;
    
        if(n <= 0) return(ARG_ERROR_RC);
        RC_NULL_CHK( vect );
    
        for(ii1=0; ii1<n; ii1++){
            /** 出力は全て log_printf() を使用 **/
            /** azlib には無いかも．その場合は fprintf() で代用 **/
            if(ii1 > 0) RC_TRY( log_printf(1, ", ") );
            RC_TRY( log_printf(1, "%15.7e", vect[ii1]) );
        }
        RC_TRY( log_printf(1, "\n") );
    
        return(NORMAL_RC);
    }
    
    
    /* 行列 matrix[m][n] を fp に出力 */
    RC my_print_matrix(int m, int n, double **matrix)
    {
        int ii1;
    
        if(m <= 0) return(ARG_ERROR_RC);
        if(n <= 0) return(ARG_ERROR_RC);
        RC_NULL_CHK( matrix );
    
        for(ii1=0; ii1<m; ii1++){
            RC_TRY( print_vector(n, matrix[ii1]) );
        }
    
        return(NORMAL_RC);
    }
    
    
    /* u[n] と v[n] の内積を product に代入 */
    /** OPTISHAPE-TS のライブラリ(TSlib)内に同じ名前の関数があったので，先頭に my_ を付けた **/
    RC my_inner_product(int n, const double u[], const double v[], double *product)
    {
        int ii1;
    
        if(n <= 0) return(ARG_ERROR_RC);
        RC_NULL_CHK( u );
        RC_NULL_CHK( v );
        RC_NULL_CHK( product );
    
        *product = 0.0;
        for(ii1=0; ii1<n; ii1++) *product = u[ii1]*v[ii1];
    
        return(NORMAL_RC);
    }
    
    
    /* u[m] と v[n] のテンソル積を matrix[m][n] に代入 */
    RC my_tensor_product(int m, const double u[], int n, const double v[], double **matrix)
    {
        int ii1, ii2;
    
        if(m <= 0) return(ARG_ERROR_RC);
        RC_NULL_CHK( u );
        if(n <= 0) return(ARG_ERROR_RC);
        RC_NULL_CHK( v );
        RC_NULL_CHK( matrix );
    
        for(ii1=0; ii1<m; ii1++){
            for(ii2=0; ii2<n; ii2++){
                matrix[ii1][ii2] = u[ii1]*v[ii2];
            }
        }
    
        return(NORMAL_RC);
    }
    
    
    /* matrix[m][n] と u[n] の積を v[m] に代入 */
    RC mul_matrix_vector(int m, int n, double **matrix, const double u[], double v[])
    {
        int ii1, ii2;
    
        if(m <= 0) return(ARG_ERROR_RC);
        if(n <= 0) return(ARG_ERROR_RC);
        RC_NULL_CHK( matrix );
        RC_NULL_CHK( u );
        RC_NULL_CHK( v );
    
        for(ii1=0; ii1<m; ii1++){
            v[ii1] = 0.0;
            for(ii2=0; ii2<n; ii2++){
                v[ii1] += matrix[ii1][ii2]*u[ii2];
            }
        }
    
        return(NORMAL_RC);
    }
    
    
    /* a[l][m] * b[m][n] を c[l][n] に代入 */
    RC mul_matrix1(int l, int m, int n, double **a, double **b, double **c)
    {
        int ii1, ii2, ii3;
        double tmp;
    
        if(l <= 0) return(ARG_ERROR_RC);
        if(m <= 0) return(ARG_ERROR_RC);
        if(n <= 0) return(ARG_ERROR_RC);
        RC_NULL_CHK( a );
        RC_NULL_CHK( b );
        RC_NULL_CHK( c );
    
        for(ii1=0; ii1<l; ii1++){
            for(ii2=0; ii2<n; ii2++){
                tmp = 0.0;
                for(ii3=0; ii3<m; ii3++){
                    tmp += a[ii1][ii3]*b[ii3][ii2];
                }
                c[ii1][ii2] = tmp;
            }
        }
    
        return(NORMAL_RC);
    }
    
    
    /* a[l][m] * b[m][n] を c[l][n] に代入 */
    RC mul_matrix2(int l, int m, int n, double **a, double **b, double **c)
    {
        int ii1, ii2, ii3;
    
        if(l <= 0) return(ARG_ERROR_RC);
        if(m <= 0) return(ARG_ERROR_RC);
        if(n <= 0) return(ARG_ERROR_RC);
        RC_NULL_CHK( a );
        RC_NULL_CHK( b );
        RC_NULL_CHK( c );
    
        for(ii1=0; ii1<l; ii1++){
            for(ii2=0; ii2<n; ii2++) c[ii1][ii2] = 0.0;
            for(ii2=0; ii2<m; ii2++){
                for(ii3=0; ii3<n; ii3++){
                    c[ii1][ii3] += a[ii1][ii2]*b[ii2][ii3];
                }
            }
        }
    
        return(NORMAL_RC);
    }
    
    
    /* a[l][m] * b[m][n] を c[l][n] に代入 */
    RC mul_matrix3(int l, int m, int n, double **a, double **b, double **c)
    {
        int ii1, ii2, ii3;
    
        if(l <= 0) return(ARG_ERROR_RC);
        if(m <= 0) return(ARG_ERROR_RC);
        if(n <= 0) return(ARG_ERROR_RC);
        RC_NULL_CHK( a );
        RC_NULL_CHK( b );
        RC_NULL_CHK( c );
    
        for(ii1=0; ii1<n; ii1++){
            for(ii2=0; ii2<l; ii2++) c[ii2][ii1] = 0.0;
            for(ii2=0; ii2<m; ii2++){
                for(ii3=0; ii3<l; ii3++){
                    c[ii3][ii1] += a[ii3][ii2]*b[ii2][ii1];
                }
            }
        }
    
        return(NORMAL_RC);
    }
    
    
    /* wa*a[n] + wb*b[n] を c[n] に代入 */
    RC wadd_vector(int n, double wa, const double a[], double wb, const double b[], double c[])
    {
        int ii1;
    
        if(n <= 0) return(ARG_ERROR_RC);
        RC_NULL_CHK( a );
        RC_NULL_CHK( b );
        RC_NULL_CHK( c );
    
        for(ii1=0; ii1<n; ii1++){
            c[ii1] = wa*a[ii1] + wb*b[ii1];
        }
    
        return(NORMAL_RC);
    }
    
    
    /* wa*a[m][n] + wb*b[m][n] を c[m][n] に代入 */
    RC wadd_matrix(int m, int n, double wa, double **a, double wb, double **b, double **c)
    {
        int ii1, ii2;
    
        if(m <= 0) return(ARG_ERROR_RC);
        if(n <= 0) return(ARG_ERROR_RC);
        RC_NULL_CHK( a );
        RC_NULL_CHK( b );
        RC_NULL_CHK( c );
    
        for(ii1=0; ii1<m; ii1++){
            for(ii2=0; ii2<n; ii2++){
                c[ii1][ii2] = wa*a[ii1][ii2] + wb*b[ii1][ii2];
            }
        }
    
        return(NORMAL_RC);
    }
    
    
    /* src[m][n] を dest[m][n] にコピー */
    RC my_copy_matrix(int m, int n, double **src, double **dest)
    {
        int ii1, ii2;
    
        if(m <= 0) return(ARG_ERROR_RC);
        if(n <= 0) return(ARG_ERROR_RC);
        RC_NULL_CHK( src );
        RC_NULL_CHK( dest );
    
        for(ii1=0; ii1<m; ii1++){
            for(ii2=0; ii2<n; ii2++){
                dest[ii1][ii2] = src[ii1][ii2];
            }
        }
    
        return(NORMAL_RC);
    }
    
    
    /* [A]{x} = {b} をガウスの消去法で解く */
    /* [A] は上三角行列に変換されるので注意すること */
    /* ピボット選択を省略しているので，対角優位の行列でなければ解けないか */
    /* 精度が劣化する可能性がある． */
    int gauss_solve(int n, double **A, const double b[], double x[])
    {
        int ii1, ii2, ii3;
    
        if(n <= 0) return(ARG_ERROR_RC);
        RC_NULL_CHK( A );
        RC_NULL_CHK( b );
        RC_NULL_CHK( x );
    
        for(ii1=0; ii1<n; ii1++) x[ii1] = b[ii1];
    
        /* 前進消去 */
        for(ii1=0; ii1<n; ii1++){
            double piv = A[ii1][ii1];
            double inv_piv;
    
            if(fabs(piv) < 1.0E20*DBL_MIN) return(CAL_ERROR_RC);  /* 最低限のゼロ割回避 */
            inv_piv = 1.0/piv;
            for(ii2=ii1; ii2<n; ii2++) A[ii1][ii2] *= inv_piv;
            x[ii1] *= inv_piv;
    
            for(ii2=ii1+1; ii2<n; ii2++){
                double tmp = A[ii2][ii1];
    
                for(ii3=ii1; ii3<n; ii3++){
                    A[ii2][ii3] -= tmp*A[ii1][ii3];
                }
                x[ii2] -= tmp*x[ii1];
            }
        }
    
        /* 後退代入 */
        for(ii1=n-1; ii1>=0; ii1--){
            for(ii2=ii1+1; ii2<n; ii2++){
                x[ii1] -= A[ii1][ii2]*x[ii2];
            }
        }
    
        return(NORMAL_RC);
    }
    
    
    /* [A]{x} = {b} をLU分解で解く */
    /* [A] は下三角が[L]，上三角が[U]に変換されるので注意すること */
    /* 返還後の対角項は[L]が有し，[U]の対角項は 1 */
    /* 解法の安定性は gauss_solve() と同じ */
    int LU_solve(int n, double **A, const double b[], double x[])
    {
        int ii1, ii2, ii3;
    
        if(n <= 0) return(ARG_ERROR_RC);
        RC_NULL_CHK( A );
        RC_NULL_CHK( b );
        RC_NULL_CHK( x );
    
        /* LU 分解 */
        for(ii1=0; ii1<n; ii1++){
            double piv = A[ii1][ii1];
            double inv_piv;
    
            if(fabs(piv) < 1.0E20*DBL_MIN) return(CAL_ERROR_RC);  /* 最低限のゼロ割回避 */
            inv_piv = 1.0/piv;
            for(ii2=ii1+1; ii2<n; ii2++) A[ii1][ii2] *= inv_piv;
            for(ii2=ii1+1; ii2<n; ii2++){
                double tmp = A[ii2][ii1];
    
                for(ii3=ii1+1; ii3<n; ii3++){
                    A[ii2][ii3] -= tmp*A[ii1][ii3];
                }
            }
        }
    
        for(ii1=0; ii1<n; ii1++) x[ii1] = b[ii1];
    
        /* 前進，後退代入 */
        for(ii1=0; ii1<n; ii1++){
            double piv;
    
            for(ii2=0; ii2<ii1; ii2++){
                x[ii1] -= A[ii1][ii2]*x[ii2];
            }
            piv = A[ii1][ii1];
            if(fabs(piv) < 1.0E20*DBL_MIN) return(CAL_ERROR_RC);  /* 最低限のゼロ割回避 */
            x[ii1] /= piv;
        }
        for(ii1=n-1; ii1>=0; ii1--){
            for(ii2=ii1+1; ii2<n; ii2++){
                x[ii1] -= A[ii1][ii2]*x[ii2];
            }
        }
    
        return(NORMAL_RC);
    }
    
    
    /* 以下は課題16用 */
    
    /** l, m, n をそれぞれブロック化して，独立して計算させることで，並列化とキャッシュの **/
    /** ヒット率を上げて高速化を行う． **/
    /** BL, BM,, BN は l, m, n それぞれのブロックサイズ **/
    
    #define BL 32
    #define BM 32
    #define BN 32
    
    RC mul_matrix_omp(int l, int m, int n, double **A, double **B, double **C)
    {
        int l_block, m_block, n_block;
        int ii1;
    
        if(l <= 0) return(ARG_ERROR_RC);
        if(m <= 0) return(ARG_ERROR_RC);
        if(n <= 0) return(ARG_ERROR_RC);
        RC_NULL_CHK( A );
        RC_NULL_CHK( B );
        RC_NULL_CHK( C );
    
        /** l, m, n より，ブロック数を計算，ブロックサイズに満たない部分も計算するので **/
        /** それぞれ切り上げる． **/
        l_block = (l + BL -1)/BL;
        m_block = (m + BM -1)/BM;
        n_block = (n + BN -1)/BN;
    
        /** C[][] は最初に初期化しておき，順次加算するしていく． **/
        for(ii1=0; ii1<l; ii1++){
            int ii2;
            for(ii2=0; ii2<n; ii2++){
                C[ii1][ii2] = 0.0;
            }
        }
    
        /** ここで，OpenMP の並列化を行う．**/
        /** 各ブロックの計算時間はスレッド生成のオーバーヘッドより十分大きいと過程し， **/
        /** さらに，ブロックサイズに満たないブロックの計算で，各スレッドの実行時間が **/
        /** 不均一になると予想されるので，dynamic スケジューリングを使用 **/
        /** ループ変数 ii1 はスレッド毎に持つ必要があるので private 変数に指定（念のため） **/
    #pragma omp parallel for private(ii1) schedule(dynamic)
        for(ii1=0; ii1<l_block*n_block; ii1++){
            /** C[][] の各ブロックは行方向(l)，列方向(n)問わず独立して処理できるので **/
            /** l_block*n_block をまとめて並列処理する．比較的大きなスレッド数を同時実行できる．**/
            int ii2;
            for(ii2=0; ii2<m_block; ii2++){
                /** m 方向のブロック化は，キャッシュのヒット率を向上させるため **/
                mul_matrix_omp_sub(l, m, n, A, B, C, ii1/n_block, ii2, ii1%n_block);
            }
        }
    
        return(NORMAL_RC);
    }
    
    
    /* i, j, k は，それぞれ l, m, n 方向のブロックのインデックス **/
    /** A の i,j ブロックと B の j, k ブロックの積を C の i,k ブロックに加算する． **/
    static RC mul_matrix_omp_sub(int l, int m, int n, double **A, double **B, double **C,
                                 int i, int j, int k)
    {
        /** スレッド内で呼び出される関数のローカル変数は，スレッド毎に確保される． **/
        int i_size, j_size, k_size;
        double blockA[BL][BM];
        double blockBt[BN][BM];
        int ii1, ii2, ii3;
    
        /** ブロックサイズは，基本的に BL, BM, BN だが，割り切れない場合に半端なサイズの **/
        /** ブロックを処理する必要があることに注意 **/
        i_size = MIN2(BL, l - i*BL);
        j_size = MIN2(BM, m - j*BM);
        k_size = MIN2(BN, n - k*BN);
    
        /** A の i,j ブロックをコピー **/
        /** この時，後の処理でのメモリーアクセスを考えて転置しておく **/
        for(ii1=0; ii1<i_size; ii1++){
            for(ii2=0; ii2<j_size; ii2++){
                blockA[ii1][ii2] = A[i*BL + ii1][j*BM + ii2];
            }
        }
    
        /** B の j,k ブロックをコピー **/
        for(ii1=0; ii1<j_size; ii1++){
            for(ii2=0; ii2<k_size; ii2++){
                blockBt[ii2][ii1] = B[j*BM + ii1][k*BN + ii2];
            }
        }
    
        if((i_size == BL)&&(j_size == BM)&&(k_size == BN)){
            /** 典型的な場合，ブロックサイズはそれぞれ BL, BM, BN になるので， **/
            /** この部分を特にチューニングする． **/
            /** BL, BN は偶数とし，それぞれのループを2段アンローリング(展開)する． **/
            /** つまり，１回のループ毎に2回分の処理を行って，ループ回数を1/2にする．**/
            for(ii1=0; ii1<BL; ii1+=2){
                for(ii2=0; ii2<BN; ii2+=2){
                    double tmp00 = 0.0;
                    double tmp01 = 0.0;
                    double tmp10 = 0.0;
                    double tmp11 = 0.0;
                    /** 最内側ループはシンプルに記述し，コンパイラにベクトル化させる．**/
                    for(ii3=0; ii3<BM; ii3++){
                        /** 外側のループをアンローリングすることで， **/
                        /** ロード命令4回，ストア命令0回，積演算4回，和演算4回 **/
                        /** となっている．(tmp00,01,10,11はレジスタを使うとして) **/
                        /** アンローリングしない場合は，ロード2回，ストア0回，積1回，和1回 **/
                        /** つまり，(演算回数/メモリーアクセス回数)の比率高めることができる． **/
                        /** アンローリングの段数を大きくするとさらに比率を改善できるが，**/
                        /** 最内側ループで使用するレジスターが不足して逆効果になる． **/
                        /** ここでは，使用するレジスタの総数は8個(tmp00,01,10,11とa0,1とb0,1 **/
                        double a0 = blockA[ii1    ][ii3];
                        double a1 = blockA[ii1 + 1][ii3];
                        double b0 = blockBt[ii2    ][ii3];
                        double b1 = blockBt[ii2 + 1][ii3];
    
                        tmp00 += a0*b0;
                        tmp01 += a0*b1;
                        tmp10 += a1*b0;
                        tmp11 += a1*b1;
                    }
                    C[i*BL + ii1    ][k*BN + ii2    ] += tmp00;
                    C[i*BL + ii1    ][k*BN + ii2 + 1] += tmp01;
                    C[i*BL + ii1 + 1][k*BN + ii2    ] += tmp10;
                    C[i*BL + ii1 + 1][k*BN + ii2 + 1] += tmp11;
                }
            }
        }else{
            /** 中途半端なブロックサイズの場合は，全てここで処理する． **/
            for(ii1=0; ii1<i_size; ii1++){
                for(ii2=0; ii2<k_size; ii2++){
                    double tmp = 0.0;
                    for(ii3=0; ii3<j_size; ii3++){
                        tmp += blockA[ii1][ii3]*blockBt[ii2][ii3];
                    }
                    C[i*BL + ii1][k*BN + ii2] += tmp;
                }
            }
        }
    
        return(NORMAL_RC);
    }
    
```

以下にファイル名.hのコードを示します。

```

    #ifndef ファイル名_H
    #define ファイル名_H
    
    RC allocate_vector(int n, double **vect);
    RC free_vector(int n, double **vect);
    RC allocate_matrix(int m, int n, double ***matrix);
    RC free_matrix(int m, int n, double ***matrix);
    RC print_vector(int n, const double vect[]);
    RC my_print_matrix(int m, int n, double **matrix);
    RC my_inner_product(int n, const double u[], const double v[], double *product);
    RC my_tensor_product(int m, const double u[], int n, const double v[], double **matrix);
    RC mul_matrix_vector(int m, int n, double **matrix, const double u[], double v[]);
    RC mul_matrix1(int l, int m, int n, double **a, double **b, double **c);
    RC mul_matrix2(int l, int m, int n, double **a, double **b, double **c);
    RC mul_matrix3(int l, int m, int n, double **a, double **b, double **c);
    RC wadd_vector(int n, double wa, const double a[], double wb, const double b[], double c[]);
    RC wadd_matrix(int m, int n, double wa, double **a, double wb, double **b, double **c);
    RC my_copy_matrix(int m, int n, double **src, double **dest);
    RC gauss_solve(int n, double **A, const double b[], double x[]);
    RC LU_solve(int n, double **A, const double b[], double x[]);
    
    RC mul_matrix_omp(int l, int m, int n, double **A, double **B, double **C);
    RC mul_matrix_omp2(int l, int m, int n, double **A, double **B, double **C);
    
    #endif /* ファイル名_H */
    
```

コンパイルの結果、以下のようなエラーがでてしまいます。

```

    ファイル名.c:337:5: error: conflicting types for ‘gauss_solve’
     int gauss_solve(int n, double **A, const double b[], double x[])
         ^
    In file included from ファイル名.c:8:0:
    ファイル名.h:19:4: note: previous declaration of ‘gauss_solve’ was here
     RC gauss_solve(int n, double **A, const double b[], double x[]);
        ^
    ファイル名.c:383:5: error: conflicting types for ‘LU_solve’
     int LU_solve(int n, double **A, const double b[], double x[])
         ^
    In file included from ファイル名.c:8:0:
    ファイル名.h:20:4: note: previous declaration of ‘LU_solve’ was here
     RC LU_solve(int n, double **A, const double b[], double x[]);
        ^
    
```

どのように訂正すればよいのか分からず困っております。  
よろしくお願いいたします。
CC BY-SA 4.0
2018-09-15T03:02:38.047
48415
2018-09-16T05:01:09.417
2018-09-16T05:01:09.417
4236
question
c
行列計算処理のプログラムのエラー
「ファイル名.h」中には、各関数のプロトタイプを

```

    RC gauss_solve(int n, double **A, const double b[], double x[]);
    RC LU_solve(int n, double **A, const double b[], double x[]);
    
```

のように戻り値を`RC`型で宣言しているのに、実際の「ファイル名.c」内の関数定義が、それとは異なる、

```

    int gauss_solve(int n, double **A, const double b[], double x[])
    {
        ...
    }
    
    int LU_solve(int n, double **A, const double b[], double x[])
    {
        ...
    }
    
```

と言うことで、「同じ関数なのに異なる戻り値型で宣言されている」ことを「型が衝突している」( ** _conflicting types_**
)と表現しています。

基本的に、ヘッダーファイル内の関数プロトタイプと実際の関数定義の関数見出し部とは完全に一致させてください。

型`RC`がどう定義されているのか不明ですが、「ファイル名.c」の方を以下のように修正して、ヘッダー内のプロトタイプと一致させると良いでしょう。

```

    RC gauss_solve(int n, double **A, const double b[], double x[])
    {
        ...
    }
    
    RC LU_solve(int n, double **A, const double b[], double x[])
    {
        ...
    }
    
```
CC BY-SA 4.0
2018-09-15T03:27:15.057
48417
2018-09-15T03:27:15.057
13972
48415
answer