CUDA cusolverDn<t>gesvd()函数认知

2023-11-12

  1. 函数说明
    cusolverDn<t>gesvd()函数用于矩阵的奇异值分解,和Matlab的svd函数对应。

  2. 数学简介

    • 奇异值分解的公式为:

      在这里插入图片描述

      这里用S代表西格玛,即A = U*S*VH。我们的最终目的就是计算出右边三个矩阵。

    • 矩阵尺寸:
      设:A为m行n列的矩阵,则U为m行m列,S为m行n列,VH为n行n列。注:后面三个矩阵的秩和A的秩相等。

    • 因为矩阵A、U、S、VH都代表了一次线性变换,又因为公式右边等于左边。所以,我们可以说右面三个矩阵对应的线性变换等价于左边,即将A的线性变换分解为三步,U、S、VH分别代表了旋转、拉伸、旋转

    • U、S、VH求解过程

    • SVD的意义和用途

  3. matlab计算
    对矩阵A做svd分解,matlab代码如下:

    % 生成矩阵A
    A = [
        1 2
        2 5
        3 6
    ] + [
        0i 3i
        -3i 0i
        -5i -2i
    ];
    % svd分解
    [U,S,V] = svd(A);
    % 打印结果
    A       %原矩阵
    S       %奇异值
    U       %左奇异向量
    VH = V' %右奇异向量的共轭转置(这样打印为了和CUDA比较)
    

    matlab执行结果:

    A =
       1.0000 + 0.0000i   2.0000 + 3.0000i
       2.0000 - 3.0000i   5.0000 + 0.0000i
       3.0000 - 5.0000i   6.0000 - 2.0000i
    S =
       11.0864         0
             0    1.7583
             0         0
    U =
      -0.3085 - 0.0443i  -0.7870 - 0.2161i   0.4850 - 0.0398i
      -0.3564 + 0.4239i  -0.3013 - 0.0884i  -0.6875 + 0.3494i
      -0.3575 + 0.6844i   0.4126 - 0.2554i   0.3774 - 0.1612i
    VH =
      -0.6122 + 0.0000i  -0.5453 - 0.5726i
       0.7907 + 0.0000i  -0.4222 - 0.4433i
    
  4. CUDA函数原型(以cuDoubleComplex类型举例)
    cusolverDnZgesvd (

    cusolverStatus_t				//状态值
    cusolverDnZgesvd (				//函数名,D代表稠密矩阵,Z代表双精度复数
        cusolverDnHandle_t handle,	//句柄,上下文相关,估计和FILE指针类似
        signed char jobu,			//U的保存方式。'A'-all,不化简,以m行m列保存,不论A是否满秩;'S'-simplify,化简;
        signed char jobvh,			//同jobu
        int m,						//A的行数
        int n,						//A的列数
        cuDoubleComplex *A,			//A的指针
        int lda,					//A的主维度
        double *S,					//S的指针,结果从大到小排序,即S[i]>S[i+1]
        cuDoubleComplex *U,			//U的指针
        int ldu,					//U的主维度
        cuDoubleComplex *VH,		//VH的指针
        int ldvh,					//VH的主维度
        cuDoubleComplex *work,		//工作空间指针,用于函数计算的缓存空间,需要用户申请
        int lwork,					//工作空间的大小,由cusolverDnZgesvd_bufferSize()计算
        double *rwork,				//不知道做啥用的
        int *devInfo				//计算结果标志位,=0时正常
    );
    
  5. 示例代码
    cusolver_utils.h,来自Nvidia官方库。

    /*
     * Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved.
     *
     * Redistribution and use in source and binary forms, with or without
     * modification, are permitted provided that the following conditions
     * are met:
     *  * Redistributions of source code must retain the above copyright
     *    notice, this list of conditions and the following disclaimer.
     *  * Redistributions in binary form must reproduce the above copyright
     *    notice, this list of conditions and the following disclaimer in the
     *    documentation and/or other materials provided with the distribution.
     *  * Neither the name of NVIDIA CORPORATION nor the names of its
     *    contributors may be used to endorse or promote products derived
     *    from this software without specific prior written permission.
     *
     * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
     * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
     * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     */
    
    #pragma once
    
    #include <cmath>
    #include <functional>
    #include <iostream>
    #include <random>
    #include <stdexcept>
    #include <string>
    
    #include <cuComplex.h>
    #include <cuda_runtime_api.h>
    #include <cublas_api.h>
    #include <cusolverDn.h>
    #include <library_types.h>
    
    // CUDA API error checking
    #define CUDA_CHECK(err)                                                                            \
        do {                                                                                           \
            cudaError_t err_ = (err);                                                                  \
            if (err_ != cudaSuccess) {                                                                 \
                printf("CUDA error %d at %s:%d\n", err_, __FILE__, __LINE__);                          \
                throw std::runtime_error("CUDA error");                                                \
            }                                                                                          \
        } while (0)
    
    // cusolver API error checking
    #define CUSOLVER_CHECK(err)                                                                        \
        do {                                                                                           \
            cusolverStatus_t err_ = (err);                                                             \
            if (err_ != CUSOLVER_STATUS_SUCCESS) {                                                     \
                printf("cusolver error %d at %s:%d\n", err_, __FILE__, __LINE__);                      \
                throw std::runtime_error("cusolver error");                                            \
            }                                                                                          \
        } while (0)
    
    // cublas API error checking
    #define CUBLAS_CHECK(err)                                                                          \
        do {                                                                                           \
            cublasStatus_t err_ = (err);                                                               \
            if (err_ != CUBLAS_STATUS_SUCCESS) {                                                       \
                printf("cublas error %d at %s:%d\n", err_, __FILE__, __LINE__);                        \
                throw std::runtime_error("cublas error");                                              \
            }                                                                                          \
        } while (0)
    
    // cublas API error checking
    #define CUSPARSE_CHECK(err)                                                                        \
        do {                                                                                           \
            cusparseStatus_t err_ = (err);                                                             \
            if (err_ != CUSPARSE_STATUS_SUCCESS) {                                                     \
                printf("cusparse error %d at %s:%d\n", err_, __FILE__, __LINE__);                      \
                throw std::runtime_error("cusparse error");                                            \
            }                                                                                          \
        } while (0)
    
    // memory alignment
    #define ALIGN_TO(A, B) (((A + B - 1) / B) * B)
    
    // device memory pitch alignment
    static const size_t device_alignment = 32;
    
    // type traits
    template <typename T> struct traits;
    
    template <> struct traits<float> {
        // scalar type
        typedef float T;
        typedef T S;
    
        static constexpr T zero = 0.f;
        static constexpr cudaDataType cuda_data_type = CUDA_R_32F;
    #if CUDART_VERSION >= 11000
        static constexpr cusolverPrecType_t cusolver_precision_type = CUSOLVER_R_32F;
    #endif
    
        inline static S abs(T val) { return fabs(val); }
    
        template <typename RNG> inline static T rand(RNG &gen) { return (S)gen(); }
    
        inline static T add(T a, T b) { return a + b; }
    
        inline static T mul(T v, double f) { return v * f; }
    };
    
    template <> struct traits<double> {
        // scalar type
        typedef double T;
        typedef T S;
    
        static constexpr T zero = 0.;
        static constexpr cudaDataType cuda_data_type = CUDA_R_64F;
    #if CUDART_VERSION >= 11000
        static constexpr cusolverPrecType_t cusolver_precision_type = CUSOLVER_R_64F;
    #endif
    
        inline static S abs(T val) { return fabs(val); }
    
        template <typename RNG> inline static T rand(RNG &gen) { return (S)gen(); }
    
        inline static T add(T a, T b) { return a + b; }
    
        inline static T mul(T v, double f) { return v * f; }
    };
    
    template <> struct traits<cuFloatComplex> {
        // scalar type
        typedef float S;
        typedef cuFloatComplex T;
    
        static constexpr T zero = {0.f, 0.f};
        static constexpr cudaDataType cuda_data_type = CUDA_C_32F;
    #if CUDART_VERSION >= 11000
        static constexpr cusolverPrecType_t cusolver_precision_type = CUSOLVER_C_32F;
    #endif
    
        inline static S abs(T val) { return cuCabsf(val); }
    
        template <typename RNG> inline static T rand(RNG &gen) {
            return make_cuFloatComplex((S)gen(), (S)gen());
        }
    
        inline static T add(T a, T b) { return cuCaddf(a, b); }
        inline static T add(T a, S b) { return cuCaddf(a, make_cuFloatComplex(b, 0.f)); }
    
        inline static T mul(T v, double f) { return make_cuFloatComplex(v.x * f, v.y * f); }
    };
    
    template <> struct traits<cuDoubleComplex> {
        // scalar type
        typedef double S;
        typedef cuDoubleComplex T;
    
        static constexpr T zero = {0., 0.};
        static constexpr cudaDataType cuda_data_type = CUDA_C_64F;
    #if CUDART_VERSION >= 11000
        static constexpr cusolverPrecType_t cusolver_precision_type = CUSOLVER_C_64F;
    #endif
    
        inline static S abs(T val) { return cuCabs(val); }
    
        template <typename RNG> inline static T rand(RNG &gen) {
            return make_cuDoubleComplex((S)gen(), (S)gen());
        }
    
        inline static T add(T a, T b) { return cuCadd(a, b); }
        inline static T add(T a, S b) { return cuCadd(a, make_cuDoubleComplex(b, 0.)); }
    
        inline static T mul(T v, double f) { return make_cuDoubleComplex(v.x * f, v.y * f); }
    };
    
    template <typename T> void print_matrix(const int &m, const int &n, const T *A, const int &lda);
    
    template <> void print_matrix(const int &m, const int &n, const float *A, const int &lda) {
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                std::printf("%0.2f ", A[j * lda + i]);
            }
            std::printf("\n");
        }
    }
    
    template <> void print_matrix(const int &m, const int &n, const double *A, const int &lda) {
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                std::printf("%0.2f ", A[j * lda + i]);
            }
            std::printf("\n");
        }
    }
    
    template <> void print_matrix(const int &m, const int &n, const cuComplex *A, const int &lda) {
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                std::printf("%0.2f + %0.2fj ", A[j * lda + i].x, A[j * lda + i].y);
            }
            std::printf("\n");
        }
    }
    
    template <>
    void print_matrix(const int &m, const int &n, const cuDoubleComplex *A, const int &lda) {
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                std::printf("%0.2f + %0.2fj ", A[j * lda + i].x, A[j * lda + i].y);
            }
            std::printf("\n");
        }
    }
    
    template <typename T>
    void generate_random_matrix(cusolver_int_t m, cusolver_int_t n, T **A, int *lda) {
        std::random_device rd;
        std::mt19937 gen(rd());
        std::uniform_real_distribution<typename traits<T>::S> dis(-1.0, 1.0);
        auto rand_gen = std::bind(dis, gen);
    
        *lda = n;
    
        size_t matrix_mem_size = static_cast<size_t>(*lda * m * sizeof(T));
        // suppress gcc 7 size warning
        if (matrix_mem_size <= PTRDIFF_MAX)
            *A = (T *)malloc(matrix_mem_size);
        else
            throw std::runtime_error("Memory allocation size is too large");
    
        if (*A == NULL)
            throw std::runtime_error("Unable to allocate host matrix");
    
        // random matrix and accumulate row sums
        for (int i = 0; i < m; ++i) {
            for (int j = 0; j < n; ++j) {
                T *A_row = (*A) + *lda * i;
                A_row[j] = traits<T>::rand(rand_gen);
            }
        }
    }
    
    // Makes matrix A of size mxn and leading dimension lda diagonal dominant
    template <typename T>
    void make_diag_dominant_matrix(cusolver_int_t m, cusolver_int_t n, T *A, int lda) {
        for (int i = 0; i < std::min(m, n); ++i) {
            T *A_row = A + lda * i;
            auto row_sum = traits<typename traits<T>::S>::zero;
            for (int j = 0; j < n; ++j) {
                row_sum += traits<T>::abs(A_row[j]);
            }
            A_row[i] = traits<T>::add(A_row[i], row_sum);
        }
    }
    
    // Returns cudaDataType value as defined in library_types.h for the string containing type name
    cudaDataType get_cuda_library_type(std::string type_string) {
        if (type_string.compare("CUDA_R_16F") == 0)
            return CUDA_R_16F;
        else if (type_string.compare("CUDA_C_16F") == 0)
            return CUDA_C_16F;
        else if (type_string.compare("CUDA_R_32F") == 0)
            return CUDA_R_32F;
        else if (type_string.compare("CUDA_C_32F") == 0)
            return CUDA_C_32F;
        else if (type_string.compare("CUDA_R_64F") == 0)
            return CUDA_R_64F;
        else if (type_string.compare("CUDA_C_64F") == 0)
            return CUDA_C_64F;
        else if (type_string.compare("CUDA_R_8I") == 0)
            return CUDA_R_8I;
        else if (type_string.compare("CUDA_C_8I") == 0)
            return CUDA_C_8I;
        else if (type_string.compare("CUDA_R_8U") == 0)
            return CUDA_R_8U;
        else if (type_string.compare("CUDA_C_8U") == 0)
            return CUDA_C_8U;
        else if (type_string.compare("CUDA_R_32I") == 0)
            return CUDA_R_32I;
        else if (type_string.compare("CUDA_C_32I") == 0)
            return CUDA_C_32I;
        else if (type_string.compare("CUDA_R_32U") == 0)
            return CUDA_R_32U;
        else if (type_string.compare("CUDA_C_32U") == 0)
            return CUDA_C_32U;
        else
            throw std::runtime_error("Unknown CUDA datatype");
    }
    
    // Returns cusolverIRSRefinement_t value as defined in cusolver_common.h for the string containing
    // solver name
    cusolverIRSRefinement_t get_cusolver_refinement_solver(std::string solver_string) {
        if (solver_string.compare("CUSOLVER_IRS_REFINE_NONE") == 0)
            return CUSOLVER_IRS_REFINE_NONE;
        else if (solver_string.compare("CUSOLVER_IRS_REFINE_CLASSICAL") == 0)
            return CUSOLVER_IRS_REFINE_CLASSICAL;
        else if (solver_string.compare("CUSOLVER_IRS_REFINE_GMRES") == 0)
            return CUSOLVER_IRS_REFINE_GMRES;
        else if (solver_string.compare("CUSOLVER_IRS_REFINE_CLASSICAL_GMRES") == 0)
            return CUSOLVER_IRS_REFINE_CLASSICAL_GMRES;
        else if (solver_string.compare("CUSOLVER_IRS_REFINE_GMRES_GMRES") == 0)
            return CUSOLVER_IRS_REFINE_GMRES_GMRES;
        else
            printf("Unknown solver parameter: \"%s\"\n", solver_string.c_str());
    
        return CUSOLVER_IRS_REFINE_NOT_SET;
    }
    
    

    cusolver_gesvd_example.cu,参考官方库编写。

    #include <cstdio>
    #include <cstdlib>
    #include <vector>
    #include <cuda_runtime.h>
    #include <cusolverDn.h>
    #include "cusolver_utils.h"
    
    void print_matrix(const int &m, const int &n, const cuDoubleComplex *A, const int &ldx);
    
    /* matlab矩阵A为:
        1.0000 + 0.0000i   2.0000 + 3.0000i
        2.0000 - 3.0000i   5.0000 + 0.0000i
        3.0000 - 5.0000i   6.0000 - 2.0000i
    
        gesvd中应该对应A的转置(非共轭转置),内存中存储顺序如下:
        1.0000 + 0.0000i   2.0000 - 3.0000i   3.0000 - 5.0000i    2.0000 + 3.0000i   5.0000 + 0.0000i   6.0000 - 2.0000i
    */
    // 输入矩阵A应为列存储格式,即matlab中A.'
    const int m = 3;   //矩阵行
    const int n = 2;   //矩阵列
    const int lda = m; /* lda >= m */
    const std::vector<cuDoubleComplex> h_A = {        //列存储
        {1, 0}, {2, -3}, {3, -5},
        {2, 3}, {5, 0}, {6, -2},
    };
    
    
    int main(int argc, char *argv[]) {    
        // 步骤1:创建句柄
        cusolverDnHandle_t cusolverH = NULL;
        CUSOLVER_CHECK(cusolverDnCreate(&cusolverH));
    
        // 步骤2:申请空间
        cuDoubleComplex *A = nullptr;
        double *S = nullptr;
        cuDoubleComplex *U = nullptr;       // 左奇异矩阵
        cuDoubleComplex *VH = nullptr;      // 又奇异矩阵的复共轭转置
        const int ldu = m;                  // 根据公式,U为m行m列的方阵
        const int ldvh = n;                 // 根据公式,VH为n行n列的仿真
        cuDoubleComplex *W = nullptr;       // W = S*VH 没看懂啥意思
        int *devInfo = nullptr;             // 函数运行状态返回值
        int lwork = 0;                      // 工作空间大小
        cuDoubleComplex *Work = nullptr;    // 工作空间指针
        double *rwork = nullptr;
        CUDA_CHECK(cudaMallocManaged(reinterpret_cast<void **>(&A), sizeof(cuDoubleComplex) * m * n));
        CUDA_CHECK(cudaMallocManaged(reinterpret_cast<void **>(&S), sizeof(double) * n));
        CUDA_CHECK(cudaMallocManaged(reinterpret_cast<void **>(&U), sizeof(cuDoubleComplex) * ldu * n));
        CUDA_CHECK(cudaMallocManaged(reinterpret_cast<void **>(&VH), sizeof(cuDoubleComplex) * ldvh * n));
        CUDA_CHECK(cudaMallocManaged(reinterpret_cast<void **>(&W), sizeof(cuDoubleComplex) * lda * n));
        CUDA_CHECK(cudaMallocManaged(reinterpret_cast<void **>(&devInfo), sizeof(int)));
        CUSOLVER_CHECK(cusolverDnZgesvd_bufferSize(cusolverH, m, n, &lwork));
        CUDA_CHECK(cudaMallocManaged(reinterpret_cast<void **>(&Work), sizeof(cuDoubleComplex) * lwork));
        CUDA_CHECK(cudaMemcpy(A, h_A.data(), sizeof(cuDoubleComplex) * h_A.size(), cudaMemcpyHostToDevice));
        std::printf("A = \n");
        print_matrix(m, n, A, lda);
        std::printf("=====\n");
    
        // 步骤3:SVD计算
        signed char jobu = 'A';  // all m columns of U
        signed char jobvt = 'A'; // all n columns of VH
        CUSOLVER_CHECK(
            cusolverDnZgesvd(
                cusolverH, jobu, jobvt,
                m, n, A, lda,
                S, 
                U, ldu, // ldu
                VH, ldvh, // ldvt,
                Work, lwork, rwork,
                devInfo
            )
        );
        CUDA_CHECK(cudaDeviceSynchronize());
    
        std::printf("after gesvd: *devInfo = %d\n", *devInfo);
        if (0 == *devInfo) {
            std::printf("gesvd converges \n");
        } else if (0 > *devInfo) {
            std::printf("%d-th parameter is wrong \n", -*devInfo);
            exit(1);
        } else {
            std::printf("WARNING: info = %d : gesvd does not converge \n", *devInfo);
        }
    
        std::printf("S = 奇异向量值\n");
        print_matrix(n, 1, S, n);
        std::printf("=====\n");
    
        std::printf("U = 左奇异向量\n");
        print_matrix(m, m, U, ldu);
        std::printf("=====\n");
    
        std::printf("VH = 右奇异向量\n");
        print_matrix(n, n, VH, ldvh);
        std::printf("=====\n");
    
        // 步骤4:释放资源
        CUDA_CHECK(cudaFree(A));
        CUDA_CHECK(cudaFree(U));
        CUDA_CHECK(cudaFree(VH));
        CUDA_CHECK(cudaFree(S));
        CUDA_CHECK(cudaFree(W));
        CUDA_CHECK(cudaFree(devInfo));
        CUDA_CHECK(cudaFree(Work));
        CUDA_CHECK(cudaFree(rwork));
    
        CUSOLVER_CHECK(cusolverDnDestroy(cusolverH));
        CUDA_CHECK(cudaDeviceReset());
    
        return EXIT_SUCCESS;
    }
    
    // 打印矩阵(列存储格式的矩阵)
    void print_matrix(const int &m, const int &n, const cuDoubleComplex *A, const int &ldx) {
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if(A[j * ldx + i].y < 0){
                    if(A[j * ldx + i].x < 0){
                        std::printf("\t-%0.4f - %0.4fj ", -A[j * ldx + i].x, -A[j * ldx + i].y);
                    }else{
                        std::printf("\t %0.4f - %0.4fj ", A[j * ldx + i].x, -A[j * ldx + i].y);
                    }
                    
                }else{
                    if(A[j * ldx + i].x < 0){
                        std::printf("\t-%0.4f + %0.4fj ", -A[j * ldx + i].x, A[j * ldx + i].y);
                    }else{
                        std::printf("\t %0.4f + %0.4fj ", A[j * ldx + i].x, A[j * ldx + i].y);
                    }
                }
            }
            std::printf("\n");
        }
    }
    

    程序运行结果:

    A = 
             1.0000 + 0.0000j        2.0000 + 3.0000j 
             2.0000 - 3.0000j        5.0000 + 0.0000j 
             3.0000 - 5.0000j        6.0000 - 2.0000j 
    =====
    after gesvd: *devInfo = 0
    gesvd converges 
    S = 奇异向量值
    11.09 
    1.76 
    =====
    U = 左奇异向量
            -0.3085 - 0.0443j       -0.7870 - 0.2161j        0.4850 - 0.0398j 
            -0.3564 + 0.4239j       -0.3013 - 0.0884j       -0.6875 + 0.3494j 
            -0.3575 + 0.6844j        0.4126 - 0.2554j        0.3774 - 0.1612j 
    =====
    VH = 右奇异向量
            -0.6122 + -0.0000j      -0.5453 - 0.5726j 
             0.7907 + 0.0000j       -0.4222 - 0.4433j 
    =====
    
  6. 注意

    • gesvd只能计算m>=n的矩阵。
    • gesvd的输出右奇异向量VH而不是V。
    • 工作空间Work,需要用户申请设备内存供函数使用。
    • 奇异值S是按从大到小排序的,即S[i] > S[i+1]。
    • 行存储和列存储为转置关系,matlab表达为A = A.'
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

CUDA cusolverDn<t>gesvd()函数认知 的相关文章

  • “构建”构建我的项目,“构建解决方案”则不构建

    我刚刚开始使用VS2010 我有一个较大的解决方案 已从 VS2008 成功迁移 我已将一个名为 Test 的控制台应用程序项目添加到解决方案中 选择构建 gt 构建解决方案不编译新项目 选择构建 gt 构建测试确实构建了项目 在失败的情况
  • Web 客户端和 Expect100Continue

    使用 WebClient C NET 时设置 Expect100Continue 的最佳方法是什么 我有下面的代码 我仍然在标题中看到 100 continue 愚蠢的 apache 仍然抱怨 505 错误 string url http
  • 在哪里可以找到列出 SSE 内在函数操作的官方参考资料?

    是否有官方参考列出了 GCC 的 SSE 内部函数的操作 即 头文件中的函数 除了 Intel 的 vol 2 PDF 手册外 还有一个在线内在指南 https www intel com content www us en docs in
  • ASP.NET MVC:这个业务逻辑应该放在哪里?

    我正在开发我的第一个真正的 MVC 应用程序 并尝试遵循一般的 OOP 最佳实践 我正在将控制器中的一些简单业务逻辑重构到我的域模型中 我最近一直在阅读一些内容 很明显我应该将逻辑放在域模型实体类中的某个位置 以避免出现 贫血域模型 反模式
  • 查找c中结构元素的偏移量

    struct a struct b int i float j x struct c int k float l y z 谁能解释一下如何找到偏移量int k这样我们就可以找到地址int i Use offsetof 找到从开始处的偏移量z
  • 嵌套接口:将 IDictionary> 转换为 IDictionary>?

    我认为投射一个相当简单IDictionary
  • 使用实体框架模型输入安全密钥

    这是我今天的完美想法 Entity Framework 中的强类型 ID 动机 比较 ModelTypeA ID 和 ModelTypeB ID 总是 至少几乎 错误 为什么编译时不处理它 如果您使用每个请求示例 DbContext 那么很
  • 创建链表而不将节点声明为指针

    我已经在谷歌和一些教科书上搜索了很长一段时间 我似乎无法理解为什么在构建链表时 节点需要是指针 例如 如果我有一个节点定义为 typedef struct Node int value struct Node next Node 为什么为了
  • WCF 中 SOAP 消息的数字签名

    我在 4 0 中有一个 WCF 服务 我需要向 SOAP 响应添加数字签名 我不太确定实际上应该如何完成 我相信响应应该类似于下面的链接中显示的内容 https spaces internet2 edu display ISWG Signe
  • 显示UnityWebRequest的进度

    我正在尝试使用下载 assetbundle统一网络请求 https docs unity3d com ScriptReference Networking UnityWebRequest GetAssetBundle html并显示进度 根
  • 使用 Bearer Token 访问 IdentityServer4 上受保护的 API

    我试图寻找此问题的解决方案 但尚未找到正确的搜索文本 我的问题是 如何配置我的 IdentityServer 以便它也可以接受 授权带有 BearerTokens 的 Api 请求 我已经配置并运行了 IdentityServer4 我还在
  • SolrNet连接说明

    为什么 SolrNet 连接的容器保持静态 这是一个非常大的错误 因为当我们在应用程序中向应用程序发送异步请求时 SolrNet 会表现异常 在 SolrNet 中如何避免这个问题 class P static void M string
  • 覆盖子类中的字段或属性

    我有一个抽象基类 我想声明一个字段或属性 该字段或属性在从该父类继承的每个类中具有不同的值 我想在基类中定义它 以便我可以在基类方法中引用它 例如覆盖 ToString 来表示 此对象的类型为 property field 我有三种方法可以
  • 链接器错误:已定义

    我尝试在 Microsoft Visual Studio 2012 中编译我的 Visual C 项目 使用 MFC 但出现以下错误 error LNK2005 void cdecl operator new unsigned int 2
  • @(t)在Matlab中是什么意思? [复制]

    这个问题在这里已经有答案了 正如标题所示 考虑到下面的上下文 t 在 Matlab 中到底意味着什么 computeNumericalGradient 是一个函数 cofiCostFunc 也是一个接受一堆参数的函数 问题是 t 对 cof
  • 通过指向其基址的指针删除 POD 对象是否安全?

    事实上 我正在考虑那些微不足道的可破坏物体 而不仅仅是POD http en wikipedia org wiki Plain old data structure 我不确定 POD 是否可以有基类 当我读到这个解释时is triviall
  • cmake 将标头包含到每个源文件中

    其实我有一个简单的问题 但找不到答案 也许你可以给我指一个副本 所以 问题是 是否可以告诉 cmake 指示编译器在每个源文件的开头自动包含一些头文件 这样就不需要放置 include foo h 了 谢谢 CMake 没有针对此特定用例的
  • C# 成员变量继承

    我对 C 有点陌生 但我在编程方面有相当广泛的背景 我想做的事情 为游戏定义不同的 MapTiles 我已经像这样定义了 MapTile 基类 public class MapTile public Texture2D texture pu
  • 如何在文本框中插入图像

    有没有办法在文本框中插入图像 我正在开发一个聊天应用程序 我想用图标图像更改值 等 但我找不到如何在文本框中插入图像 Thanks 如果您使用 RichTextBox 进行聊天 请查看Paste http msdn microsoft co
  • C++ 标准是否指定了编译器的 STL 实现细节?

    在写答案时this https stackoverflow com questions 30909296 can you put a pimpl class inside a vector我遇到了一个有趣的情况 这个问题演示了这样一种情况

随机推荐

  • 发现了uroport工具的一个bug,还不知道如何解决

    点击条件属性下的 配置条件 进行配置的 让一个属性等于0的时候控制样式 预览 保存一切正常 等到下次打开这个文件的时候 表示等于的双等号 变成了undefined 如下图 这时候点保存 或者预览 都也点不了 但是不耽误使用 也可以一个一个将
  • Springboot2整合阿里云OSS实现文件上传、下载、删除、查看

    1 阿里云配置 https jingyan baidu com article ea24bc3973db059a63b3316d html 2 pom文件
  • qml基础学习 模型视图(一)

    文章目录 一 理解qml模型和视图 二 效果展示 三 源码分析 1 GridView增删 2 列表 3 卡牌效果 四 相关文章 一 理解qml模型和视图 qt的发展是迅速的 虽然在每一个release版本中或多或少都有bug 但是作为一个庞
  • 组合数学-鸽巢原理

    中国剩余定理证明笔记
  • 传播正能量——做一个快乐的程序员

    引子 今天在博客园看到施瓦小辛格的文章我们搞开发的为什么会感觉到累 顿时有感而发 自己本来不擅长写文章 更不擅长写这种非技术性的文章 但是在思绪喷薄之际 还是止不住有很多话要说 针对从客观上说 搞开发的很累 这种说法 我也来发表一下我的看法
  • Nginx转发,swagger误将upstream作为base url

    在用Nginx转发请求到sprint boot上游服务的时候 有一个配置项 如果处理不好 会导致在swagger里面无法访问API 下面来看一下实例 实例来自VMWare 开源项目Singleton https github com vmw
  • Spring源码学习笔记

    一 Spring启动容器刷新12步 二 Spring循环引用流程图 三 SpringAop执行流程 四 Spring事务的个人理解 Spring事务的使用非常简单 只需要在需要开启事务的方法上加 Transactional rollback
  • 【机器学习实战-14章】利用SVD简化数据

    奇异值分解 Singular Value Decomposition SVD 是提取信息的强大工具 14 1 SVD的应用 优点 简化数据 去除噪声 提高算法的结果 缺点 数据的转换可能难以理解 14 1 1 隐性语义索引 最早的SVD应用
  • python 气泡图练习

    导入了matplotlib pyplot和seaborn模块 以及gapminder数据集 它从gapminder数据集中选择了2007年的数据 并创建了一个散点图 其中x轴表示人均GDP y轴表示预期寿命 气泡的大小表示人口规模 图例被关
  • BurpSuite之Intruder模块学习篇

    BurpSuite介绍 BurpSuite介绍 Intruder模块 该模块重要用于完成对Web应用程序自动化攻击 也就是我们经常说的爆破 下面我们以爆破DVWA靶机的暴力破解页面来介绍该模块的一个个版块 进行演示之前我们先进去把登录密码给
  • c++ 关键字constexpr的使用

    一 想要正确使用constexpr关键字 需要知道编译时常量和运行时常量 1 编译时常量 编译时已知的常量 编译器知道其确切的值 字符串常量 如 123 hello world 等 以常量表达式初始化的const变量 如 const x 2
  • Redis 缓存回收的7种策略volatile设置过期时间及allkeys所有数据范围内

    1 基础说明 当redis设置内存使用限制后 当达到内存限制时 Redis将尝试删除key 控制节点的最大使用内存 redis conf中配置项maxmemory
  • 威马汽车:跃马扬鞭未竟,鞍马劳顿难行?

    活下去 像牲口一样地活下去 威马汽车创始人 董事长兼CEO沈晖1月在社交媒体上分享的电影台词 已然成为威马近况的真实写照 来源 新浪微博 威马汽车沈晖Freeman 最近 网上出现了大量关于 威马汽车将实施全员停薪留职 的消息 还有网友发布
  • 将 Matlab 启动文件夹指定为 userpath

    将 Matlab 启动文件夹指定为 userpath 在使用 Matlab 进行编程时 我们可能需要在程序启动时打开一个特定的文件夹 而不是默认的文件夹 这篇文章将介绍如何将 Matlab 的启动文件夹指定为 userpath 首先 让我们
  • C语言编写基于mysql数据库的简单数据管理系统

    系统环境 Ubuntu 14 04 安装mysql数据库 sudo apt get install mysql server mysql client 安装mysql开发包SDK sudo apt get install libmysqlc
  • MySQL必知必会 学习笔记 第二十三章 使用存储过程

    MySQL 5中增加了存储过程的支持 一个操作需要多条SQL语句才能完成时 可以创建存储过程 其中保存一条或多条SQL语句 使用存储过程的理由 1 通过把处理封装在容易使用的单元中 简化复杂的操作 2 所有人都使用同一存储过程代替某复杂操作
  • 剑指 Offer 22. 链表中倒数第k个节点

    简单说两句 CSDN个人主页 后端小知识 GZH 后端小知识 欢迎关注 点赞 收藏 留言 题目 剑指 Offer 22 链表中倒数第k个节点 我们今天来看一道easy的题目吧 这是选自剑指Offer上的一道题 好了 我们一起来看看题意吧 考
  • 前端那些事儿-winter前端公开课

    前端那些事儿 winter前端公开课 黑白棋练习 文末附源码 关于面试和前端职业发展方向 关于面试的问题 前端面试内容 vue nodejs 闭包 面试基于简历 简历写的都是真实的 再向外拓展 面试的东西 如果不知道 尽量把相关的 知道的东
  • 微信小程序:封装上传图片组件

    特点 支持拍照和本地选择 可以限制最多上传几个 支持删除 实时同步选择个数 并在达到限制是隐藏上传入口 自适应布局 自动换行 先看效果 上面0 4是我没及时更新最新图片 其实是自动计算的 使用方式 简单粗暴直接放在外层
  • CUDA cusolverDn<t>gesvd()函数认知

    函数说明 cusolverDn