Fast list-product sign for PackedArray?

2019-07-20 18:53发布

As a continuation of my previous question, Simon's method to find the list product of a PackedArray is fast, but it does not work with negative values.

This can be "fixed" by Abs with minimal time penalty, but the sign is lost, so I will need to find the product sign separately.

The fastest method that I tried is EvenQ @ Total @ UnitStep[-lst]

lst = RandomReal[{-2, 2}, 5000000];

Do[
  EvenQ@Total@UnitStep[-lst],
  {30}
] // Timing

Out[]= {3.062, Null}

Is there a faster way?

2条回答
来,给爷笑一个
2楼-- · 2019-07-20 19:41

This is a little over two times faster than your solution and apart from the nonsense of using Rule@@@ to extract the relevant term, I find it more clear - it simply counts the number elements with each sign.

EvenQ[-1 /. Rule@@@Tally@Sign[lst]]

To compare timings (and outputs)

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
查看更多
仙女界的扛把子
3楼-- · 2019-07-20 19:44

A bit late-to-the-party post: if you are ultimately interested in speed, Compile with the C compilation target seems to be about twice faster than the fastest solution posted so far (Tally - Sign based):

fn = Compile[{{l, _Real, 1}},
  Module[{sumneg = 0},
    Do[If[i < 0, sumneg++], {i, l}];
     EvenQ[sumneg]], CompilationTarget -> "C", 
     RuntimeOptions -> "Speed"]; 

Here are the timings on my machine:

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
查看更多
登录 后发表回答