MATLAB: 你不知道的12个基础知识
1.
我们知道,
是一个小数点后无限位的无理数,计算机是无法精确表示的。所以,在MATLAB中, pi只是一个近似值,3.141592653589793,精确到小数点后15位
pi == 3.141592653589793% ans = 1
2. sin(pi)≠0
因为
,导致的一个问题是,sin(pi)并不精确的等于0。事实上,所有的sin(n*pi)都不为0,且互不相等。
sin(pi)% ans = 1.224646799147353e-16sin(2*pi)% ans = -2.449293598294706e-16sin(3*pi)% ans = 3.673940397442059e-16
甚至可以看到,当n足够大时,sin(n*pi)会接近于±1.
sin(4e16*pi)% ans = -0.999478704149319
正确的计算sin(n*pi)的方法是,利用sinpi函数。这是一个R2018b推出的新函数,能够精确计算形如sin(pi*x)的值。
sinpi(1) == 0% ans = 1sinpi(4e16) == 0% ans = 1sinpi(1/4) == sqrt(2)/2% ans = 1
如果是早期版本的MATLAB,就只能将弧度制转换成角度制后,用sind函数计算了。
sind(180) == 0% ans = 1sind(180*4e16) == 0% ans = 1sind(45) == sqrt(2)/2% ans = 1
3. 0.7/0.1≠7 但0.2/0.1=2
0.7/0.1 == 7% ans =0
这是由于浮点数的表示机制决定的,计算机是二进制的,在表示某些小数时,并不是精确表示的。由于二进制的限制,计算机无法精确的表示0.7。
format long0.7/0.1 % ans = 6.999999999999999
事实上,计算机中,所有的数不是连续的,而是离散的,每个浮点数和下一个更大的浮点数之间都存在一个较小的间隔,这个间隔可以用eps函数来计算。
例如,1234567890.0123456789最后一位的9是无效的,因为即使是双精度double也无法精确到最后一位。
1234567890.0123456789 == 1234567890.012345678% ans = 1% 左边的数比右边的数多了最后一位的9,但仍然是相等的。
那么,如果遇到类似的问题时,如何输出正确的判断结果呢?一种可行的方法是全部转换为整数
(0.7*10)/(0.1*10) == 7% ans = 1
或者,求两个数的差值,看差值的绝对值是否足够小。如果精度要求不高的话,可以自己设定一个较小的阈值
abs(0.7/0.1 - 7) <= 1e-6% ans = 1
如果精度要求高的话,可借助于eps函数
abs(0.7/0.1 - 7) <= eps(7)% ans = 1
4.矩阵转置.' 与' 的区别
大多数教程、网上博客、甚至书籍里面都会提到,MATLAB的矩阵转置运算是" ' "符号。事实上,这是一个很大的误区。A'是矩阵A的共轭转置,只不过大多数情况下,A虚部为0,无法体现出共轭。
A = [1, 2; 3, 4];A'% ans = [1, 3; 2, 4]
但是,如果A是复数矩阵,就会出现共轭。
A = [1+2i, 3+4i; 5+6i, 7+8i];A'% ans = [1-2i,5-6i; 3-4i,7-8i];
正确的转置符号是" .' "
A = [1+2i, 3+4i; 5+6i, 7+8i];A.'% ans = [1+2i,5+6i; 3+4i,7+8i];
5. 每次生成相同的随机数
在知乎上面有很多类似的问题,如何保证每次生成的随机数相同。我看到很多回答都是说,将生成的随机数save成本地mat文件,然后在下次要用的时候,用load函数读取mat文件中的值。这种方法也不是不可以,但是效率比较低,文件读写可能会花费大量的时间。
事实上,MATLAB生成的随机数都是伪随机数,也就是说,按照某种特定的算法生成的。这意味着,随机数的生成过程是可以复现的,可以通过控制随机数生成器的"种子",确保每次生成相同的随机数。
rng函数用于控制随机数的生成
% 保存当前随机数生成器的状态("种子")scurr = rng();% 生成随机数A = randn([1,4])% A = [-0.4611 0.1132 1.3442 -0.4842];% 每次想要生成相同的随机数时% 先用rng函数将生成器的状态置为上次保存的scurrrng(scurr);A = randn([1,4])% A = [-0.4611 0.1132 1.3442 -0.4842];
6. 如何生成类似于A1,A2,....,A100的变量
在知乎上也有很多类似的问题,纷纷表示用手一个一个的敲进去太累了。大部分的回答是,用eval、feval之类的函数。但是eval函数的效率很低,而且代码的可读性会很差。
事实是,绝大部分情况下,并不需要生成A1,A2,...,A100这样的变量。真正需要做的是,改变自己的编程思路,给数组A增加一个额外的维度,用这个维度来表示A1到A100。
% 例如A1到A100,% An每个变量的值为[n,n+1,...,n+99]% 用eval函数可以完成上述赋值for ii = 1:100    eval(['A' num2str(ii) '=' num2str(ii) ':' num2str(ii+99)]);end% 事实上,只需要给
A多一个维度就可以了% 这样当你想要使用A1变量时,只需要调用A(1,:)就可以了for ii = 1:100    A(ii,:) = ii:ii+99;end
如果A1,A2,...A100每个变量的长度不一样,不能放到一个矩阵里面怎么办?改用cell数组
% 例如A1到A100,% An每个变量的值为[n,n+1,...,100]% 用eval函数可以生成完成上述赋值for ii = 1:100    eval(['A' num2str(ii) '=' num2str(ii) ':' num2str(100)]);end% 使用cell元胞数组完成类似的赋值% 当你想使用A1变量时,只需要调用A{1}for ii = 1:100    A{ii} = ii:100;end
7. i 和j都是MATLAB内置函数(built-in function)
在上面的例子,我在for循环里面的循环变量用的ii,而不是常用的i,这是为什么呢?因为在MATLAB中,i是一个内置函数,代表的是虚数单位(j也是),用于输入复数。
% 确保当前工作区没有i,j变量clear i ji == j% ans = 1
当然可以将i和j重载成变量,但是重载内置函数不是一个好的编程习惯,同时也会带来运行速度上的降低。而且,一旦程序中涉及输入复数,就可能会出现错误。
% 下面的代码中,想实现的是复数1+2i% 但实际上,A = [3,5,7,9,11]a = 1;b = 2;for i = 1:5    A(i) = a + b*i;end
那么,为了避免这个问题,一种良好的编程习惯就是,将循环变量i,j改成ii,jj。在写虚数单位时,用1i,1j代替i,j.
for ii = 1:5    A(ii) = a + b*1i;end
8. dbstop if error真的很好用
当我作为一个MATLAB beginner第一次知道这个命令时,感觉仿佛迎来了春天,给我带来的震撼不亚于第一次接触bsxfun。
在调试MATLAB程序时,如果有错误,我们经常需要在出错的那一行加上断点,然后重新运行脚本或函数。这样程序会运行到断点前,我们就可以观察出错前各个变量的值,进而到bug。这一过程需要经历运行,出错,加断点,再运行这一过程。
matlab生成随机数如果在MATLAB命令行输入dbstop if error,然后再运行程序,这样程序会自动停在出错的
那一行,这时可以直接观察各个变量的值,省去了自己加断点的过程。而且,不需要每次运行程序前都输入dbstop if error,只需要输入一次就OK。
如果想要在每次warning前暂停程序,也可以在命令行输入dbstop if warning
9. 调试程序时在不同的函数之间传递值

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。