为什么Eigen库中double的计算速度比float快3倍?

问题描述 投票:0回答:1

这是我的代码。我使用 double 类型创建了一组矩阵和向量乘法,并使用 float 类型创建了另一组。两组乘法在for循环中执行300万次,并分别记录所花费的时间。我发现 double 类型明显比 float 类型快。我尝试了不同的编译器优化选项:

1.没有优化。

2. O1.

3.氧气。

我发现无论优化级别如何,double的计算速度都比float高很多,大约快2到3倍。我也在不同类型的处理器上进行了测试,结论几乎是一样的。

    #include <iostream>
    #include <Eigen/Dense>
    #include <chrono>

    Eigen::Matrix3d A1 = Eigen::Matrix3d::Random();
    Eigen::Matrix3d B1 = Eigen::Matrix3d::Random();
    Eigen::Vector3d C1 = Eigen::Vector3d::Random();
    Eigen::Vector3d D1 = Eigen::Vector3d::Random();

    Eigen::Matrix3f A2 = Eigen::Matrix3f::Random();
    Eigen::Matrix3f B2 = Eigen::Matrix3f::Random();
    Eigen::Vector3f C2 = Eigen::Vector3f::Random();
    Eigen::Vector3f D2 = Eigen::Vector3f::Random();

    int num = 3000000;

    int main()
    {
    std::cout << "start1:" << std::endl;
    auto start1 = std::chrono::high_resolution_clock::now();
    
    for (int i = 0; i < num; i++)
    {
        Eigen::Vector3d E1 = A1 * C1 + B1 * D1;
        double dd = E1[0, 0];//just prevent compiler optimization
    }

    auto end1 = std::chrono::high_resolution_clock::now();  
    std::chrono::duration<double, std::milli> elapsed1 = end1 - start1; 
    std::cout << "Eigen use: " << elapsed1.count() << " ms.\n" << std::endl;

    std::cout << "start2:" << std::endl;
    auto start2 = std::chrono::high_resolution_clock::now();

    for (int i = 0; i < num; i++)
    {
        Eigen::Vector3f E2 = A2 * C2 + B2 * D2;
        float dd = E2[0, 0];//just prevent compiler optimization
    }

    auto end2 = std::chrono::high_resolution_clock::now();
    std::chrono::duration<double, std::milli> elapsed2 = end2 - start2;
    std::cout << "Eigen use: " << elapsed2.count() << " ms." << std::endl;
    }

下图为i7-13700k、win10 X64平台、vs2022 x64编译器优化O2下的结果。

这是结果图

double:
Eigen use: 38.4053 ms.

float:
Eigen use: 92.1853 ms.

有人可以帮我理解为什么吗?非常感谢。

c++ compiler-optimization matrix-multiplication eigen3
1个回答
0
投票

不是一个完整的答案,但它可能会帮助您更好地对代码进行基准测试并避免潜在的错误结果(例如,由于某些行被优化)。不要使用

std::chrono
,而是使用基准测试库,例如来自谷歌的并写一个基准:

#include <Eigen/Dense>

#include <benchmark/benchmark.h>

Eigen::Matrix3d A1 = Eigen::Matrix3d::Random();
Eigen::Matrix3d B1 = Eigen::Matrix3d::Random();
Eigen::Vector3d C1 = Eigen::Vector3d::Random();
Eigen::Vector3d D1 = Eigen::Vector3d::Random();

Eigen::Matrix3f A2 = Eigen::Matrix3f::Random();
Eigen::Matrix3f B2 = Eigen::Matrix3f::Random();
Eigen::Vector3f C2 = Eigen::Vector3f::Random();
Eigen::Vector3f D2 = Eigen::Vector3f::Random();


static void Floats(benchmark::State &state) {
  for (auto _ : state) {
    Eigen::Vector3f E2 = A2 * C2 + B2 * D2;
    float dd = E2(0, 0);
    benchmark::DoNotOptimize(E2);
    benchmark::DoNotOptimize(dd);
  }
}
BENCHMARK(Floats);

static void Doubles(benchmark::State &state) {
  for (auto _ : state) {
    Eigen::Vector3d E1 = A1 * C1 + B1 * D1;
    double dd = E1(0, 0);
    benchmark::DoNotOptimize(E1);
    benchmark::DoNotOptimize(dd);
  }
}
BENCHMARK(Doubles);

在我的机器上,两次操作的结果几乎相同:

Run on (4 X 2688.01 MHz CPU s)
CPU Caches:
  L1 Data 48 KiB (x2)
  L1 Instruction 32 KiB (x2)
  L2 Unified 1280 KiB (x2)
  L3 Unified 12288 KiB (x1)
Load Average: 0.04, 0.29, 0.16
-----------------------------------------------------
Benchmark           Time             CPU   Iterations
-----------------------------------------------------
Floats           3.41 ns         3.41 ns    208083014
Doubles          3.31 ns         3.31 ns    210535117

浮动确实稍微慢一些(不知道为什么)。

您可以尝试为一些更复杂的操作编写基准,使用 100x100 矩阵、计算矩阵逆等。

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.