Быстрый список-знак продукта для PackedArray?
Как продолжение моего предыдущего вопроса, метод Саймона для нахождения списка продуктов PackedArray быстрый, но он не работает с отрицательными значениями.
Это может быть исправлено Abs
с минимальными затратами времени, но знак теряется, поэтому мне нужно будет найти знак продукта отдельно.
Самый быстрый метод, который я пытался EvenQ @ Total @ UnitStep[-lst]
lst = RandomReal[{-2, 2}, 5000000];
Do[
EvenQ@Total@UnitStep[-lst],
{30}
] // Timing
Out[]= {3.062, Null}
Есть ли более быстрый способ?
2 ответа
Это чуть более чем в два раза быстрее, чем ваше решение, и кроме глупости использования Rule@@@
Чтобы извлечь соответствующий термин, я нахожу его более понятным - он просто считает количество элементов с каждым знаком.
EvenQ[-1 /. Rule@@@Tally@Sign[lst]]
Сравнивать тайминги (и выводы)
In[1]:= lst=RandomReal[{-2,2},5000000];
s=t={};
Do[AppendTo[s,EvenQ@Total@UnitStep[-lst]],{10}];//Timing
Do[AppendTo[t,EvenQ[-1/.Rule@@@Tally@Sign[lst]]],{10}];//Timing
s==t
Out[3]= {2.11,Null}
Out[4]= {0.96,Null}
Out[5]= True
Немного опоздал на пост: если вы в конечном итоге заинтересованы в скорости, Compile
с целью компиляции C, кажется, примерно в два раза быстрее, чем самое быстрое решение, опубликованное до сих пор (Tally
- Sign
основан):
fn = Compile[{{l, _Real, 1}},
Module[{sumneg = 0},
Do[If[i < 0, sumneg++], {i, l}];
EvenQ[sumneg]], CompilationTarget -> "C",
RuntimeOptions -> "Speed"];
Вот время на моей машине:
In[85]:= lst = RandomReal[{-2, 2}, 5000000];
s = t = q = {};
Do[AppendTo[s, EvenQ@Total@UnitStep[-lst]], {10}]; // Timing
Do[AppendTo[t, EvenQ[-1 /. Rule @@@ Tally@Sign[lst]]], {10}]; // Timing
Do[AppendTo[q, fn [lst]], {10}]; // Timing
s == t == q
Out[87]= {0.813, Null}
Out[88]= {0.515, Null}
Out[89]= {0.266, Null}
Out[90]= True