国产精品久久久久久2021,日韩精品无码av中文无码版,亚洲精品久久久午夜麻豆,无码成人精品日本动漫纯h

010-68421378
當(dāng)前您所在的位置:首頁(yè)>新聞中心>新品發(fā)布

Wolfram | 10個(gè)編寫快速運(yùn)行的Mathematica代碼的小訣竅

發(fā)布時(shí)間:2020/06/22 瀏覽量:4389
分享一下我在優(yōu)化Mathematica代碼時(shí)首先會(huì)看的一些內(nèi)容。

當(dāng)我聽到人們說(shuō)Mathematica不夠快的時(shí)候,我通常會(huì)提出想要看一下這段令他們煩惱的代碼,然后會(huì)發(fā)現(xiàn),其實(shí)并不是Mathematica本身的表現(xiàn)不夠好,而是Mathematica沒(méi)有被最優(yōu)使用。我覺(jué)得我應(yīng)該和大家分享一下我在優(yōu)化Mathematica代碼時(shí)首先會(huì)看的一些內(nèi)容。

01

如果可以的話盡量盡早使用浮點(diǎn)數(shù)

我最??吹降膶?dǎo)致代碼變慢的問(wèn)題是,程序員會(huì)不經(jīng)意地讓Mathematica做超出需要的細(xì)致的事情。沒(méi)必要的代數(shù)精確是其中最常見的問(wèn)題。

在多數(shù)與數(shù)字相關(guān)的軟件中,是不需要這么精確的代數(shù)的。1/3和0.33333333333333是一樣的。當(dāng)你碰到特別嚴(yán)重的在數(shù)字上不穩(wěn)定的問(wèn)題時(shí)這個(gè)差異可能會(huì)被放大的特別明顯,但是,在大多數(shù)情況中,浮點(diǎn)數(shù)已經(jīng)足夠使用了,而且最重要的是,浮點(diǎn)數(shù)運(yùn)算更快。Mathematica中,任何小于16位的小數(shù)都被看作是機(jī)器浮點(diǎn)數(shù),所以如果更想要速度而可以舍棄一些精確性的時(shí)候,記得用小數(shù)(比如,三分之一輸入為1./3.)。以下是一個(gè)例子,可以看到使用浮點(diǎn)數(shù)是精確數(shù)運(yùn)行速度的50.6倍。在這個(gè)例子中,兩個(gè)數(shù)字的使用得到的是同一個(gè)結(jié)果。

在符號(hào)運(yùn)算中也是這樣。如果你不是很在意符號(hào)式的結(jié)果,并且計(jì)算的穩(wěn)定性也不是問(wèn)題的話,那么盡快使用數(shù)值作為替代。比如,求解下面的二項(xiàng)式符號(hào)計(jì)算時(shí),在使用數(shù)值作為替代之前,這個(gè)代碼可能會(huì)讓Mathematica生成長(zhǎng)達(dá)五頁(yè)的中間符號(hào)表達(dá)式。

但是如果先用數(shù)值替代,那么Solve會(huì)使用更快的數(shù)值方法。

當(dāng)用數(shù)據(jù)列表工作時(shí),使用實(shí)數(shù)的方法必須保持一致。只要一個(gè)精確的數(shù)值就可以讓整個(gè)數(shù)據(jù)組處于一個(gè)更靈活但是缺乏效率的形式中。

 

02
學(xué)會(huì)Compile
 

Compile函數(shù)接受Mathematica的代碼,并讓你預(yù)先聲明輸入?yún)?shù)的類型(比如實(shí)數(shù)、復(fù)數(shù)等)和結(jié)構(gòu)(如數(shù)值、列表、矩陣等)。這雖然失去了Mathematica語(yǔ)言靈活性的優(yōu)勢(shì),但是可以免于擔(dān)心類似于“如果參數(shù)是符號(hào)怎么辦?”的問(wèn)題,Mathematica也可以最優(yōu)化程序并創(chuàng)建一個(gè)字節(jié)碼在虛擬器上運(yùn)行。并不是所有東西都可以被編譯,且簡(jiǎn)單的代碼可能不會(huì)有太大效果,但是那種復(fù)雜的低階數(shù)字代碼速度可以得到大大的提升。

下面是一個(gè)例子:

使用Compile可以比Function的運(yùn)行速度提高80倍。

但是我們可以在Compile函數(shù)中加入一些代碼的可并行性質(zhì),這樣可以生成更好的結(jié)果。

在我的雙核處理器電腦上,我的運(yùn)行結(jié)果比原本快150倍,如果是多核處理器那么效果會(huì)更加明顯。

但是要注意,很多Mathematica函數(shù)比如Table、Plot、NIntegrate等會(huì)自動(dòng)編譯它們的參數(shù),這樣的話你使用上述方法可能不會(huì)看到任何速度上的提升。

 

02.5
使用Compile生成C代碼
 
 

另外,如果你的代碼可編譯,你還可以使用選項(xiàng)CompilationTarget->“C”來(lái)生成C代碼,調(diào)用你的C編碼器并將其匯編成一個(gè)DLL,并把這個(gè)DLL鏈接回Mathematica,都是自動(dòng)操作的。在編譯階段,DLL直接在CPU上運(yùn)行而非Mathematica的虛擬器,所以會(huì)更快得到結(jié)果。

03
使用內(nèi)置函數(shù)
 
 

Mathematica有很多函數(shù)。起碼半數(shù)以上的人可能不會(huì)坐下來(lái)學(xué)習(xí)所有函數(shù)。所以當(dāng)我看見有些人會(huì)寫一些代碼而沒(méi)有意識(shí)到其實(shí)Mathematica知道怎么做這些操作的時(shí)候,我一點(diǎn)也不意外。這種重復(fù)操作不僅是浪費(fèi)時(shí)間,而且公司是花錢請(qǐng)程序員來(lái)開發(fā)研究運(yùn)行這些操作的最有效方法,所以內(nèi)置的函數(shù)一般是非常快的。

如果你發(fā)現(xiàn)有些結(jié)果很接近了但是不完全對(duì)的時(shí)候,此時(shí)可以檢查選項(xiàng)和參數(shù),通常它們會(huì)概括可以覆蓋很多特殊用法或者專有應(yīng)用的函數(shù)。

下面舉一個(gè)這樣的例子。如果我有一個(gè)一百萬(wàn)2x2矩陣的列表,我想把該列表轉(zhuǎn)換成一百萬(wàn)個(gè)包含四個(gè)元素的列表,概念上來(lái)說(shuō)最簡(jiǎn)單的方法是用Map把已經(jīng)用Flatten扁平化過(guò)的數(shù)據(jù)進(jìn)行映射即可。

但是Flatten本身知道怎么把整個(gè)步驟完成,你只要說(shuō)明數(shù)據(jù)結(jié)構(gòu)的第二層和第三層應(yīng)該被合并而第一層不動(dòng)就可以了。說(shuō)明這種細(xì)節(jié)的內(nèi)容可能相對(duì)來(lái)說(shuō)是比較細(xì)致的工作,但是只需要使用Flatten就能完成整個(gè)扁平化工作可以讓整個(gè)進(jìn)程比你自己手動(dòng)做這些程序要快將近4倍。

所以記住:在運(yùn)行代碼之前在幫助菜單里先搜索一遍。

 

04
使用Wolfram Workbench
 
 

Mathematica對(duì)于某些種類的編程錯(cuò)誤容忍度很高——如果你忘記在正確的時(shí)候初始化一個(gè)變量,Mathematica會(huì)以符號(hào)的模式順利運(yùn)行,而并不會(huì)有循環(huán)計(jì)算或者預(yù)料之外的數(shù)據(jù)類型出現(xiàn)。如果你只想要一個(gè)答案的話這個(gè)功能是很棒的,但是這也會(huì)讓你沒(méi)有得到最優(yōu)的解答。

Workbench會(huì)在幾個(gè)方面幫助你。首先它會(huì)幫你排除程序問(wèn)題,并把大型的代碼項(xiàng)目組織得更好,整齊易讀的代碼會(huì)讓程序員更好地寫優(yōu)秀的代碼。但是最關(guān)鍵的功能在于分析器會(huì)告訴你是哪一行代碼用光了時(shí)間,而且會(huì)告訴你調(diào)用這些代碼用了多少時(shí)間。

看下這個(gè)例子,一個(gè)很可怕的執(zhí)行斐波那契數(shù)的方法。如果你沒(méi)有考慮到數(shù)列的雙重遞歸,你可能會(huì)驚訝計(jì)算fib[35]怎么會(huì)需要22秒鐘(大約和內(nèi)置函數(shù)計(jì)算Fibonacci[1000000000]所有208,987,639位數(shù)字需要的時(shí)間一樣)(請(qǐng)看訣竅3)。

在分析器中運(yùn)行這個(gè)代碼可以解釋這個(gè)現(xiàn)象的原因。主要規(guī)則被援引9,227,464次,fib[1]的值被請(qǐng)求18,454,929次。

學(xué)習(xí)代碼能做什么,而不是想當(dāng)然,會(huì)讓你眼界大開。

 

05
記住你將來(lái)會(huì)需要用到的值
 

這個(gè)編程訣竅對(duì)任何語(yǔ)言都管用。Mathematica認(rèn)為你想知道的是這個(gè):

這省去了用任何值調(diào)用 f 的結(jié)果,這樣的話如果再用相同數(shù)值調(diào)用 f,Mathematica不需要再算一遍。這里你就是用內(nèi)存換取計(jì)算速度,所以如果你的函數(shù)要用大量不同數(shù)值調(diào)用而不太重復(fù)的時(shí)候這個(gè)方法可能不合適。但是如果輸入的范圍有限,那么這個(gè)方法就很有用了。以下就是如何拯救我剛才提到的來(lái)解釋訣竅3的例子的方法??梢园训谝粭l規(guī)則改成這樣:

然后速度立刻就可以提升,因?yàn)閒ib[35]現(xiàn)在只需要用主要的規(guī)則運(yùn)算33次。查詢之前的結(jié)果可以防止循環(huán)遞歸fib[1]的問(wèn)題。

 

06
并行
 
 

有很多Mathematica的操作都會(huì)自動(dòng)在本地核中并行運(yùn)行(大部分是代數(shù)、圖像處理和統(tǒng)計(jì)),如果需要手動(dòng)的話,Compile也可以。但是對(duì)于其他操作來(lái)說(shuō),或者如果你想在遠(yuǎn)程硬件上并行操作,你可以試用內(nèi)置的并行編程架構(gòu)來(lái)完成。

有一個(gè)這樣工具的集合,但是都是為非常獨(dú)立的任務(wù)服務(wù)的,比如ParallelTable, ParallelMap,ParallelTry,還有很多。每個(gè)這樣的小工具都可以自動(dòng)進(jìn)行通信、工作管理和收集結(jié)果。發(fā)送任務(wù)和回收結(jié)果需要一點(diǎn)時(shí)間,所以在減少時(shí)間和增加時(shí)間上會(huì)有需要一個(gè)取舍。你的Mathematica有四個(gè)計(jì)算內(nèi)核,如果你有額外的CPU可使用的話,還可以通過(guò)gridMathematica在此基礎(chǔ)上提高這一性能。這里由于我用的是雙核電腦,ParallelTable實(shí)際將我的運(yùn)算時(shí)間縮少了一半。如果有更多CPU則會(huì)得到更好的結(jié)果。

任何Mathematica可以做的事情都可以以并行方法運(yùn)行。比如,你可以給遠(yuǎn)程硬件發(fā)送一個(gè)并任務(wù)集合,每個(gè)任務(wù)都在CPU或GPU中編譯和運(yùn)行。

 

06.5
想想CUDALink和OPENCLLink
 
 

如果你有GPU硬件,有一些用批量并行運(yùn)行方法可以做的非??斓氖虑?。除非這些最優(yōu)化CUDA函數(shù)恰好可以做你想要它們做的事情,否則你還要做一點(diǎn)額外的工作,但是CUDALink和OpenCLLink 工具可以為你自動(dòng)化很多繁瑣的細(xì)節(jié)。

 

07
使用Sow和Reap累積大量數(shù)據(jù)(不是AppendTo)
 
 

因?yàn)镸athematica數(shù)據(jù)結(jié)構(gòu)的靈活性,AppendTo不會(huì)假設(shè)你要追加的是一個(gè)數(shù)字,因?yàn)槟阋芳拥目赡苁且粋€(gè)文件、音頻或者圖像等。所以AppendTo必須為所有數(shù)據(jù)創(chuàng)建一個(gè)新的副本,并重新調(diào)整架構(gòu)以適應(yīng)新追加的信息。當(dāng)數(shù)據(jù)累積的時(shí)候這個(gè)過(guò)程會(huì)變得越來(lái)越慢。(而且構(gòu)建data=Append[data,value]與AppendTo一樣。)

嘗試使用Sow和Reap。Sow會(huì)舍棄你想要累積的值,而Reap收集它們并一次性在末尾建立一個(gè)數(shù)據(jù)對(duì)象。下列范例是等價(jià)的:

08
使用Block或With而非Module
 
 

Block,With和Module都是本地化構(gòu)建的工具,但是屬性上有些小區(qū)別。根據(jù)我的經(jīng)驗(yàn),95%以上的幾率在我寫的代碼中Block和Module是可以互相替換的,但是Block通常快一點(diǎn),而在另一些例子中(Block的變量在只讀狀態(tài)的情況下)With會(huì)快一些。

09
少用模式匹配
 

模式匹配很好,可以讓項(xiàng)目中復(fù)雜的任務(wù)變得簡(jiǎn)單一點(diǎn)。但是它有時(shí)會(huì)很慢,尤其是像BlankNullSequence這種比較復(fù)雜的模式(通常寫作“___”)中,可能會(huì)花很長(zhǎng)時(shí)間仔細(xì)在你的數(shù)據(jù)中搜索一些——你作為一個(gè)程序員可能已經(jīng)可以判斷的——不存在的模式。如果想要速度的話,那么選擇范圍更窄的模式,或者不用模式會(huì)更好。

比如,下面范例使用了模式,在一行代碼中簡(jiǎn)潔地執(zhí)行了冒泡排序:

上例概念上很簡(jiǎn)單,但是比起這個(gè)我最開始學(xué)習(xí)編程的時(shí)候就學(xué)過(guò)的列出步驟的方法來(lái)說(shuō)還是要慢很多:

當(dāng)然在這個(gè)例子中你可以用內(nèi)置函數(shù)(參見訣竅3),這個(gè)內(nèi)置函數(shù)會(huì)使用比冒泡排序更好的排序算法。

 

010
嘗試不同的方法
 
 

Mathematica的一個(gè)很重要的優(yōu)點(diǎn)是,它可以用不同的方式處理同一個(gè)問(wèn)題。它允許你按照你自己的想法編程,而不是為了編程語(yǔ)言的風(fēng)格重構(gòu)你的問(wèn)題。但是,概念上簡(jiǎn)單和計(jì)算效率不是一件事。有時(shí)候容易懂的想法可能會(huì)需要更多的工作才能實(shí)現(xiàn)。

但是另一個(gè)問(wèn)題是,因?yàn)镸athematica中最優(yōu)化和一些絕妙算法都是自動(dòng)應(yīng)用的,所以很難預(yù)測(cè)什么時(shí)候Mathematica又會(huì)做出另一個(gè)絕妙的操作。比如,下例是兩種計(jì)算階乘的方法,第二種比第一種快10倍。

為什么?你可能會(huì)猜可能Do的循環(huán)很慢,或者所有這些任務(wù)緩存都需要時(shí)間,或者可能第一次執(zhí)行的時(shí)候有什么東西出了問(wèn)題,但是實(shí)際的原因很難預(yù)料到。Time有一個(gè)很聰明的二元分離的小技巧,可以在當(dāng)你有大量整數(shù)參數(shù)的情況下使用,即將循環(huán)將參數(shù)分成兩個(gè)更小的乘積(1*2*…*32767)*(32768*…*65536),而不是把這個(gè)參數(shù)從第一個(gè)用到最后一個(gè)。當(dāng)然要做的乘法數(shù)量還是一樣,但是不會(huì)再包括數(shù)值非常大的整數(shù),所以平均來(lái)說(shuō),運(yùn)算的速度會(huì)更快。在Mathematica中有很多這樣隱藏的小魔法,而且每次新版本發(fā)布都會(huì)有更多的小技巧加入。

當(dāng)然最好的方法還是使用內(nèi)置函數(shù)(又說(shuō)到訣竅3了):

Mathematica可以做非常高級(jí)的計(jì)算,而且有強(qiáng)大的功能和極高的精確性,但是這兩者并不總能兼得。我希望這些訣竅可以在快速編程、快速執(zhí)行和精確結(jié)果的沖突訴求中對(duì)你有些許幫助。

 

用可計(jì)算文件格式(CDF)文件的形式下載這篇博文。

https://blog.wolfram.com/data/uploads/2011/12/10TipsForMathematicaCode.cdf

下一篇:SciChart WPF v6.2.0來(lái)了!
上一篇:Tenable.ot:為IT安全人員和OT工程師提供了全面的安全工具和報(bào)告

                               

 京ICP備09015132號(hào)-996 | 違法和不良信息舉報(bào)電話:4006561155

                                   © Copyright 2000-2026 北京哲想軟件有限公司版權(quán)所有 | 地址:北京市海淀區(qū)西三環(huán)北路50號(hào)豪柏大廈C2座11層1105室

                         北京哲想軟件集團(tuán)旗下網(wǎng)站:哲想軟件 | 哲想動(dòng)畫

                            華滋生物