我經常寫:{[email protected]#, [email protected]#} &
有沒有更快的方法來找到最小值和最大值?
然而,這似乎效率低下,因爲表達式必須掃描兩次,一次找到最小值,一次找到最大值。有沒有更快的方法來做到這一點?表達式通常是張量或數組。
我經常寫:{[email protected]#, [email protected]#} &
有沒有更快的方法來找到最小值和最大值?
然而,這似乎效率低下,因爲表達式必須掃描兩次,一次找到最小值,一次找到最大值。有沒有更快的方法來做到這一點?表達式通常是張量或數組。
這會比較慢。
minMax = Compile[{{list, _Integer, 1}},
Module[{currentMin, currentMax},
currentMin = currentMax = First[list];
Do[
Which[
x < currentMin, currentMin = x,
x > currentMax, currentMax = x],
{x, list}];
{currentMin, currentMax}],
CompilationTarget -> "C",
RuntimeOptions -> "Speed"];
v = RandomInteger[{0, 1000000000}, {10000000}];
minMax[v] // Timing
我覺得它比獅子座的版本快一點,因爲Do
有點比For
快,即使是在編譯的代碼。
但是,最終,這是使用高級功能編程語言時所遇到的那種性能打擊的例子。
加成響應獅子座:
我不認爲,該算法可以佔到全部的時間差。 很多往往不是,我認爲,無論如何這兩項測試都會被應用。然而,Do
和For
之間的差異是可測量的。
cf1 = Compile[{{list, _Real, 1}},
Module[{sum},
sum = 0.0;
Do[sum = sum + list[[i]]^2,
{i, Length[list]}];
sum]];
cf2 = Compile[{{list, _Real, 1}},
Module[{sum, i},
sum = 0.0;
For[i = 1, i <= Length[list],
i = i + 1, sum = sum + list[[i]]^2];
sum]];
v = RandomReal[{0, 1}, {10000000}];
First /@{Timing[cf1[v]], Timing[cf2[v]]}
{0.685562, 0.898232}
很酷!它比我最快的解決方案快兩倍。主要原因是你可以減少約兩倍的測試次數,因爲你實際上使用了更好的算法 - 你明確地使用了這樣一個事實,即在任何給定的元素中,只有兩個測試中的一個可以有效 - +1。 – 2011-05-04 13:30:00
我可能不得不在我的所有帖子中指定「For Mathematica 7」。我會把它留給其他人投票,因爲我無法測試它。這並不意味着我不感謝你的努力。 – 2011-05-04 13:32:27
馬克,祝賀1k代表。你能指導我瞭解*爲什麼*這種事情在運行時沒有或不能被優化? – 2011-05-04 13:37:45
在Mathematica編程實踐中,我認爲這個速度是最快的。我看到試圖使其更快內MMA是使用Compile
與C編譯目標,如下的唯一方法:
getMinMax =
Compile[{{lst, _Real, 1}},
Module[{i = 1, min = 0., max = 0.},
For[i = 1, i <= Length[lst], i++,
If[min > lst[[i]], min = lst[[i]]];
If[max < lst[[i]], max = lst[[i]]];];
{min, max}], CompilationTarget -> "C", RuntimeOptions -> "Speed"]
然而,即使這似乎是比你的代碼有點慢:
In[61]:= tst = RandomReal[{-10^7,10^7},10^6];
In[62]:= Do[getMinMax[tst],{100}]//Timing
Out[62]= {0.547,Null}
In[63]:= Do[{[email protected]#,[email protected]#}&[tst],{100}]//Timing
Out[63]= {0.484,Null}
你可能可以完全用C編寫函數,然後編譯並加載爲DLL - 這樣可以消除一些開銷,但我懷疑你會贏得超過百分之幾 - 不值得IMO的努力。
編輯
有趣的是,你可能會顯著增加與手動公共子表達式消除(lst[[i]]
這裏)編譯解決方案的速度:
getMinMax =
Compile[{{lst, _Real, 1}},
Module[{i = 1, min = 0., max = 0., temp},
While[i <= Length[lst],
temp = lst[[i++]];
If[min > temp, min = temp];
If[max < temp, max = temp];];
{min, max}], CompilationTarget -> "C", RuntimeOptions -> "Speed"]
比{[email protected]#,[email protected]#}
快一點。
如果您使用Mma7,尤其不值得您付出努力! ; Leonid,你當然比我更瞭解Mathematica的機制。你可以(用幾句話......)告訴我爲什麼像{Min @#,Max @#}&'不能在內部進行「JIT」優化?也就是說,爲什麼Mathematica不是或不能用這種方式建造? – 2011-05-04 13:06:41
我認爲這樣的優化很難使一般可靠,對於更復雜的函數,符號參數等等。此外,它與習慣性mma編程有點正交,因爲通過這樣做,你打破了高層思維過程(聲明式編程樣式)通過指定應如何計算的細節。我認爲,除非你獲得了一個數量級以上的提速,否則這種優化並沒有得到回報,因爲你失去了高層思維(抽象,可讀性,屏幕空間)的優勢,這通常更重要,特別是對於較大的項目。 – 2011-05-04 13:14:12
對於數組,你可以做最簡單的事情功能和使用
Fold[{Min[##],Max[##]}&, [email protected]#, [email protected]#]& @ data
不幸的是,沒有速度惡魔。即使對於短列表,5個元素,所有Leonid's answers和Mark's answer至少快7倍,在v.7中未編譯。對於長列表,25000個元素,Mark的速度提高了19.6倍,但這個長度只有0.05秒左右。
但是,我不會計算出{Min[#], Max[#]}&
作爲選項。未編譯的速度比Mark的短名單快1.7倍,長列表的速度快近15倍(分別比Fold
解決方案快8倍和近300倍)。
不幸的是,我無法獲得{Min[#], Max[#]}&
,Leonid's或Mark的答案的編譯版本的好數字,而是我得到了無數難以理解的錯誤消息。實際上,{Min[#], Max[#]}&
的執行時間增加了。儘管如此,Fold
解決方案也有了顯着的改進,並且花費了Leonid答案未編譯時間的兩倍。
編輯:爲好奇,這裏的未編譯的功能的一些定時測量 -
的每個功能是在水平軸上,並且平均時間指定的長度的100列出了用於,以秒爲單位,是垂直軸。按照時間遞增的順序,曲線是{Min[#], Max[#]}&
,馬克的答案,列昂尼德的第二個答案,列昂尼德的第一個答案,以及從上面的Fold
方法。
謝謝!我知道,我是_curious_ :) – 2011-05-04 17:43:08
@belisarius之一。我已經計算了時間,所以我繪製了它們讓所有人都看到。 – rcollyer 2011-05-04 18:00:00
對於所有正在進行計時的人,我想警告您,執行順序非常重要。例如,看一下下面的兩個微妙的不同時間測試:
(1)
res =
Table[
a = RandomReal[{0, 100}, 10^8];
{
Min[a] // AbsoluteTiming // First, Max[a] // AbsoluteTiming // First,
Max[a] // AbsoluteTiming // First, Min[a] // AbsoluteTiming // First
}
, {100}
]
古怪的人在這裏是最後Min
(2)
res =
Table[
a = RandomReal[{0, 100}, 10^8];
{
Max[a] // AbsoluteTiming // First, Min[a] // AbsoluteTiming // First,
Min[a] // AbsoluteTiming // First, Max[a] // AbsoluteTiming // First
}
, {100}
]
這裏,第一個Max
發現最高時機,第二個最高時機爲max
,兩個Min
s大致相同且最低。實際上,我預計Max
和Min
需要大約相同的時間,但他們不需要。前者似乎比後者多花50%的時間。杆位也似乎有50%的讓分。
現在與馬克和列昂尼德給出的算法進行比較:
res =
Table[
a = RandomReal[{0, 100}, 10^8];
{
{Max[a], Min[a]} // AbsoluteTiming // First,
{[email protected]#, [email protected]#} &@a // AbsoluteTiming // First,
getMinMax[a] // AbsoluteTiming // First,
minMax[a] // AbsoluteTiming // First,
{Min[a], Max[a]} // AbsoluteTiming // First
}
, {100}
]
在這裏,我們找到0.3 S爲{最大值[A],閔[A]}(其中包括杆位障礙),.1水平是Mark的方法;其他人都差不多。
@Mr。我想知道你是否願意在你的問題中添加一個編輯,並在Mma 7中給出每個答案的時間圖。張貼代碼,然後我將在Mma 8中運行它以添加結果。同意? – 2011-05-04 14:41:04
@belisarius此刻我很困,但我不明白。 – 2011-05-04 14:43:31
@Mr。別擔心,我也是。也許只是一件愚蠢的事情.. – 2011-05-04 14:56:50