PackedArrays 有快速的产品操作吗?
在 Mathematica 中,包含所有机器大小的整数或浮点数的向量(或矩形数组)可以存储在压缩数组中。这些对象占用的内存较少,并且某些操作对它们的速度要快得多。
RandomReal
在可能的情况下生成一个压缩数组。打包数组可以使用 Developer
函数 FromPackedArray
解包
考虑这些时间
lst = RandomReal[1, 5000000];
Total[lst] // Timing
Plus @@ lst // Timing
lst = Developer`FromPackedArray[lst];
Total[lst] // Timing
Plus @@ lst // Timing
Out[1]= {0.016, 2.50056*10^6}
Out[2]= {0.859, 2.50056*10^6}
Out[3]= {0.625, 2.50056*10^6}
Out[4]= {0.64, 2.50056*10^6}
因此,在打包数组的情况下,Total
速度要快很多倍比 Plus @@
但对于非压缩数组来说大致相同。请注意,Plus @@
在打包数组上实际上要慢一些。
现在考虑
lst = RandomReal[100, 5000000];
Times @@ lst // Timing
lst = Developer`FromPackedArray[lst];
Times @@ lst // Timing
Out[1]= {0.875, 5.8324791357*10^7828854}
Out[1]= {0.625, 5.8324791357*10^7828854}
最后,我的问题:Mathematica 中是否有一种快速方法来计算打包数组的列表乘积,类似于 Total
?
我怀疑这可能是不可能的,因为数值误差与乘法相结合。此外,该函数需要能够返回非机器浮点数才能发挥作用。
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 operations are much faster on them.
RandomReal
produces a packed array when possible. A packed array can be unpacked with the Developer
function FromPackedArray
Consider these timings
lst = RandomReal[1, 5000000];
Total[lst] // Timing
Plus @@ lst // Timing
lst = Developer`FromPackedArray[lst];
Total[lst] // Timing
Plus @@ lst // Timing
Out[1]= {0.016, 2.50056*10^6}
Out[2]= {0.859, 2.50056*10^6}
Out[3]= {0.625, 2.50056*10^6}
Out[4]= {0.64, 2.50056*10^6}
Therefore, in the case of a packed array, Total
is many times faster than Plus @@
but about the same for a non-packed array. Note that Plus @@
is actually a little slower on the packed array.
Now consider
lst = RandomReal[100, 5000000];
Times @@ lst // Timing
lst = Developer`FromPackedArray[lst];
Times @@ lst // Timing
Out[1]= {0.875, 5.8324791357*10^7828854}
Out[1]= {0.625, 5.8324791357*10^7828854}
Finally, my question: is there a fast method in Mathematica for the list product of a packed array, analogous to Total
?
I suspect that this may not be possible because of the way that numerical errors compound with multiplication. Also, the function will need to be able to return non-machine floats to be useful.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我还想知道是否有一个相当于
Total
的乘法。一个
真正不太糟糕的解决方案是只要数字是正数并且不太大或太小,
那么舍入误差并不算太糟糕。
对评估过程中可能发生的情况的猜测是: (1) 如果数字是正浮点数,则可以快速将 Log 操作应用于打包数组。 (2) 然后可以使用Total 的压缩数组方法快速将数字相加。 (3) 那么这只是最后一步,需要出现非机器尺寸的浮子。
请参阅此答案了解解决方案适用于正浮点数和负浮点数。
让我们快速检查一下该解决方案是否适用于产生非机器大小答案的浮点数。与 Andrew 的(更快)
compiledListProduct
相比:如果您选择较大 (
>1
) 的实数,则compiledListProduct
将产生警告CompiledFunction::cfne:遇到数字错误;继续进行未编译的评估。 并且需要一些时间才能给出结果...
一个好奇的是
Sum
和Product
都可以采用任意列表。Sum
工作正常,但对于长
PackedArray
来说,例如这里的测试示例,Product
会失败,因为自动编译的代码(在版本 8.0 中)会失败无法正确捕获下溢/溢出:有用的 WRI 技术支持提供的解决方法是使用 SetSystemOptions["CompileOptions" ->; 关闭产品编译。 {“ProductCompileLength”->无穷大}]。另一种选择是使用
lst=Developer`FromPackedArray[lst]
。I've also wondered if there was a multiplicative equivalent to
Total
.A
reallynot so bad solution isAs long as the numbers are positive and aren't too big or small,
then the rounding errors aren't too bad.
A guess as to what might be happening during evaluation is that: (1) Provided the numbers are positive floats, the
Log
operation can be quickly applied to the packed array. (2) The numbers can then be quickly added usingTotal
's packed array method. (3) Then it's only the final step where a non-machine sized float need arise.See this SO answer for a solution that works for both positive and negative floats.
Let's quickly check that this solution works with floats that yield a non-machine sized answer. Compare with Andrew's (much faster)
compiledListProduct
:If you choose larger (
>1
) reals, thencompiledListProduct
will yield the warningCompiledFunction::cfne: Numerical error encountered; proceeding with uncompiled evaluation.
and will take some time to give a result...One curio is that both
Sum
andProduct
can take arbitrary lists.Sum
works finebut for long
PackedArray
s, such as the test examples here,Product
fails since the automatically compiled code (in version 8.0) does not catch underflows/overflows properly:The work around supplied by the helpful WRI tech support is to turn off the product compilation using
SetSystemOptions["CompileOptions" -> {"ProductCompileLength" -> Infinity}]
. Another option is to uselst=Developer`FromPackedArray[lst]
.首先,为了避免混淆,请看一个示例,其结果均可以表示为硬件机器精度数字,这些数字必须全部小于
您的 Total 示例,该示例已具有此良好(且快速)的属性。这是使用机器编号的 Times 示例的变体:
现在我们可以使用 编译使编译函数能够有效地执行此操作:
速度要快得多:
假设您有 C 编译器和 Mathematica 8,您还可以自动编译一路 C 代码。创建一个临时 DLL,并在运行时链接回 Mathematica。
这提供的性能与内置 Mathematica 函数的性能没有太大区别:
请注意,如果您的产品确实会超出 $MaxMachineNumber (或 $MinMachineNumber),那么你最好坚持使用
Apply[Times, list]
。如果您的结果可以达到那么大,同样的评论也适用于 Total: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
Your Total example already had this nice (and fast) property. Here is a variant on your Times example using machine numbers:
Now we can use Compile to make a compiled function to perform this operation efficiently:
It's much faster:
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.
This gives performance not much different to that which a built-in Mathematica function would have:
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:西蒙的方法速度很快,但在负值时失败。结合他对我的其他问题的回答,这里是处理底片的快速解决方案。谢谢,西蒙。
功能
测试
Simon's method is fast, but it fails on negative values. Combining it with his answer to my other question, here is a fast solution that handles negatives. Thanks, Simon.
Function
Testing