Я также задавался вопросом, был ли мультипликативный эквивалент Total
.
A действительно не так уж и плохое решение
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) Тогда это только последний шаг, когда возникает необходимость в плавании не машинного размера.
См. этот ответ SO для решения, которое работает как для положительных, так и для отрицательных чисел.
Давайте быстро проверим, что это решение работает с числами с плавающей точкой, которые дают ответ не машинного размера.Сравните с Эндрю (намного быстрее) 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
, и 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
с, таких как тестовые примеры здесь, 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]
.