MATLAB:你不知道的12個基礎(chǔ)知識

??之前的文章,可能過于晦澀難懂匙睹。再加上我寫的也不好愚屁,解釋的不夠清楚,導(dǎo)致最后看的人不多痕檬。這次來點簡單輕松的霎槐,爭取大家都能看懂。
??下面都是我自己個人總結(jié)的梦谜,未經(jīng)本人許可丘跌,禁止轉(zhuǎn)載(長文預(yù)警,能仔細看完的唁桩,看完還不主動點贊收藏的闭树,我覺得應(yīng)該沒有。)

1.pi\neq\pi

??我們知道荒澡, \pi 是一個小數(shù)點后無限位的無理數(shù)报辱,計算機是無法精確表示的。所以单山,在MATLAB中碍现,pi只是一個近似值,3.141592653589793米奸,精確到小數(shù)點后15位昼接。

pi  ==  3.141592653589793  
% ans = 1

2. sin(pi)≠0

??因為pi\neq\pi,導(dǎo)致的一個問題是躏升,sin(pi)并不精確的等于0辩棒。事實上,所有的sin(n*pi)都不為0膨疏,且互不相等一睁。

sin(pi)  
% ans = 1.224646799147353e-16  
sin(2*pi)  
% ans = -2.449293598294706e-16  
sin(3*pi)  
% ans = 3.673940397442059e-16

甚至可以看到,當(dāng)n足夠大時佃却,sin(n*pi)會接近于±1.

sin(4e16*pi)  
% ans = -0.999478704149319

正確地計算sin(n\pi)的方法是者吁,利用sinpi函數(shù)。這是一個R2018b推出的新函數(shù)饲帅,能夠精確計算形如sin(n\pi)的值复凳。

sinpi(1)  ==  0  
% ans = 1  
sinpi(4e16)  ==  0  
% ans = 1  
sinpi(1/4)  ==  sqrt(2)/2  
% ans = 1

如果是早期版本的MATLAB瘤泪,就只能將弧度制轉(zhuǎn)換成角度制后,用sind函數(shù)計算了育八。

sind(180)  ==  0  
% ans = 1  
sind(180*4e16)  ==  0  
% ans = 1  
sind(45)  ==  sqrt(2)/2  
% ans = 1

3. 0.7/0.1≠7 但0.2/0.1=2

0.7/0.1  ==  7  
% ans =0

??這是由于浮點數(shù)的表示機制決定的对途,計算機是二進制的,在表示某些小數(shù)時髓棋,并不是精確表示的实檀。由于二進制的限制,計算機無法精確的表示0.7按声。

format long 
0.7/0.1  
% ans = 6.999999999999999

??事實上膳犹,計算機中,所有的數(shù)不是連續(xù)的签则,而是離散的须床,每個浮點數(shù)和下一個更大的浮點數(shù)之間都存在一個較小的間隔,這個間隔可以用eps函數(shù)來計算渐裂。
??例如豺旬,1234567890.0123456789最后一位的9是無效的,因為即使是雙精度double也無法精確到最后一位芯义。

1234567890.0123456789  ==  1234567890.012345678  
% ans = 1  
% 左邊的數(shù)比右邊的數(shù)多了最后一位的9哈垢,但仍然是相等的。

那么扛拨,如果遇到類似的問題時耘分,如何輸出正確的判斷結(jié)果呢?一種可行的方法是全部轉(zhuǎn)換為整數(shù)

(0.7*10)/(0.1*10)  ==  7  
% ans = 1

或者绑警,求兩個數(shù)的差值求泰,看差值的絕對值是否足夠小。如果精度要求不高的話,可以自己設(shè)定一個較小的閾值

abs(0.7/0.1  -  7)  <=  1e-6  
% ans = 1

如果精度要求高的話,可借助于eps函數(shù)

abs(0.7/0.1  -  7)  <=  eps(7)  
% ans = 1

4. 矩陣轉(zhuǎn)置.' 與' 的區(qū)別

??大多數(shù)教程计盒、網(wǎng)上博客渴频、甚至?xí)锩娑紩岬剑琈ATLAB的矩陣轉(zhuǎn)置運算符'北启。事實上卜朗,這是一個很大的誤區(qū)。A'是矩陣A的共軛轉(zhuǎn)置咕村,只不過大多數(shù)情況下场钉,A虛部為0,無法體現(xiàn)出共軛懈涛。

A =  [1,  2;  3,  4]; 
A'  
% ans = [1, 3; 2, 4]

但是逛万,如果A是復(fù)數(shù)矩陣,就會出現(xiàn)共軛批钠。

A =  [1+2i,  3+4i;  5+6i,  7+8i];
A'  
% ans = [1-2i,5-6i; 3-4i,7-8i];

正確的轉(zhuǎn)置運算符是.'

A =  [1+2i,  3+4i;  5+6i,  7+8i]; 
A.'  
% ans = [1+2i,5+6i; 3+4i,7+8i];

5. 每次生成相同的隨機數(shù)

??在知乎上面有很多類似的問題宇植,如何保證每次生成的隨機數(shù)相同得封。我看到很多回答都是說,將生成的隨機數(shù)save成本地mat文件指郁,然后在下次要用的時候忙上,用load函數(shù)讀取mat文件中的值。這種方法也不是不可以闲坎,但是效率比較低晨横,文件讀寫可能會花費大量的時間。
??事實上箫柳,MATLAB生成的隨機數(shù)都是偽隨機數(shù),也就是說啥供,按照某種特定的算法生成的悯恍。這意味著,隨機數(shù)的生成過程是可以復(fù)現(xiàn)的伙狐,可以通過控制隨機數(shù)生成器的"種子"涮毫,確保每次生成相同的隨機數(shù)。
??rng函數(shù)用于控制隨機數(shù)的生成贷屎。

% 保存當(dāng)前隨機數(shù)生成器的狀態(tài)("種子")
scurr =  rng();  
% 生成隨機數(shù) 
A =  randn([1,4])  
% A = [-0.4611 0.1132 1.3442 -0.4842];  

% 每次想要生成相同的隨機數(shù)時  
% 先用rng函數(shù)將生成器的狀態(tài)置為上次保存的
scurr  rng(scurr); 
A =  randn([1,4])  
% A = [-0.4611 0.1132 1.3442 -0.4842];

6. 如何生成類似于A1,A2,....,A100的變量

??在知乎上也有很多類似的問題罢防,紛紛表示用手一個一個的敲進去太累了。大部分的回答是唉侄,用eval咒吐、feval之類的函數(shù)。但是eval函數(shù)的效率很低属划,而且代碼的可讀性會很差恬叹。
??事實是,絕大部分情況下同眯,并不需要生成A1,A2,...,A100這樣的變量绽昼。真正需要做的是,改變自己的編程思路须蜗,給數(shù)組A增加一個額外的維度硅确,用這個維度來表示A1到A100。

% 例如A1到A100,  
% An每個變量的值為[n,n+1,...,n+99]  
% 用eval函數(shù)可以完成上述賦值  
for ii =  1:100  
    eval(['A'  num2str(ii)  '='  num2str(ii)  ':'  num2str(ii+99)]);  
end  

% 事實上明肮,只需要給A多一個維度就可以了  
% 這樣當(dāng)你想要使用A1變量時菱农,只需要調(diào)用A(1,:)就可以了 
for ii =  1:100  
    A(ii,:)  = ii:ii+99;  
end

如果A1,A2,...A100每個變量的長度不一樣,不能放到一個矩陣里面怎么辦晤愧?改用cell數(shù)組

% 例如A1到A100,  
% An每個變量的值為[n,n+1,...,100]  
% 用eval函數(shù)可以生成完成上述賦值  
for ii =  1:100  
    eval(['A'  num2str(ii)  '='  num2str(ii)  ':'  num2str(100)]);  
end

% 使用cell元胞數(shù)組完成類似的賦值  
% 當(dāng)你想使用A1變量時,只需要調(diào)用A{1}  
for ii =  1:100 
    A{ii}  = ii:100;  
end

7. i 和j都是MATLAB內(nèi)置函數(shù)(built-in function)

??在上面的例子大莫,我在for循環(huán)里面的循環(huán)變量用的ii,而不是常用的i官份,這是為什么呢只厘?因為在MATLAB中烙丛,i是一個內(nèi)置函數(shù),代表的是虛數(shù)單位(j也是)羔味,用于輸入復(fù)數(shù)河咽。

% 確保當(dāng)前工作區(qū)沒有i,j變量 
clear i  j  
i  ==  j  
% ans = 1

??當(dāng)然可以將ij覆蓋為變量,但是覆蓋內(nèi)置函數(shù)不是一個好的編程習(xí)慣赋元,同時也會帶來運行速度上的降低忘蟹。而且,一旦程序中涉及輸入復(fù)數(shù)搁凸,就可能會出現(xiàn)錯誤媚值。

% 下面的代碼中,想實現(xiàn)的是復(fù)數(shù)1+2i  
% 但實際上,A = [3,5,7,9,11] 
a =  1; 
b =  2;  
for  i  =  1:5  
    A(i)  = a + b*i;  
end

那么,為了避免這個問題护糖,一種良好的編程習(xí)慣就是褥芒,將循環(huán)變量i,j改成ii,jj。在寫虛數(shù)單位時嫡良,用1i,1j代替i,j.

for ii =  1:5 
    A(ii)  = a + b*1i;  
end

8. dbstop if error真的很好用

??當(dāng)我作為一個MATLAB新手首次接觸這個命令時锰扶,感覺仿佛迎來了春天,給我?guī)淼恼鸷巢粊営诘谝淮谓佑|bsxfun寝受。
??在調(diào)試MATLAB程序時坷牛,如果有錯誤,我們經(jīng)常需要在出錯的那一行加上斷點很澄,然后重新運行腳本或函數(shù)京闰。這樣程序會運行到斷點前,我們就可以觀察出錯前各個變量的值甩苛,進而找到bug忙干。這一過程需要經(jīng)歷運行,出錯浪藻,加斷點捐迫,再運行這一過程。
??如果在MATLAB命令行輸入dbstop if error爱葵,然后再運行程序施戴,這樣程序會自動停在出錯的那一行,這時可以直接觀察各個變量的值萌丈,省去了自己加斷點的過程赞哗。而且,不需要每次運行程序前都輸入dbstop if error辆雾,只需要輸入一次就OK肪笋。
如果想要在每次warning前暫停程序,也可以在命令行輸入dbstop if warning

9. 調(diào)試程序時在不同的函數(shù)之間傳遞值

??我們知道,如果想在想讓一個值在各個函數(shù)都使用藤乙,可以將其設(shè)為全局變量(global)猜揪,此時聲明了該全局變量的函數(shù),可以互相傳遞這個值坛梁。
??那么而姐,如果是在調(diào)試時,程序已經(jīng)運行了一半划咐,停在了某個斷點前拴念,想將函數(shù)內(nèi)當(dāng)前的某個值傳遞到上一個函數(shù),或者直接傳遞到基礎(chǔ)工作區(qū)褐缠,用于后續(xù)對變量值的仔細分析政鼠,怎么辦?(基礎(chǔ)工作區(qū)就是队魏,MATLAB的主函數(shù)空間缔俄,當(dāng)程序運行完后的工作區(qū)。)
??解決方法是使用assignin函數(shù)器躏。
??assignin函數(shù)能夠在基礎(chǔ)工作區(qū)(base),或者調(diào)用當(dāng)前函數(shù)的函數(shù)工作區(qū)(caller)內(nèi)蟹略,產(chǎn)生一個新的變量登失,該變量的值等于當(dāng)前函數(shù)空間內(nèi)的某個值。(比較繞口挖炬,仔細看下面例子吧)
??例如揽浙,下面的函數(shù)myfun, 函數(shù)本身是用于畫圖的,不會返回任何值意敛。

function  myfun() 
a =  randn([1,1e4]);  
plot(a);  
end

第3行前有一個斷點馅巷,程序停在斷點前。這時草姻,我們可以看到a的值钓猬,但我們希望將a的值導(dǎo)入到基礎(chǔ)工作區(qū),進行后續(xù)的分析撩独。(一旦我們退出調(diào)試敞曹,或者繼續(xù)運行程序,都無法得到a的值综膀。當(dāng)然澳迫,可以修改myfun,給它添加一個返回值a剧劝,然后重新運行程序橄登。但是,如果是一個復(fù)雜的程序,花了很多時間程序才運行到這個位置拢锹,重新開始意味著前功盡棄谣妻。)
??這時,我們可以在調(diào)試時面褐,在MATLAB命令行中輸入下列命令:

% 在基礎(chǔ)工作區(qū)生成一個變量a_debug  
% a_debug的值與a的值相等  
assignin('base','a_debug',a)

這樣拌禾,在退出當(dāng)前調(diào)試后,能夠在基礎(chǔ)工作區(qū)看到一個a_debug變量展哭,它的值等于myfun函數(shù)中a的值湃窍。

10.退出MATLAB時自動保存當(dāng)前工作空間的變量

??如果當(dāng)前路徑中存在finish.m文件,matlab在退出前匪傍,會自動運行finish.m文件您市。通過編寫finish文件,即可實現(xiàn)對當(dāng)前工作空間變量的保存役衡。

save 'C:\Users\matlab.mat'  

新建腳本文件茵休,將上述命令復(fù)制過去,保存為finish.m文件手蝎。這樣當(dāng)你退出MATLAB時榕莺,就會自動將當(dāng)前工作區(qū)內(nèi)的變量全部保存到C:\Users\matlab.mat文件中。

注意:

  1. 如果想要當(dāng)前文件夾位于任何文件夾時均能觸發(fā)finish.m腳本的運行棵介,將其保存在MATLABPATH文件夾中钉鸯,具體請使用path命令查看。
  2. 退出matlab時邮辽,右上角的"×"唠雕,命令行輸入quit, exit均能自動觸發(fā)finish.m腳本的運行。
  3. 命令行輸入quit force時吨述,強制退出matlab岩睁,不會執(zhí)行finish.m腳本。

11. 啟動MATLAB時自動讀取上次保存的工作空間變量

??在MATLAB默認的工作文件夾揣云,編寫startup.m腳本捕儒,MATLAB在啟動時會自動運行該腳本。

load 'C:\Users\matlab.mat'  

startup.m文件必須位于MATLAB啟動后的默認文件夾內(nèi)
注意:

  • MATLAB的默認文件夾可以更改

12. 使用pcode對MATLAB代碼進行模糊處理

??有時邓夕,我們希望自己的代碼別人能夠使用肋层,但不能看到源代碼,這是可以通過pcode命令簡單實現(xiàn)這一操作翎迁。
??MATLAB在運行.m程序文件時栋猖,事實上是先將.m文件(文本文件)轉(zhuǎn)換成.p文件(二進制文件)。p文件一般是隱藏文件汪榔,在文件夾中是無法看到的蒲拉。我們可以通過pcode命令將m文件轉(zhuǎn)換成p文件肃拜。將p文件轉(zhuǎn)給第三方使用,但對方無法輕易看到源代碼雌团。

% 下列命令會在當(dāng)前文件夾內(nèi)生成myfun.p  
% myfun.p與myfun.m具有相同的功能 
pcode myfun

注意:

  1. p文件的優(yōu)先級高于m文件燃领,如果函數(shù)名相同,matlab會優(yōu)先使用p文件锦援。
  2. p文件不夠安全猛蔽,不能將其視為加密,只是一個簡單的模糊處理灵寺。
  3. p文件是可以被逆向的曼库,至少MathWorks就可以。
  4. 網(wǎng)上流傳過p文件逆向的小工具略板,這些工具要么被刪毁枯,要么已不適用現(xiàn)在的版本。
  5. 上古版本的MATLAB可以對p文件進行斷點調(diào)試叮称,某種程度上可以推測出源碼种玛。
  6. MATLAB軟件本身也使用了很多p文件,說明MathWorks認為p文件沒有那么容易被破解瓤檐。
  7. 如果代碼涉及知識產(chǎn)權(quán)或商業(yè)機密赂韵,p文件是不安全的,妥善的方法是將代碼部署在遠程服務(wù)器上挠蛉。

結(jié)束語

你都看到這里了祭示,還不點贊收藏?

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市轧抗,隨后出現(xiàn)的幾起案子恩敌,更是在濱河造成了極大的恐慌,老刑警劉巖横媚,帶你破解...
    沈念sama閱讀 212,383評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件纠炮,死亡現(xiàn)場離奇詭異,居然都是意外死亡灯蝴,警方通過查閱死者的電腦和手機恢口,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,522評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來穷躁,“玉大人耕肩,你說我怎么就攤上這事。” “怎么了猿诸?”我有些...
    開封第一講書人閱讀 157,852評論 0 348
  • 文/不壞的土叔 我叫張陵婚被,是天一觀的道長。 經(jīng)常有香客問我梳虽,道長址芯,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,621評論 1 284
  • 正文 為了忘掉前任窜觉,我火速辦了婚禮谷炸,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘竖螃。我一直安慰自己淑廊,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 65,741評論 6 386
  • 文/花漫 我一把揭開白布特咆。 她就那樣靜靜地躺著季惩,像睡著了一般。 火紅的嫁衣襯著肌膚如雪腻格。 梳的紋絲不亂的頭發(fā)上画拾,一...
    開封第一講書人閱讀 49,929評論 1 290
  • 那天,我揣著相機與錄音菜职,去河邊找鬼青抛。 笑死饶深,一個胖子當(dāng)著我的面吹牛印叁,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播勿负,決...
    沈念sama閱讀 39,076評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼嫡意,長吁一口氣:“原來是場噩夢啊……” “哼举瑰!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起蔬螟,我...
    開封第一講書人閱讀 37,803評論 0 268
  • 序言:老撾萬榮一對情侶失蹤此迅,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后旧巾,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體耸序,經(jīng)...
    沈念sama閱讀 44,265評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,582評論 2 327
  • 正文 我和宋清朗相戀三年鲁猩,在試婚紗的時候發(fā)現(xiàn)自己被綠了坎怪。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,716評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡廓握,死狀恐怖芋忿,靈堂內(nèi)的尸體忽然破棺而出炸客,到底是詐尸還是另有隱情,我是刑警寧澤戈钢,帶...
    沈念sama閱讀 34,395評論 4 333
  • 正文 年R本政府宣布痹仙,位于F島的核電站,受9級特大地震影響殉了,放射性物質(zhì)發(fā)生泄漏开仰。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 40,039評論 3 316
  • 文/蒙蒙 一薪铜、第九天 我趴在偏房一處隱蔽的房頂上張望众弓。 院中可真熱鬧,春花似錦隔箍、人聲如沸谓娃。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,798評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽滨达。三九已至,卻和暖如春俯艰,著一層夾襖步出監(jiān)牢的瞬間捡遍,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,027評論 1 266
  • 我被黑心中介騙來泰國打工竹握, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留画株,地道東北人。 一個月前我還...
    沈念sama閱讀 46,488評論 2 361
  • 正文 我出身青樓啦辐,卻偏偏與公主長得像谓传,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子芹关,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,612評論 2 350