我也想知道是否有一个乘法相当于Total
.
A really not so bad solution is
In[1]:= lst=RandomReal[2,5000000];
Times@@lst//Timing
Exp[Total[Log[lst]]]//Timing
Out[2]= {2.54,4.370467929041*10^-666614}
Out[3]= {0.47,4.370467940*10^-666614}
只要数字是正数并且不太大或太小,
那么舍入误差并不算太糟糕。
对评估过程中可能发生的情况的猜测是:(1)如果数字是正浮点数,则Log
操作可以快速应用于打包数组。 (2) 然后可以使用以下命令快速添加数字Total
的压缩数组方法。 (3) 那么这只是最后一步,需要出现非机器尺寸的浮子。
See 这个答案 https://stackoverflow.com/questions/5294640/is-there-a-fast-product-operation-for-packedarrays/5308395#5308395适用于正浮点数和负浮点数的解决方案。
让我们快速检查一下该解决方案是否适用于产生非机器大小答案的浮点数。与安德鲁相比(快得多)compiledListProduct
:
In[10]:= compiledListProduct =
Compile[{{l, _Real, 1}},
Module[{tot = 1.}, Do[tot *= x, {x, l}]; tot],
CompilationTarget -> "C"]
In[11]:= lst=RandomReal[{0.05,.10},15000000];
Times@@lst//Timing
Exp[Total[Log[lst]]]//Timing
compiledListProduct[lst]//Timing
Out[12]= {7.49,2.49105025389*10^-16998863}
Out[13]= {0.5,2.4910349*10^-16998863}
Out[14]= {0.07,0.}
如果您选择较大的(>1
) 实数,那么compiledListProduct
会产生警告CompiledFunction::cfne: Numerical error encountered; proceeding with uncompiled evaluation.
并且需要一些时间才能给出结果......
一个好奇的是,两者Sum
and Product
可以采用任意列表。Sum
工作正常
In[4]:= lst=RandomReal[2,5000000];
Sum[i,{i,lst}]//Timing
Total[lst]//Timing
Out[5]= {0.58,5.00039*10^6}
Out[6]= {0.02,5.00039*10^6}
但很长一段时间PackedArray
s,例如这里的测试示例,Product
失败,因为自动编译的代码(在版本 8.0 中)无法正确捕获下溢/溢出:
In[7]:= lst=RandomReal[2,5000000];
Product[i,{i,lst}]//Timing
Times@@lst//Timing
Out[8]= {0.,Compile`AutoVar12!}
Out[9]= {2.52,1.781498881673*10^-666005}
WRI 技术支持提供的解决方法是使用以下命令关闭产品编译SetSystemOptions["CompileOptions" -> {"ProductCompileLength" -> Infinity}]
。另一种选择是使用lst=Developer`FromPackedArray[lst]
.