我有一個場景,我必須從用戶那里獲取n個輸入并將其存盤在一個陣列中,我還需要找到陣列中所有元素的總和。 由于這是在代碼中,我想知道最理想的方法。
一般來說,I/O操作被認為是使用大量CPU時間的惡名。如果我經常從 I/O 和處理中切換過來,而不是先接受普通輸入,然后再處理總和,那么在大規模輸入(即 1000 個輸入)中是否會有性能上的影響?
我正在使用C 語言和在線法官(Codeforces)。
第一種方法。我回圈了n次,從輸入流中讀取了n個輸入,并將它們逐一放入陣列中。然后將它們全部相加。
int n, sum=0;
cingt;> n。
int *myarray = new int[n];
for(int i=0; i<n; i )
{
cin>> myarray[i];
}
for(int i=0; i<n; i )
{
sum = myarray[i];
}
第二種方法。我在里面回圈了n次,讀取了n個輸入。每一次,我都把它放在一個陣列中,并把剛才作為輸入的數字也加起來。
int n, sum=0;
cingt;> n。
int *myarray = new int[n];
for(int i=0; i<n; i )
{
cingt;> myarray[i];
sum = myarray[i];
}
uj5u.com熱心網友回復:
在這樣的程式中,你有一個單執行緒來接收用戶的輸入,將其存盤在一個陣列中并進行求和,這不會有(明顯的)區別--無論如何都會發生同樣的操作。
更明顯的優化是取消陣列。如果所需的輸出只是一個總和,你可以直接對輸入進行求和,而不需要存盤它們:
更明顯的優化是取消陣列。
int sum = 0;
for(int i=0; i<n; i )
{
int temp;
cingt;> temp;
sum = temp;
}
uj5u.com熱心網友回復:
我懷疑在實踐中,與你函式中的其他操作相比,cin的速度非常慢,任何差異都不可能被測量出來。
盡管如此,如果我們忽略cin的緩慢性,而專注于你的函式所生成的代碼的質量,我認為單回圈方法有幾個優點。
- 第一個例子中,所有的代碼都是由一個人完成的。
- 第一個例子中,所有的回圈控制指令都有兩次,這些指令很便宜,但并不免費。
- 最近寫入的記憶體位置幾乎可以肯定仍在 L1 快取中,而在前一個回圈中寫入的記憶體位置如果迭代次數較多,則可能不在 L1 快取中。
在一個回圈中做太多不同的事情的一個可能的缺點是,你可能會耗盡 "呼叫-保存 "暫存器,迫使代碼使用堆疊來處理本來可以存在于暫存器中的變數,但我認為這在大多數架構上不會成為一個問題。
當我在Godbolt上查看編譯后的代碼時,我注意到的另一件事是,由于cin需要一個參考而不是回傳一個值,"n "不能跨函式呼叫而存在于暫存器中。所以呼叫cin的回圈必須在每次迭代時重新加載它。
uj5u.com熱心網友回復:
嚴格來說,在一個回圈中做這些事情會更快,但這不是你應該擔心的區別。
對于Codeforces,你可能希望有更快的io,所以我建議你使用scanf和printf而不是cin和cout,它們是已知更快。
如果你想使用cin和cout,你也可以添加這一行,它使它們更快,你可以查看為什么這里
ios_base::sync_with_stdio(false)。
cin.tie(NULL)。
為什么?
當這段代碼翻譯成匯編時,該回圈只是一個有條件的跳轉陳述句,根據條件的不同,跳轉可能被采取或不采取,只有當條件被評估時我們才能知道。
我們肯定不想等待條件評估,所以我們有分支預測(可以用很多方法),它做"一些計算"來估計是否采取分支。
在條件被評估之前,我們遵循我們的假設,并執行指令,而不將其結果提交給暫存器或記憶體。
如果我們的估計是正確的,這些結果將被提交(我們自然地繼續執行),如果不正確,我們將簡單地沖刷管道(丟棄這些指令和它們的結果)。
盡管如此,我們的性能還是被降低了,這種失誤預測的懲罰(我們計算的結果不需要),這就是為什么減少對流動指令的控制有助于提高性能。
對于你的情況,將回圈分成兩個,將產生兩個條件跳轉指令,而不是一個,這將增加失誤懲罰。
有些編譯器會進行回圈展開以解決類似的問題。
只要您不是在處理 HPC(高性能計算)應用,或者真的需要不惜一切代價進行更好的優化,您就不需要擔心這個問題。
相反,您應該關注改進演算法本身,因此正如 @Mureinik 所說,如果您的問題只需要求和,而不需要進一步使用數字本身,您就可以在飛行中計算出和。
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/309420.html
標籤:
