Fortran Coder

查看: 248|回复: 4
打印 上一主题 下一主题

[线性代数] OpenBLAS在c++、Fortran中效率差距这么大?

[复制链接]

42

帖子

5

主题

0

精华

熟手

F 币
251 元
贡献
100 点
跳转到指定楼层
楼主
发表于 2025-5-8 13:43:21 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
OpenBLAS在c++、Fortran中的差距这么大? 是因为OpenBLAS基于C编写吗?


MinGW 编译生成 BLAS/LAPACK、 OpenBLAS两个库。
g++ gFortran 分别用这两个库,矩阵求逆、乘法等操。 算法完全相同。

运行时间:(秒)
                       G++       GFortran
BLAS/LAPACK      4.0          2.1

OpenBLAS          0.16         1.6



分享到:  微信微信
收藏收藏 点赞点赞 点踩点踩

839

帖子

2

主题

0

精华

大宗师

F 币
3941 元
贡献
2341 点
沙发
发表于 2025-5-9 21:03:29 | 只看该作者
算法完全相同才是问题,不妨搜一下“一只忧郁台湾乌龟”的笑话。c是行优先,fortran是列优先。

134

帖子

11

主题

0

精华

大师

F 币
633 元
贡献
381 点

贡献勋章管理勋章帅哥勋章元老勋章星光勋章规矩勋章

板凳
发表于 2025-5-10 12:53:24 | 只看该作者
“一只忧郁台湾乌龟”的笑话

0. 這不是笑話, 這是"辱"華
1. 由繁入簡, 有其時宜性, 這只是當下30-50年
2. 資訊引領, 往前100-200年, 簡繁何異
3. 中華文化淵遠流長, 上溯1000-2000年, 誰得視?

42

帖子

5

主题

0

精华

熟手

F 币
251 元
贡献
100 点
地板
 楼主| 发表于 6 天前 | 只看该作者
本帖最后由 gps99 于 2025-5-14 18:17 编辑

源码贴上来吧。 应该不是行/列顺序问题,直接用库 未手动行列。

[Fortran] 纯文本查看 复制代码
module inv
contains
    function inverse(A) result(Ainv)
        real(kind=8), dimension(:,:), intent(in) :: A
        real(kind=8), dimension(size(A,1),size(A,2)) :: Ainv
        real(kind=8), dimension(size(A,1)) :: work
        integer, dimension(size(A,1)) :: ipiv 
        integer :: n, info

        print *, "Step 1:: 矩阵求逆中 ... ..."
        !external DGETRF
        !external DGETRI
        Ainv = A
        n = size(A,1)
        call DGETRF(n, n, Ainv, n, ipiv, info)
        if (info /= 0) then
           stop '矩阵是 奇异阵 !'
        end if
        call DGETRI(n, Ainv, n, ipiv, work, n, info)
        if (info /= 0) then
           stop '矩阵求逆 失败 !'
        end if
        print *, "Step 2:: 矩阵相乘中... ..."
    end function inverse   
end module


program MatrixSpeed

    use inv
    implicit none
    real(kind=8), allocatable :: z(:,:), re(:,:)
    integer             :: i, j, n, p
    real(kind=8)        :: u
    real(kind=4)        :: t1, t2

    n = 1500
    p = 1500
    allocate(z(n,p),re(n,n))
    do i=1,n
        do j=1,p
            call random_number(u)
            z(i,j) = u * 3.0
        enddo
    enddo

    ! 随机矩阵求逆,再乘以原矩阵,得到单位阵。
    print *, "N= ", n
    print *, "正在计算... ..."
    call cpu_time(t1)
    re = matmul(z, inverse(z))
    call cpu_time(t2)
    print *, "Time:  ", t2-t1, " 秒"
    do i=1,min(10,n)
        write (*,'(10(f10.4, x))') re(i, 1:min(10,n))
    enddo

end program MatrixSpeed



命令行 分别编译 Lapack、OpenBLAS

gfortran -O3 -o Matrix_for_Lapack.exe Matrix_for_Lapack.f90 -L"D:/CLib/Lapack/lib" -llapack -lblas
gfortran -O3 -o Matrix_for_OpenBLAS.exe Matrix_for_OpenBLAS.f90 -L"D:/CLib/OpenBLAS/lib" -lopenblas

[C++] 纯文本查看 复制代码
#include <iostream>
#include <vector>
#include <random>
#include <ctime>
#include <iomanip>
#include <cblas.h>  // CBLAS 头文件
#include <lapacke.h>  // LAPACKE 头文件

using namespace std;

// 生成 N 维随机方阵
void generate_random_matrix(std::vector<double>& A, int N) {
    std::default_random_engine generator(time(0));
    std::uniform_real_distribution<double> distribution(-1.0, 1.0);

    A.resize(N * N);
    for (int i = 0; i < N * N; ++i) {
        A[i] = distribution(generator);
    }
}


// 求方阵的逆阵
bool inverse_matrix(std::vector<double>& A, int N) {
    std::vector<int> ipiv(N);  // 用于记录主元的位置
    int info = LAPACKE_dgetrf(LAPACK_ROW_MAJOR, N, N, A.data(), N, ipiv.data());  // LU 分解
    if (info != 0) {
        std::cerr << "LU decomposition failed.\n";
        return false;
    }

    info = LAPACKE_dgetri(LAPACK_ROW_MAJOR, N, A.data(), N, ipiv.data());  // 求逆阵
    if (info != 0) {
        std::cerr << "Failed to compute inverse matrix.\n";
        return false;
    }

    return true;
}


// 输出矩阵  前 K 行 K 列
void print_matrix(const std::vector<double>& A, int N, int K) {
    for (int i = 0; i < K; ++i) {
        for (int j = 0; j < K; ++j) {
            std::cout << std::setw(10) << std::fixed << std::setprecision(4) << A[i * N + j];
        }
        std::cout << "\n";
    }
}

int main() 
{
    int N = 1500;  // 矩阵的维度
    std::cout << "N =   " << N << endl;

    double start;
    std::vector<double> A(N * N);  // 随机生成的 N 维方阵
    std::vector<double> B(N * N);  // 拷贝 A 的矩阵 B
    std::vector<double> E(N * N);  // 单位阵

    std::cout << "正在计算 ... ..." << endl;
    start = clock(); //初始时间
    
    // 生成随机方阵 A
    generate_random_matrix(A, N);

    // 拷贝 A 到 B
    B = A;

    // 求 B 的逆阵并返回 逆阵 B。 使用 LAPACK
    std::cout << "Step 1:: 逆阵求解中 ... ...\n";
    inverse_matrix(B, N);

    // 计算 A * B,得到单位阵 E,使用 CBLAS
    std::cout << "Step 2:: 矩阵相乘中 ... ...\n";
    cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans,
                N, N, N, 1.0, A.data(), N, B.data(), N, 0.0, E.data(), N);

    //截止时间
    std::cout << "\nTime = " << clock() - start << " MilliSeconds\n" << endl;    

    // 打印单位阵 E 的前 10 行 10 列
    cout << "Matrix A_Inv * A = E 单位阵:" << endl;
    print_matrix(E, N, 10);

    return 0;
}[/i][i]

命令行编译 lapacke版
g++ -O3 -o Matrix_Gcc-Lapack.exe Matrix_Gcc-Lapack.cpp -ID:\CLib\Lapack\include -LD:\CLib\Lapack\lib D:\CLib\Lapack\lib\libblas.a D:\CLib\Lapack\lib\libcblas.a D:\CLib\Lapack\lib\liblapack.a D:\CLib\Lapack\lib\liblapacke.a -llapacke -llapack -lcblas -lblas


命令行编译 OpenBLAS版
g++ -O3 -o Matrix_Gcc-OpenBLAS.exe Matrix_Gcc-OpenBLAS.cpp -ID:\CLib\OpenBLAS\include -LD:\CLib\OpenBLAS\lib -lopenblas


42

帖子

5

主题

0

精华

熟手

F 币
251 元
贡献
100 点
5#
 楼主| 发表于 6 天前 | 只看该作者
有什么改进方法吗? 欢迎大神讨论
您需要登录后才可以回帖 登录 | 极速注册

本版积分规则

捐赠本站|Archiver|关于我们 About Us|小黑屋|Fcode ( 京ICP备18005632-2号 )

GMT+8, 2025-5-20 12:38

Powered by Tencent X3.4

© 2013-2025 Tencent

快速回复 返回顶部 返回列表