<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          寫代碼一天,debug一年?

          共 3864字,需瀏覽 8分鐘

           ·

          2020-12-30 12:47

          點擊?程序猿聲?關(guān)注我們
          各位同學(xué)大家好~今天來閑聊一下。對于學(xué)習(xí)或者科研上需要接觸計算機相關(guān)軟件(比如一些模擬,優(yōu)化軟件等)或者代碼(比如需要實現(xiàn)某些理論進行數(shù)值上的驗證),經(jīng)常會遇到各種各樣的代碼問題,然后也百度不出來,有一種絕望叫做我看了100遍代碼沒發(fā)現(xiàn)問題,可它運行了就是不對!

          說到這,小編得強調(diào)一下,代碼層面的問題是不會有人教你怎么去解決的,因為這些問題太具體了,一切都得靠自己來。但是吧,看著幾千甚至及萬行的代碼,在自己搓出來的shi山之中找一個非語法層面的錯誤,這談何容易!這時候大家想必更絕望了,自己找又找不出錯誤,別人又幫不了,那豈不是涼了?

          別急,今天小編就來談?wù)劊鯓涌焖俣ㄎ粏栴},從而對癥下藥,解決問題。與其坐著絕望,不如自己動手豐衣足食!當(dāng)然了,對于語法錯誤或者配置錯誤導(dǎo)致代碼無法運行的,這些根本不算錯誤,不在本文的討論之列哦。


          一、大致定位問題


          大家首先要明確一點,錯誤不會憑空產(chǎn)生,如果結(jié)果與預(yù)期不符合,那么在整個過程中肯定存在著大大小小的錯誤。第一步首先是要定位問題,相信寫代碼的同學(xué),在開始之前肯定會有一套理論支撐,而代碼無非就是把理論落實到了機器上面,最后發(fā)現(xiàn)運行結(jié)果與自己預(yù)期的不一致。好了,大家想想,為什么不一致?因為從理論上來說這個結(jié)果應(yīng)該是A,而代碼卻給出了B。現(xiàn)在,大家記住這句話,因為我們下面的找錯過程都是基于這句話進行的。


          從理論推導(dǎo)到代碼落地,出現(xiàn)問題的大范圍一般有以下幾個地方:


          a. 輸入錯誤

          如果算法提示找不到可行解,那么是不是數(shù)據(jù)設(shè)計的有問題,需要檢查一下。這個比較簡單。


          b. 理論上的錯誤

          你的理論推導(dǎo)不正確,這是最根源的錯誤。沒啥好說的,趕緊去修正理論。那么怎樣判斷是理論上的錯誤呢?很簡單,你把代碼中跑的數(shù)據(jù),給手動模擬一遍,如果你堅信理論是正確的話,那么你手工模擬的結(jié)果應(yīng)該也是在預(yù)期之內(nèi)的。如果不是的話,那很有可能就是理論出現(xiàn)了問題。tip:手動模擬數(shù)據(jù)量不要太大,不然累死你。


          c. 代碼邏輯出現(xiàn)了錯誤

          這是最常見的,也是最棘手的錯誤,畢竟咱們都是咱在巨人肩膀上做的研究(大部分理論前人已經(jīng)給我們證明好了),沒見過豬跑,總吃過豬肉,理論上出錯的可能性還是比較小的。而并非每個人都是代碼老司機,秋名山碼神,大多數(shù)都是剛?cè)胄械男率郑圆涣粜膶懧┮粋€else導(dǎo)致邏輯錯誤也是大大有可能的。


          這方面的原因判斷也不麻煩,如果你做了上一步的手工模擬以后,發(fā)現(xiàn)手工模擬的結(jié)果和理論預(yù)期是一致的,那么很大概率是代碼的鍋。


          二、找出問題所在


          定位問題是解決問題的第一步,我見過很多人遇到問題,居然原因都不找就坐在屏幕前絕望的。作為科研人,這是非常不可取的,我們要有迎難而上的決心和courage,只要思想不滑坡,辦法總比困難多嘛……


          對于理論上的問題,基本上你手工模擬一遍以后就能發(fā)現(xiàn)那個地方不合理,那么修正一下模型或者推導(dǎo)就行了,比如哪里推導(dǎo)錯了一個小數(shù)點等等。這個就是根據(jù)你做的主題以及個人一些科研經(jīng)驗來修復(fù)了,小編也沒啥經(jīng)驗。


          而對于代碼邏輯上的問題,那就是咱們今天要講的重點了。最有效也是最簡單粗暴的做法就是debug!當(dāng)然這個概念太廣了,針對不同的方向有一套不同的法子,比如算法、開發(fā)等。小編就著這個運籌算法這個方向的兩大類算法(啟發(fā)式和精確解)給大家介紹一下一些debug的思路。


          首先無論是對于什么算法,在初版完成以后,第一件要做的事情是寫一個check的程序。這個程序有什么作用呢?第一,檢查得出結(jié)果中是否所有約束都滿足了。如果存在著某個約束沒有得到滿足,那么你就可以去找找相應(yīng)的約束處理代碼,看看到底是哪里沒做到位。第二,根據(jù)得出來的解,重新把目標(biāo)值從頭到尾,從上到下,從左到右再算一遍,然后檢查重新算的目標(biāo)值和算法得出來的目標(biāo)值是否相同。如果不同,那么可能是你目標(biāo)值的計算出現(xiàn)了問題。


          而目標(biāo)值計算出錯這種類型的錯誤在啟發(fā)式算法中非常常見,為什么呢?大家可以看看我之前講過了幾期推文:


          如何實現(xiàn)一個高效的啟發(fā)式算法?

          如何實現(xiàn)一個高效的啟發(fā)式算法?(VRPTW篇)


          為了能夠?qū)崿F(xiàn)比較快速評估鄰居解,我們很有必要在啟發(fā)式中記錄大量的Delta值,以減少冗余的計算,加快算法的求解速度。如果目標(biāo)值過于復(fù)雜,記錄的Delta值過多,難免會出錯。最后導(dǎo)致目標(biāo)值偏離了真實的目標(biāo)值。因此最后重新驗算目標(biāo)值能夠確保啟發(fā)式算法的結(jié)果無誤。


          而且,對于一個啟發(fā)式而言,得出的解滿足約束,目標(biāo)值又正確,那么就已經(jīng)能算沒有“錯誤”了,至于如何提高解的質(zhì)量……請大家多關(guān)注公眾號哈。


          對于精確式算法而言,它的代碼實現(xiàn)是和你的理論推導(dǎo)緊密聯(lián)系的。不啟發(fā)式那一套達到相同功能隨便怎么來都行,要是你的數(shù)學(xué)推導(dǎo)搞錯了一個小數(shù)點,那么就恭喜你,可能要debug上一年了。。。

          其實像約束不滿足這種錯誤精確式算法里面還是比較好解決的,而這類算法最麻煩的一個地方是,精確式跑出來的居然不是最優(yōu)解(通過和CPLEX結(jié)果進行對比得知)!


          這就比較絕望了,你說你出個bug,比如目標(biāo)值沒算對,或者是約束沒做好,或許還能搶救下。你這下直接找不到最優(yōu)解,茫茫shi山,錯誤要我從何找起?別急!還沒到山窮水盡的地步。


          首先,我們從精確算法的本質(zhì)入手,它的本質(zhì)是什么?窮舉!對,就是窮舉,只不過它在窮舉的同時,會使用一些dominance rules把一些比較差的分支給干掉,這樣在保證最優(yōu)性的同時又能以比較快的速度找到最優(yōu)解。那么,我們就順著這個思路,相比大家的代碼中肯定設(shè)置了一些dominance rules用來加速的。那么,先把dominance rules給注釋掉,或者讓他永遠返回False,就是不會干掉任何一個解。就相當(dāng)于full extension,全遍歷了。這樣是一定能找到最優(yōu)解的,如果找到了,那么問題簡單了,就是dominance rules出了問題。


          如果還是沒找到。。。那么恭喜你,問題又變復(fù)雜了。現(xiàn)在,讓我們喝杯茶思考下人生,再想想還有什么辦法。這個時候就很有必要上終極大法了--逆向調(diào)試法!沒錯,我們之前不是通過CPLEX得出了問題的最優(yōu)解嗎?(前提是你CPLEX的結(jié)果一定要正確,把模型構(gòu)建出來并調(diào)正確,這個應(yīng)該不是很難吧~)。我們通過觀察CPLEX得出的最優(yōu)解,然后逆向回來看算法的執(zhí)行流程,仔細(xì)想想,為什么我們算法沒有得出這個最優(yōu)解呢?


          然后你就回到算法中,看看是哪個部分和解的生成最接近,從那里開始一層一層往上調(diào)試。比如再branch and price求解vrp類問題中,CPLEX得出的一條路徑中有0-1-2-3-4,而branch and price輸出的最優(yōu)解卻沒有這個路徑。大家想想,在bp算法中路徑是通過子問題的labeling algorithm加進去的,我們先在spprc中把每次迭代找到的路徑全部輸出來,看看是否包含了0-1-2-3-4。如果沒有包含,那么就斷定是spprc的問題,如果包含了,就想想是不是branch干掉了。。。


          不信給大家看一下,為了找出我的labeling中為啥沒有找出這條最優(yōu)解的路徑,我在擴展過程中寫了如下調(diào)試代碼:



          可真是人肉調(diào)試了,不可謂不壯觀。。。


          三、小結(jié)


          總之,debug是一門大學(xué)問,它的中心思想是定位問題的所在,才能對癥下藥。定位的過程也應(yīng)當(dāng)是先從大到小,再從內(nèi)到外。所謂從大到小,先大概定位一下錯誤可能出現(xiàn)在了哪些地方,然后再從內(nèi)部一層一層往外驗證。


          這個確實是需要經(jīng)驗,而且需要大量的時間。調(diào)試本身也是發(fā)現(xiàn)問題,解決問題,偶然的時候還能發(fā)現(xiàn)理論上的一些致命錯誤。因此是一門體力兼腦力活。每次有人問我,代碼出現(xiàn)了邏輯上的錯誤該怎么辦?我的回復(fù)往往只有一句話:System.out.println();因為這個真的很有用!!!


          然后,建議大家不要去看代碼,要去System.out.println();即不斷的輸出,通過輸出來發(fā)現(xiàn)問題。因為你自己寫的代碼,寫完以后你就給大腦灌輸了我的代碼一定是對的這種想法,無論你看10遍還是100遍,基本上都很難發(fā)現(xiàn)問題。而且代碼量這么大,你從頭到尾看得過來嗎?


          每次遇到問題的時候,我思考的不是怎么去解決這個問題,而是怎么去debug這個問題,即:我要輸出什么信息,在哪里輸出,才能定位到這個問題?想好以后便開始debug了。找出了問題,才能去修復(fù)它!所以呀,大家遇到問題一定要立刻馬上right now動起來,手動起來,眼動起來,腦瓜子動起來。不然,坐著什么也不干,把他丟在一邊,久而久之,這個問題就成了歷史遺留問題。若干天后你就再也不想碰他了,這樣就前功盡棄了。。。


          ,小編實在是太笨了,本來想把這些方法好好給寫一寫,后來寫著寫著就亂起來了,因此大家也就將就著看一看吧。畢竟這東西吧,只可意會不可言傳。每個人都有自己的一些經(jīng)驗和法則,小編只是把自己的一些經(jīng)驗分享出來而已。


          推薦閱讀:

          干貨 | 想學(xué)習(xí)優(yōu)化算法,不知從何學(xué)起?

          干貨 | 運籌學(xué)從何學(xué)起?如何快速入門運籌學(xué)算法?

          干貨 | 學(xué)習(xí)算法,你需要掌握這些編程基礎(chǔ)(包含JAVA和C++)

          干貨 | 算法學(xué)習(xí)必備訣竅:算法可視化解密

          干貨 | 模擬退火、禁忌搜索、迭代局部搜索求解TSP問題Python代碼分享

          點分享
          點收藏
          點點贊
          點在看
          瀏覽 78
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  韩国精品无码一区二区三区18 | 日韩欧美卡一卡二 | 91成人无码在线电影 | 亚洲精品乱码久久久久久蜜芽 | 国产又粗又猛又黄又爽无遮挡 |