Is there a fast product operation for PackedArrays?

后端 未结 3 877
执念已碎
执念已碎 2021-02-04 16:26

In Mathematica a vector (or rectangular array) containing all machine size integers or floats may be stored in a packed array. These objects take less memory, and some operatio

3条回答
  •  遇见更好的自我
    2021-02-04 16:52

    First, to avoid confusion, take a look at an example whose results are all representable as hardware machine precision numbers, which must all be less than

    In[1]:= $MaxMachineNumber
    
    Out[1]= 1.79769*10^308
    

    Your Total example already had this nice (and fast) property. Here is a variant on your Times example using machine numbers:

    In[2]:= lst = RandomReal[{0.99, 1.01}, 5000000];
    Times @@ lst // Timing
    
    Out[3]= {1.435, 1.38851*10^-38}
    

    Now we can use Compile to make a compiled function to perform this operation efficiently:

    In[4]:= listproduct = 
     Compile[{{l, _Real, 1}}, 
      Module[{tot = 1.}, Do[tot *= x, {x, l}]; tot]]
    
    Out[4]= CompiledFunction[{l},Module[{tot=1.},Do[tot*=x,{x,l}];tot],-CompiledCode-]
    

    It's much faster:

    In[5]:= listproduct[lst] // Timing
    
    Out[5]= {0.141, 1.38851*10^-38}
    

    Assuming you have a C compiler and Mathematica 8, you can also automatically compile all the way to C code. A temporary DLL is created and linked back into Mathematica at run-time.

    In[6]:= compiledlistproduct = 
     Compile[{{l, _Real, 1}}, 
      Module[{tot = 1.}, Do[tot *= x, {x, l}]; tot], 
      CompilationTarget -> "C"]
    
    Out[6]= CompiledFunction[{l},Module[{tot=1.},Do[tot*=x,{x,l}];tot],-CompiledCode-]
    

    This gives performance not much different to that which a built-in Mathematica function would have:

    In[7]:= compiledlistproduct[lst] // Timing
    
    Out[7]= {0.015, 1.38851*10^-38}
    

    Note that if your product really will go beyond $MaxMachineNumber (or $MinMachineNumber), then you are better off sticking with Apply[Times, list]. The same comment applies to Total, if your results can get that big:

    In[11]:= lst = RandomReal[10^305, 5000000];
    Plus @@ lst // Timing
    
    Out[12]= {1.435, 2.499873364498981*10^311}
    
    In[13]:= lst = RandomReal[10^305, 5000000];
    Total[lst] // Timing
    
    Out[14]= {1.576, 2.500061580905602*10^311}
    

提交回复
热议问题