簡體   English   中英

如何縮短此迭代問題的運行時間

[英]How to shorten runtime of this iteration problem

我有下面的 C++ 片段,如果元素可以被 2 或 3 整除,它會迭代 1-50 次並打印出一條語句,而不是數字。當前運行時間約為 1.47 秒。 如何優化此問題以加快運行速度?

#include <iostream>

int main() {
    for (int j = 1; j <= 50; j++)
    {
        if (j % 2 == 0 && j % 3 == 0)
        {
            std::cout << "Both" << std::endl;
        }

        else if (j % 2 == 0)
        {
            std::cout << "Two" << std::endl;
        }

        else if (j % 3 == 0)
        {
            std::cout << "Three" << std::endl;
        }

        else
        {
            std::cout << j << std::endl;
        }
    }
}

您可以將循環內的endl更改為"\\n" ,然后std::cout << std::flush; 循環完成后。 這會將沖洗次數減少 50 倍。

由於刷新輸出是這里唯一重要的工作,我希望這可以將您的運行時間減少 98%。 然而,我原以為即使有 50 次刷新,它仍然應該在一秒鍾之內。

首先,不要在真正需要之前嘗試優化 struff (記住這一點)。 我真的不相信該代碼需要 1.4 秒才能運行。 但是沒問題。

我能看到的唯一可以做得更好的是在編譯時將其分組。 這樣你就不會為每個數字計算模數,你只會看看是否需要打印文本。

所以我所做的是創建一個在編譯時評估的函數,如果需要,它返回一個帶有文本的const char* ,如果不需要,則返回 nullprt:

constexpr const char *type(int n) {
    if (n % 2 == 0 && n % 3 == 0) {
        return "Both";
    }

    if (n % 2 == 0) {
        return "Two";
    }

    if (n % 3 == 0) {
        return "Three";
    }

    return nullptr;
}

接下來,我有一個包含所有所需結果的數組:

const int max_number = 50;
constexpr const static std::array<const char *, max_number + 1> results{
    type(0),
    type(1),
    type(2),
    type(3),
    type(4),
    type(5),
    type(6),
    type(7),
    type(8),
    type(9),
    type(10),
    type(11),
    type(12),
    type(13),
    type(14),
    type(15),
    type(16),
    type(17),
    type(18),
    type(19),
    type(20),
    type(21),
    type(22),
    type(23),
    type(24),
    type(25),
    type(26),
    type(27),
    type(28),
    type(29),
    type(30),
    type(31),
    type(32),
    type(33),
    type(34),
    type(35),
    type(36),
    type(37),
    type(38),
    type(39),
    type(40),
    type(41),
    type(42),
    type(43),
    type(44),
    type(45),
    type(46),
    type(47),
    type(48),
    type(49),
    type(50)
};

這樣做的結果是,當程序被編譯時,你已經然后分成了gropus。 你可以在這里看到它。 生成的匯編程序將是這樣的:

.L.str:
        .asciz  "Both"

.L.str.2:
        .asciz  "Two"

.L.str.3:
        .asciz  "Three"

results:
        .quad   .L.str // 0 both
        .quad   0 // 1 none
        .quad   .L.str.2 // 2 Two
        .quad   .L.str.3 // 3 Three
        .quad   .L.str.2 // 4 Two
        .quad   0  // 5 none
        .quad   .L.str // etc
        .quad   0
        // ...  and it continues for all values

最后在運行時您只需檢查它是否為空:

int main() {
    Timer t{};
    for (int j = 1; j <= max_number; j++) {
        if (results[j]) {
            cout << results[j] << '\n';
        } else {
            cout << j << '\n';
        }
    }
}

結果:

  • 原來的方式在我的機器上花費了 0.05 到 0.08 毫秒。
  • 新方法需要 0.04 到 0.07 毫秒。

所以是的,它更快。 但它會改變任何事情的速度如此之快。

現在我真的很想弄清楚這一點。 在你需要之前不要優化! . 這是一個快速測試,它們都用-O3編譯。 差異真的很小,代碼更大更復雜。 喜歡簡單的方法

我幾乎不相信它在任何 i7 上都這么慢。 最多應該運行幾毫秒。

然而,問題是“如何改進”,為此有幾點:

  1. 開啟優化-O2
  2. 刪除循環中的std::cout 而是創建一個例如std::string ,將輸出附加到循環中的該變量,並在循環之后輸出它。 只測量循環,而不是std::cout
  3. 使用嵌套循環,就像@MichaelDorgan 建議的那樣。

只有 50 次迭代? 將其展開為狀態機(50 個狀態,1 個 switch 語句,無數學)。 或者,將其轉換為預計算值的單個打印件。 仍然沒有回答為什么程序運行得這么慢......

相同的代碼在我的機器上運行需要 12-66 毫秒。 我認為問題出在你的時間測量上。 您可以使用 C++ 的標准工具(例如chrono庫)測量運行時間:

#include<iostream>
#include<chrono>

using namespace std;

int main() {
    using clock = chrono::high_resolution_clock;

    auto start = clock::now();

    for (int j = 1; j <= 50; j++) {
        if (j % 2 == 0 && j % 3 == 0) {
            cout << "Both" << endl;
        } else if (j % 2 == 0) {
            cout << "Two" << endl;
        } else if (j % 3 == 0) {
            cout << "Three" << endl;
        } else {
            cout << j << endl;
        }
    }

    auto end = clock::now();
    cout << "Total runtime: " << chrono::duration_cast<chrono::milliseconds>(end - start).count() << "ms." << endl;
}

此代碼將以毫秒為單位測量實際循環的持續時間並打印出來。 它將忽略程序啟動、初始化和停止的任何開銷,並讓您了解實際的代碼性能,而不是操作系統的進程運行設施性能。 我敢打賭,它會顯着提高速度,對我來說,它會打印“總運行時間:4 毫秒”。 到底。

暫無
暫無

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

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