zoukankan      html  css  js  c++  java
  • [翻译]关于Mathematica提速的几点技巧(一)

    本文翻译自Wolfram Blog的一篇文章http://blog.wolfram.com/2011/12/07/10-tips-for-writing-fast-mathematica-code/,我的英语实在是差,翻译很烂看官们就忍忍吧.

    当人们跟我抱怨说Mathematica不够快时,我一般会叫他们去仔细瞧瞧那些令人恼怒的代码.跑得慢的原因通常不是Mathematica的性能问题,而是使用方式不太合适.我想我应该分享一些我在优化Mathematica代码时使用的技巧.

     1.如果可能话,使用机器精度数并尽量提早使用

    如我所见,那些漫不经心的程序员所编写的缓慢的代码的一个共同特点是,一下子让Mathematica考虑到了太多的琐事而忽略自己的实际需求.不必要的附加计算是导致代码缓慢的最普遍原因.

    大部分的数值计算软件中没有这些附加计算,1/3和0.33333333333333被认为是相等的.这些附加计算在你遇到一些复杂难缠的计算时是很有用的.但是在大部分的计算任务中,浮点运算的机器精度已经足够好,更重要的是,计算速度更快.任何小数位数小于16位的十进制输入都会自动被Mathematica按机器精度处理,所以,如何你的计算原则是速度优先,那么就尽可能使用机器精度的小数而不是精确形式(例如1/3).这里有一个简单的例子说明直接使用浮点数进行机器精度的运算会比先用绝对精确形式计算然后转换为小数的方法快50倍左右.当然,我们这个例子里得到的结果是相同的.

     

    这个结果对于符号计算也是成立的.如果你不在乎符号形式的结果和稳定性,那么尽可能早地使用浮点数.例如,在解这个多项式方程之后为系数赋值以避免长达5页的符号形式结果.

    但是如果你在解方程之前就赋值,函数Solve会直接使用速度飞快的数值计算方法.

    当你对表中的数据进行处理时,一定要保证所用的数据都是浮点小数形式的.某一个数据形式的不同就会导致整个表中的数据用另一种灵巧有余而效率不足的方式存储.

     

    32000072

    2. 学习如何使用Compile…

    函数Compile允许你对所编译的函数的参数的类型(实数,整数,复数…)和结构(数值,,矩阵…)做预先声明.这样做损失了Mathematica语言的灵活性,但是另一方面消除了如果参数是符号形式的该怎么办?”的焦虑.同时Mathematica也可以优化程序生成在其虚拟机上运行的高速字节码.不是所有的函数都能被编译,过于简单的代码也可能从编译中得不到好处,但是复杂的低级数值运算代码可以得到极大的速度提升.

    这里有一个例子:

    arg = Range[ -50., 50, 0.25];

    fn = Function[{x}, Block[{sum = 1.0, inc = 1.0}, Do[inc = inc*x/i; sum = sum + inc, {i, 10000}]; sum]];

    Map[fn, arg]; // AbsoluteTiming

    {21.5597528, Null}

    Compile代替Function使计算速度提高了80.

    cfn = Compile[{x}, Block[{sum = 1.0, inc = 1.0}, Do[inc = inc*x/i; sum = sum + inc, {i, 10000}]; sum]];

    Map[cfn, arg]; // AbsoluteTiming

    {0.2652068, Null}

    为了得到更高的性能,我们可以对Compile做进一步的关于并行运算的调整.

    cfn2 = Compile[{x}, Block[{sum = 1.0, inc = 1.0}, Do[inc = inc*x/i; sum = sum + inc, {i, 10000}]; sum], RuntimeAttributes → {Listable}, Parallelization → True];

    cfn2[arg]; // AbsoluteTiming

    {0.1404036, Null}

    ,在我的双核电脑上,速度比原始代码快乐足足150.如果我的CPU有更多核的话速度会更快.

    读者们要意识到很多Mathematica函数比如Table,Plot,NIntegrate会自动进行编译,所以再使用Compile也不会看到一点效率上的提高.

     

    2.5利用Compile生成C代码.

    更进一步,如果你的代码是可编译的话,你可以使用CompilationTarget->”C”选项生成C代码,它会自动调用你的C编译器生成动态链接库(DLL),并链接回Mathematica.这样做会在编译阶段花费更多的时间,但是动态链接库能直接运行在CPU上而不是Mathematica虚拟机,所以速度会更快.

    cfn2C = Compile[{x}, Block[{sum = 1.0, inc = 1.0}, Do[inc = inc*x/i; sum = sum + inc, {i, 10000}]; sum], RuntimeAttributes → {Listable}, Parallelization → True, CompilationTarget → "C"];

    cfn2C[arg]; // AbsoluteTiming

    {0.0470015, Null}

     

    3. 尽可能使用内置函数.

    Mathmatica中函数众多.大部分人不会坐下来一个接着一个地学习这些函数.所以当我看到一些人拼命地实现一些特定功能而没意识到Mathematica早就用内置函数实现其功能时也就不感到奇怪了.这样重新造轮子的行为不仅浪费时间,而且我们这些人的工作就是设计做好的算法以应对各种输入并保证效率,所以绝大部分的内置函数是非常快的.

    如果你发现你的代码已经很不错了但是好像还欠了点什么,查看一下选项和附加参数;通过它们能获得很多特定的功能和抽象的应用.

    有一个这样的例子.比如我想把一个100万个的2阶矩阵转换为100万个一维列表,最容易想到的方法就是使用MapFlatten的组合.

    data = RandomReal[1, {1000000, 2, 2}];

    Map[Flatten, data]; // AbsoluteTiming

    {0.2652068, Null}

    其实整个任务只要Flatten一个函数就可以做到.找到这个方法有点浪费时间,但这是值得的,整个任务的速度比比你的自己造的轮子快了接近4.

    Flatten[data, {{1}, {2, 3}}]; // AbsoluteTiming

    {0.0780020, Null}

    谨记在心---自己造轮子之前先去看看帮助.

    (待续)

     

     

     

     

     

     

  • 相关阅读:
    win10系统u盘安装单个文件超过4g解决办法
    单片机下使用IIC
    uart
    socket
    Linux中 ./configure --prefix命令
    linux下配置安装python3
    linux下的dhcp服务器实现
    安卓出现错误: java.lang.ClassCastException: android.widget.TextView cannot be cast to android.widget.EditText
    C语言基础02
    C语言基础01
  • 原文地址:https://www.cnblogs.com/mymma/p/2659007.html
Copyright © 2011-2022 走看看