Wolfram mathematica 是否有一种更快的方法来查找最小值和最大值?

Wolfram mathematica 是否有一种更快的方法来查找最小值和最大值?,wolfram-mathematica,mathematica-7,Wolfram Mathematica,Mathematica 7,我经常写:{Min@#,Max@#}& 但这似乎效率低下,因为表达式必须扫描两次,一次是为了找到最小值,一次是为了找到最大值。有没有更快的方法?表达式通常是张量或数组。在Mathematica编程实践中,我认为这是最快的。我所看到的在mma中加快编译速度的唯一方法是将Compile与C编译目标一起使用,如下所示: getMinMax = Compile[{{lst, _Real, 1}}, Module[{i = 1, min = 0., max = 0.}, For[i

我经常写:
{Min@#,Max@#}&


但这似乎效率低下,因为表达式必须扫描两次,一次是为了找到最小值,一次是为了找到最大值。有没有更快的方法?表达式通常是张量或数组。

在Mathematica编程实践中,我认为这是最快的。我所看到的在mma中加快编译速度的唯一方法是将
Compile
与C编译目标一起使用,如下所示:

getMinMax = 
 Compile[{{lst, _Real, 1}},
   Module[{i = 1, min = 0., max = 0.},
       For[i = 1, i <= Length[lst], i++,
        If[min > lst[[i]], min = lst[[i]]];
        If[max < lst[[i]], max = lst[[i]]];];
        {min, max}], CompilationTarget -> "C", RuntimeOptions -> "Speed"]
您可能完全可以用C编写函数,然后作为dll编译和加载-您可以通过这种方式消除一些开销,但我怀疑您是否会赢得超过几个百分点-这不值得我付出努力

编辑

有趣的是,您可以通过手动删除公共子表达式来显著提高编译解决方案的速度(
lst[[i]]
here):

getMinMax=
编译[{lst,{u Real,1}},
模块[{i=1,最小值=0,最大值=0,温度},
而[i temp,min=temp];
如果[max“C”,运行时选项->“速度”]

{Min@#,Max@#}
快一点

这比它强一点

minMax = Compile[{{list, _Integer, 1}},
   Module[{currentMin, currentMax},
    currentMin = currentMax = First[list];
    Do[
     Which[
      x < currentMin, currentMin = x,
      x > currentMax, currentMax = x],
     {x, list}];
    {currentMin, currentMax}],
   CompilationTarget -> "C",
   RuntimeOptions -> "Speed"];
v = RandomInteger[{0, 1000000000}, {10000000}];
minMax[v] // Timing

对于数组,可以执行最简单的函数操作并使用

Fold[{Min[##],Max[##]}&, First@#, Rest@#]& @ data
不幸的是,它不是速度恶魔。即使对于短列表,5个元素,所有和都至少快7倍,在v.7中未编译。对于25000个元素的长列表,Mark的速度提高了19.6倍,这会变得更糟,但即使在这样的长度下,这个解决方案也只需要0.05秒

但是,我不会把
{Min[#]、Max[#]}&
作为一个选项。对于短列表,Uncompiled的速度是Mark的1.7倍,而对于长列表,Uncompiled的速度是Mark的近15倍(分别是
折叠解决方案的8倍和近300倍)

不幸的是,我无法为编译版本的
{Min[#]、Max[#]}&
、Leonid或Mark的答案获得好的数字,相反,我得到了许多无法理解的错误消息。实际上,
{Min[#]、Max[#]}&
增加了执行时间。不过,折叠式的解决方案有了显著的改进,花费的时间是列奥尼德答案的未编译时间的两倍

编辑:出于好奇,这里有一些未编译函数的计时度量-


每个函数用于横轴上指定长度的100个列表,平均时间(秒)为纵轴。按照时间的升序,曲线是
{Min[#]、Max[#]}&
、马克的答案、莱昂尼德的第二个答案、莱昂尼德的第一个答案以及上面的
折叠
方法。

对于所有做计时的人,我想警告你们,执行顺序是极其重要的。例如,请看以下两个细微不同的计时测试:

(一)


这里的奇人是最后一个
Min

(二)

这里,第一个
Max
的计时最高,第二个
Max
的计时第二高,两个
Min
的计时大致相同且最低。事实上,我希望
Max
Min
所用的时间大致相同,但事实并非如此。前者似乎比后者多花50%的时间。拥有杆位似乎也有50%的障碍

现在与Mark和Leonid给出的算法进行比较:

res =
 Table[
  a = RandomReal[{0, 100}, 10^8];
  {
   {Max[a], Min[a]} // AbsoluteTiming // First,
   {Min@#, Max@#} &@a // AbsoluteTiming // First,
   getMinMax[a] // AbsoluteTiming // First,
   minMax[a] // AbsoluteTiming // First,
   {Min[a], Max[a]} // AbsoluteTiming // First
   }
  , {100}
  ]


在这里我们发现{Max[a],Min[a]}(包括杆位障碍)约为.3s,.1级为Mark的方法;其他的都差不多。

如果你使用Mma7,尤其不值得付出努力-莱昂尼德,你肯定比我更了解数学的原理。你能(用几句话…)告诉我为什么像
{Min@#,Max@#}&
这样的东西不能在内部进行JIT优化吗?这就是为什么Mathematica不是或者不能以这种方式构建?我认为对于更复杂的函数、符号参数等,这种优化很难使其总体上可靠。此外,它与惯用的mma编程有点正交,因为这样做会打破高级思维过程(声明式编程风格)通过指定应如何计算的详细信息。我认为,除非你获得一个数量级的加速,否则这样的优化不会有回报,因为你失去了高级思维(抽象、可读性、屏幕空间)的优势,而高级思维通常更重要,尤其是对于大型项目。非常酷!它大约比我的最快解决方案快两倍。主要原因是你能够减少两次测试次数,因为你实际上使用了更好的算法——你明确地使用了这样一个事实,即在任何给定的元素上,两次测试中只有一次有效-+1。我可能不得不开始在我的所有帖子中指定“For Mathematica 7”。我将把投票权留给其他人,因为我无法测试它。这并不意味着我不感谢你的努力。马克,祝贺1k代表。你能告诉我为什么这种事情不能在运行时优化吗?@Sasha如果你在M7中这样做,马克的代码比Min-Max代码慢10倍,所以这几乎不是一个选项。@Wizard先生,您当然可以在编译函数中调用
Max
Min
,如果您有需要优化的使用
Max
Min
的过程代码,这就很好了。不过,通常没有理由编译对单个内置函数的调用,因为该函数可能已经过优化。此外,优化不会从根本上改变您的算法,所以您的原始代码仍然需要两倍于单个调用
Max
Min
@Mr所需的时间。我想知道您是否愿意在您的问题中添加一个编辑,并绘制时间
cf1 = Compile[{{list, _Real, 1}},
   Module[{sum},
    sum = 0.0;
    Do[sum = sum + list[[i]]^2,
     {i, Length[list]}];
    sum]];
cf2 = Compile[{{list, _Real, 1}},
   Module[{sum, i},
    sum = 0.0;
    For[i = 1, i <= Length[list],
     i = i + 1, sum = sum + list[[i]]^2];
    sum]];
v = RandomReal[{0, 1}, {10000000}];
First /@{Timing[cf1[v]], Timing[cf2[v]]}

{0.685562, 0.898232}
Fold[{Min[##],Max[##]}&, First@#, Rest@#]& @ data
res =
 Table[
  a = RandomReal[{0, 100}, 10^8];
  {
   Min[a] // AbsoluteTiming // First, Max[a] // AbsoluteTiming // First,
   Max[a] // AbsoluteTiming // First, Min[a] // AbsoluteTiming // First
   }
  , {100}
  ]
res =
 Table[
  a = RandomReal[{0, 100}, 10^8];
  {
   Max[a] // AbsoluteTiming // First, Min[a] // AbsoluteTiming // First,
   Min[a] // AbsoluteTiming // First, Max[a] // AbsoluteTiming // First
   }
  , {100}
  ]
res =
 Table[
  a = RandomReal[{0, 100}, 10^8];
  {
   {Max[a], Min[a]} // AbsoluteTiming // First,
   {Min@#, Max@#} &@a // AbsoluteTiming // First,
   getMinMax[a] // AbsoluteTiming // First,
   minMax[a] // AbsoluteTiming // First,
   {Min[a], Max[a]} // AbsoluteTiming // First
   }
  , {100}
  ]