簡體   English   中英

為什么 C++ 雙精度類型值的乘法與加法一樣快?

[英]How come multiplication is as fast as addition for C++ double type values?

#include<vector>
#include<iostream>
#include<random>
#include<chrono>

int main()
{
    int i;
    std::mt19937 rng(std::chrono::system_clock::now().time_since_epoch().count());
    std::uniform_real_distribution<double> dist(0.5, 1);
    std::vector<double> q;
    int N = 100000000;
    for (i = 0; i < N; ++i) q.emplace_back(dist(rng));

    double sum = 0;

    auto start = std::chrono::steady_clock::now();
    for (i = 1; i < 100000000; ++i) {
        sum += q[i] + q[i - 1]; // change + to - or * or /, it takes same time.
    }

    auto end = std::chrono::steady_clock::now();
    std::cout << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() << std::endl;
    std::cout << sum << std::endl;

}

加法和減法應該是簡單的過程,可能是一些移位和按位運算,其成本與精度成正比。

而乘法和除法自然是更復雜的過程。 說乘法,它的數量級要慢一些似乎很自然(如果加法需要 O(n),則類似於 O(n^2),因為乘法可以分解為移位值的加法)對於除法,它應該更難.

然而,對於使用雙精度類型值的所有 4 個算術運算,此代碼需要大約 110 毫秒,並進行了優化。 這怎么可能? 這里發生了什么神奇的事情,讓 C++ 能夠像加法一樣快地處理乘法,或者像乘法一樣緩慢地處理加法?

ps 對於 integer,它需要〜兩倍的時間,僅用於除法。

在某些處理器上,浮點乘法與加法一樣快,因為:

  • 硬件設計人員在浮點單元中放置了很多邏輯門。
  • 指令可以分為多個階段,在流水線中執行。 例如,乘法可以在單元 M0 中執行其部分工作,然后將結果傳遞給執行另一部分的單元 M1,然后是 M2,然后是 M3。 在 M1 工作時,M0 可以開始工作在不同的乘法上。 使用這種安排,一次乘法實際上可能需要四個處理器周期才能完成,但是,因為有四個單元在四個階段上工作,處理器可以在每個周期完成一次乘法。 相反,像 XOR 這樣更簡單的指令只有一個階段。
  • 雖然有些指令可以快速執行,有些則需要更多時間,但整個處理器是由一個時鍾同步的,每個執行單元中的每個流水線階段都必須在一個時鍾周期內完成它的工作。 這給處理器設計帶來了一定的剛性——一些簡單的操作會在一個時鍾周期結束之前完成它們的工作,而復雜的操作則需要整個周期。 設計人員決定創建一個時鍾周期需要多長時間。 如果時鍾周期太短(相對於邏輯門的工作速度),那么許多指令必須占用多個周期,並且可能需要額外的開銷來管理它們。 如果一個時鍾周期太長,那么時間就被浪費在等待本可以更快完成的指令上。 對於當前的處理器技術,浮點乘法器級通常與處理器周期時間配合良好。

盡管如此,您可能會看到加法和乘法時間之間的差異。 當前的處理器設計相當復雜,處理器通常具有多個單元來執行各種浮點運算。 一個處理器可以有更多的單位來做加法而不是做乘法,所以它可以在單位時間內做比乘法更多的加法。

但是,請注意您使用的表達式:

sum += q[i] + q[i - 1];

這導致sum串行依賴於它的先前值。 處理器可以將q[i]q[i-1]相加,而無需等待先前的加法,但是,要與sum ,它必須等待先前的與sum完成。 這意味着,如果一個處理器有兩個加法單元,它可以同時處理q[i] + q[i-1]和之前的sum運算。 但是,如果它有更多的附加單元,它不能更快地 go。 它可以使用額外的單元來為i的不同值做更多的q[i] + q[i - 1]加法,但是sum的每個加法都必須等待前一個加法。 因此,對於兩個或更多加法單元,此計算取決於加法的延遲,即進行一次加法所需的時間。 (這與加法的吞吐量相反,如果沒有串行依賴,處理器在單位時間內可以進行多少次加法。)

如果您使用不同的計算,例如sum += q[i]; sum0 += q[i]; sum1 += q[i+1]; sum2 += q[i+2]; sum3 += q[i+3]; sum0 += q[i]; sum1 += q[i+1]; sum2 += q[i+2]; sum3 += q[i+3]; ,然后您可以看到不同的加法和乘法時間,具體取決於處理器有多少個加法單元和多少個乘法單元。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM