第3 章 数值计算 3.1 基本运算 3.1.1 基本运算的条件 加减运算是对矩阵、向量、数都可进行的基本运算;矩阵的乘法需要左边矩阵的列数 与右边矩阵的行数必须相等。违反这一条件,MATLAB会显示红色的出错信息: Errorusing* Incorrectdimensionsformatrixmultiplication。 单击出错信息中的“*”,就可以看到详细说明。 行向量乘以列向量(两者长度相同)等于一个数,等价于两个对应的行(列)向量的内 积,这样做不用调用求内积的内置函数。而列向量乘以行向量等于一个矩阵。 两个数可以有“除”与“除以”的运算;矩阵的这两种运算是不可行的。当一个矩阵可 逆的时候,乘以它的逆阵,就相当于“除以”这个矩阵。 因为矩阵是MATLAB 的基本数据单位,MATLAB把一个矩阵与一个数的加减定 义为这个矩阵的每个元素加上或减去这个数,得到一个同样大小的矩阵。如果正希望这 样的结果,那么只要在这个矩阵与这个数之间添上“+”号或“-”号即可,而不必像其他一 些语言一样,要用循环语句编一段程序来实现。 MATLAB 还对两个同样大小的矩阵定义了“点乘”与“点除”的运算:两者对应每个元素 相乘或相除。这对科学计算十分方便,省去了另编程序的麻烦。对一个方阵,MATLAB 还定 义了“点乘方”的运算:结果是矩阵的每个元素的乘方所得到的矩阵。这与MATLAB 所有的 内置函数一样,代入一个矩阵实参,它就对此矩阵的每个元素进行同一种运算。 3.1.2 算术运算(符) MATLAB中的算术运算符如表3.1所示。 表3.1 算术运算符 运 算 符输入指令输出结果 “+”或“-”(加上或减去) > > a= 1+ 2, b= 4 -5 a= 3, b= -1 “*”(乘以) > > c= 8*2, d=(4+ 2i)*(3-5i) % i 是虚数单位-1 c= 16 d= 22-14i “/”(forwardslash:divided by,除以或被…除) > > u= [8,6, 4; 3,2,1]/2 u= 4.000 3.000 3.000 1.500 1.000 0.500 续表 第3 章 数值计算 25 运 算 符输入指令输出结果 “\”(backslash: divided into,除) > > v= 2\ [8,6, 4; 3,2,1] % 而[8,6; 3,2]\ 2 出错! 因为分母不能 是矩阵 v= 4.000 3.000 3.000 1.500 1.000 0.500 “^”(tothepowerof,乘 方),只适用于方阵,包括 一个数字 > > x= 2^3 y= [2, 1-3i; 4-2i, -1-6i]^(1/2) x= 8 y= 1+ i 1-i 2-0i 1-2i (1)矩阵(向量)的加减是对应元素相加减,只要尺寸相同即可。 (2)两个矩阵的相乘,并不定义为对应元素相乘,而是左边矩阵的各行向量与右边矩 阵的各列向量的内积。所以,两个矩阵能相乘的条件是左边矩阵的列数(即行向量的维 数)与右边矩阵的行数(即列向量的维数)必须相等。使用运算符“*”时,必须小心。 (3)向后(反)斜线运算符“\”用在两个数字之间,“a\b”是“a 除b”,等价于“a 的逆 (或倒数)乘以b”,即a\b=a^ (-1)*b。这与线性方程组Ax=b 的解x=A-1b(A-1左 乘以b)在形式上是一样的,因此可以用来解线性方程组:MATLAB的指令为“x=A\ b”。同样,可以用内置函数mldivide,指令为“x= mldivide(A,b)”。 注意,今后为了输出结果少占空间,有时用输入向量、矩阵的格式来输出向量或矩阵。 例如,X2= [-1;3]的分量之间用分号,表示列向量;若用逗号,则为行向量。 例如: 输入指令输出结果 > >A= [2,-1;3,-2]; b= [-5;-9]; X1=A\ b, X2= inv(A)*b, X3= mldivide(A,b) % inv(A) 是A 的逆矩阵;X1 与X3 显示小数 X1 = [ -1.0000; 3.0000] X2 = [ -1; 3] X3 = [-1.0000; 3.0000] 注意,作为数字相除,“a\b”是“a 的逆乘以b”与“b/a”是“b 乘以a 的逆”是一样的,因 为数字乘法可换,但矩阵乘法(一般)不可换。而且,矩阵不能作分母。所以如果输入“x= b/A”,就会出错。 (4)类似地,向前斜线运算符“/”,也可以用在两个矩阵(向量)之间。“B/A”等价于 “B*inv(A)”,都是B 左乘以A 的逆,A 必须是可逆方阵,B 的列数必须等于A 的阶数。 同样,可以用内置函数mrdivide,指令为“x=mrdivide(B,A)”。 例如: 输入指令输出结果 > > A= [2,-1;3,-2]; B= [-5,-9]; % 同上 x1=B/A, x2=B*inv(A), x3= mrdivide(B,A), x4= mrdivide(A,B) x5=A*pinv(B) x1 = -37.0000 23.0000 x2 = -37.0000 23.0000 x3 = -37.0000 23.0000 x4 = [-0.0094; 0.0283] % 列向量 x5 = x4 26 MATLAB 与机器学习应用 注意,计算x4的B 是个行向量,不存在逆阵,这里实际上用了B 的“广义逆”(详见第 8章)。这个指令等价于计算x5的指令,其中,pinv是用来求广义逆的内置函数。 (5)乘方运算符“C^n”,矩阵C 只能是方阵。 . 当n 是正整数时,表示n 个C 连乘。 . 当n 是负整数时,矩阵C 只能是可逆方阵,表示n 个C 的逆连乘。 . “C ^(-1)”等价于“inv(C)”,即C 的逆阵。 . 当n=0时,无论矩阵C 是否是可逆方阵,结果都是单位阵I。 例如: 输入指令输出结果 > > C= [2,5;1,3], Y1= inv(C), Y2=C^(-1) Y1 = [ 3 -5; -1 2] Y2 = [ 3 -5; -1 2] B1=C^(-2), B2=Y1^2 B1 = [ 14.0000, -25.0000; -5.0000, 9.0000] B2 = [ 14, -25 ; -5 9] > > D= [2,1;4,2]; detD= det(D), E= D^0 % 内置函数det 是求方阵的行列式,见3.2 节 detD = 0, E= eye(2) 3.1.3 点乘、点乘方与点除运算 1.点运算的定义与运算符 MATLAB还设置了计算两个矩阵,包括两个向量的对应元素相乘或相除,或者一个 矩阵(向量)的每个元素的乘方的运算符:在“*”“/”“\”“^”的前面加上点“.”(dot),成为 “.*”“./”“.\”“.^”。参加运算的两个矩阵(向量)必须有同样的尺寸。 例如: 输入指令输出结果 > > x= [-1,5,3-4i]; y= [-2,-4,1+ 2i]; u= x.*y, v= x./y, w= x.^2, t= x.\ y % 以下删去了4 位或最后2、3 位全0 的小数及0 i u = 2. -20. 11. + 2. i; v = 0.5 -1.25 -1. - 2. i w = 1. 25. -7. -24. i; t = 2. -0.8 -0.2 + 0.4i 2.运算的先后次序 MATLAB的运算次序与数学规定的一样,即 . 有括号的先做括号内的运算,有多层括号(全用小括号)的,先做最里层的。 . 然后是先做(点)乘方,再做(点)乘除,最后做加减。点乘除与乘除出现在同一项 时,按先后次序运算,不能用结合律,见下面B2和B2b的区别。 例如: 第3 章 数值计算 27 输入指令输出结果 > > C= [2,5;1,3]; D= [2,1;4,2]; B=C*D^0./D + ((C-D).*C).^2, B = 1.0000 405.0000 9.2500 10.5000 % 以下运算用于检测运算符的优先级别。 B1=D^0, B2=C*B1./D, B2b=C*(B1./D), % 注意B2 与B2b 的区别 B1 = [ 1, 0; 0 1] B2 = [ 1.0000, 5.0000; 0.2500, 1.5000] B2b = [ 1.0000, 2.5000; 0.5000, 1.5000] B3=C-D, B4=B3.*C, B5=B4.^2, B6=B2+B5 B3 = [ 0 4; -3 1] B4 = [ 0 20; -3 3] B5 = [ 0 400; 9 9] B6 = B 3.1.4 数值的字符表达和分数表达 一个变量一般用数值表达,但也可以用字符表达或分数表达。例如,可以把圆周率π 转换为最接近的分数:“R=rats(pi)”“formatlong;R”或分数表达“formatrat;R”。 rats的“单数”rat是把小数转换为连分数。rats与rat只是用来显示所转换成的分 数或连分数的,不能用来参加运算。例如,rats(pi)+1会出错。但是,“formatrat;pi+1”能 得到正确结果。 例如: 输入指令输出结果 > > R= rats(pi), % 字符表达(π表达为祖冲之的密率) format long; R, % 字符表达 format rat; R1= pi+ 1 % 分数表达 R = ' 355/113 ' R = ' 355/113 ' R1= 468/113 3.2 矩阵的一元运算 矩阵的一元运算有矩阵的转置、求逆、数乘与矩阵的行列式。 3.2.1 矩阵的转置 矩阵的转置运算用符号“'”实现,即A 的转置矩阵AT。在代码中是“A'”。注意,这个 “'”必须是在MATLAB的指令窗口或“编辑”(Editor)窗口中,而且是英文环境下打印出 来的。它不同于Word在英文环境下输入的“’”。 例如: 输入指令输出结果 > > A= [11,12,13,14; 21,22,23,24; 31,32,33,34], A = 11 12 13 14 21 22 23 24 31 32 33 34 续表 28 MATLAB 与机器学习应用 输入指令输出结果 B=A' B = 11 21 31 12 22 32 13 23 33 14 24 34 这样,一个列向量可用一个行向量(它显示出来所占的空间小得多)的转置来实现。 本书以斜黑体小写字母表示列向量。线性代数书中不少把线性方程组表示为Ax=b, 其中的x 是未知量形成的列向量,而b 则是右端项常数形成的列向量。所以本书的表示 法与此一致。 列向量的分量表达式,为少占空间,也写成行向量加转置。例如,x=(1,2,3,4,5)T。 赋值语句可以写为“x= [1,2,3,4,5]'”(最后是一撇“'”)或“x=[1;2;3;4;5]”(分 量之间用分号隔开)。 若C 是复矩阵,则运算符“'”是共轭转置,即转置以后,再对每个元素取共轭复数。 例如: 输入指令输出结果 > > C= [1+ i, -2, i; 3, -i, -1-2*i], D=C' C = 1+ i -2+ 0i 0+ i 3+ 0i 0-i -1-2i D = 1.0000 -1.0000i 3.0000 + 0.0000i -2.0000 + 0.0000i 0.0000 + 1.0000i 0.0000 -1.0000i -1.0000 + 2.0000i 3.2.2 数乘矩阵 数r 乘矩阵A,直接用“r*A”或用点乘“r.*A”来实现。 3.2.3 方阵的行列式 方阵A 的行列式,用内置函数det:“det(A)”。 例如: 输入指令输出结果 > > M= [2, -1, 3; -1, 0, 4; -2, 1, 5]; r= det(M) r = -8 3.2.4 方阵的逆 当方阵M 的行列式非零时,它的逆矩阵存在,用指令“N=inv(M)”求逆矩阵N ,逆矩 阵元素用小数表示。指令“rats(N)”或“formatrat;N”可把N 的每个元素都转换为 分数。 第3 章 数值计算 29 例如: 输入指令输出结果 > > M= [2, -1, 3; -1, 0, 4; -2, 1, 5]; N= inv(M) N = 0.5000 -1.0000 0.5000 0.3750 -2.0000 1.3750 0.1250 0 0.1250 N1= rats(N) format rat; N N1 = 3×42 char 数组 ' 1/2 -1 1/2 ' ' 3/8 -2 11/8 ' ' 1/8 0 1/8 ' N = 1/2 -1 1/2 3/8 -2 11/8 1/8 0 1/8 3.2.5 与矩阵相关的其他数值 1.矩阵的尺寸 内置函数size(A)或[r,c]=size(A)返回一个行向量,其元素是矩阵A 的行数r 与 列数c。length(A)返回A 的行数与列数中的最大值,等价于max(size(A))。对于向量, 长度仅仅是元素数量。空矩阵的行数、列数与长度为零。 例如: 输入指令输出结果 > > M= [2, -1, 3; -2, 1, 5]; % “;”结尾的指令不显示 L1= size(M), L2 = length(M), L3 = max(size(M)), [r,c]= size(M) L1 = 2 3; L2 = L3 = 3 r = 2; c = 3 2.矩阵的秩 用内置函数rank()来获得。 例如: 输入指令输出结果 > > M= [11,12,13,14; 21,22,23,24; 31,32,33,34]; L= rank (M), L = 2 这是因为A 的任何两行(列)不成比例,但它们的差是成比例的向量:相邻两列的差 都等于[1;1;1],而相邻两行的差都等于[10,10,10,10]。 3.矩阵各(行或列)元素的和 用内置函数sum()来获得。 (1)矩阵A 各列元素的和:sum(A)或sum(A,1),输出一个行向量。 (2)矩阵A 各行元素的和:sum(A,2),输出一个列向量。 30 MATLAB 与机器学习应用 (3)矩阵A 各元素的和:sum(sum(A)),输出一个数。 例如: 输入指令输出结果 > > A= [1, 2, 3; -2, 1, 2]; R1sum= sum(A), R2sum=(sum(A,1)), Csum= sum(A,2), Asum= sum(sum(A)) R1sum = -1 3 5 R2sum = -1 3 5 Csum = [ 6; 1] % 列向量 Asum = 7 4.矩阵的最大值 (1)Y=max(A):矩阵A 各列元素的最大值,输出行向量Y。 (2)[Y,I]=max(A):行向量Y 同(1),行向量I 是取得同列中最大值的(第1个)元 素的行下标。 例如: 输入指令输出结果 > > A= [1, 2, 3; -2, 5, 2; 3, 5, 3]; Y=max(A), [Y,I]=max(A) Y = 3 5 3 Y = 3 5 3 I = 3 2 1 (3)C=max(A,B):矩阵C 的每个元素是对应的A 与B 元素中的最大值。特别 地,max(A,a)= max(A,a*ones(size(A))):a 是常数,a*ones(size(A))就是一个 与A 同样尺寸,每个元素全是a 的矩阵。 (4)max(A,[],DEM):“[]”是英文状态下的方括号,其中没有内容,表示“空”。 DIM=1时,求各列元素的最大者,与max(A)相同;DIM=2时,求各行元素的最大者。 例如: 输入指令输出结果 > > A= [1, 2, 3; -2, 5, 2; 3, 5, 3]; B= [-2, 0, 3; 1, 2, 3; 4, 5, 6]; C=max(A,B), M1=max(A, 2), M2=max(A, 2* ones(size(A))) % M2= M1,M2 输出省略 C = 1 2 3 1 5 3 4 5 6 M1 = 2 2 3 2 5 2 3 5 3 [Yc,Ic]=max(A,[],1), % 与max(A) 等价 % Yc,Ic 两个行向量 Yc = 3 5 3 Ic = 3 2 1 [Yr,Ir]=max(A,[],2) % Yr,Ir 两个列向量 Yr = [ 3; 5; 5] Ir = [ 3; 2; 2 5.矩阵的最小值 所有这方面的指令与求矩阵的最大值的指令类似。只要把内置函数max()改为 第3 章 数值计算 31 min(),即把求最大值改为求最小值。 例如: 输入指令输出结果 > > A= [1, 2, 3; -2, 5, 2; 3, 5, 3]; B= [-2, 0, 3; 1, 2, 3; 4, 5, 6]; X1=min(A,B), X2=min(A, 2), [Z,J]=min(A, [],2) % Z,J 两个列向量 X1 = -2 0 3 -2 2 2 3 5 3 X2 = 1 2 2 -2 2 2 2 2 2 Z = [ 1; -2; 3], J= [ 1; 1; 1] 3.3 向量的内积与外积 3.3.1 向量的内积 向量的内积(innerproduct)又称点积(dotproduct),是数量积。两个尺寸一样的行 向量a 与b 的内积用dot(a,b)或a*b' 或b*a' 或sum(a.*b)或sum(b.*a)来得到。 内置函数sum()的参数若为向量,是求各分量的和。 例如: 输入指令输出结果 > > a= [1,0,-2]; b= [-3,2,4]; d1= dot(a,b), d2= a*b', d3= b*a', d4= sum(a.*b), d5= sum(b.*a) , D1= a'*b, D2= b'*a % D2=D1 的转置 d1 = d2 = -11 d3 = d4 = d5 = -11 D1 = -3 2 4 0 0 0 6 -4 -8 (D2 = D1 ') 其中,D1与D2都是列向量(左)乘以行向量。线性代数基础好的可以自行证明:一个方 阵的秩为1的充要条件是它等于一个(非0)列向量乘以一个(非0)行向量。两个尺寸一样的列 向量a 与b 的内积也可用dot(a,b)或用类似于上面的其他方法得到,见习题X3.10。 3.3.2 向量的外积 向量的外积(crossproduct),也称叉积或向量积。两个3维行(列)向量a 与b 的外 积用cross(a,b)来得到,向量的外积仍是一个向量。 例如: 输入指令输出结果 > > a= [1,0,-2]; b= [-3,2,4]; c= cross(a,b) c = 4 2 2 32 MATLAB 与机器学习应用 3.4 内置函数与函数值计算 内置函数(Built-inFunctions)是MATLAB已经编制好的函数(子程序),前面已经 调用了一些内置函数,例如size、length、det、dot、cross、exp等。MATLAB内置了绝大多 数常用的数学函数与平面(二维)、立体(三维)的作图函数。要知道有关的函数名及其功 能,以及如何使用该函数就需要用到两个非常有用的指令。 绝大多数内置函数的参数都是矩阵(包括向量与数)。在计算函数值的时候,对矩阵 的每个元素进行计算。 3.4.1 两个重要搜索指令 1.lookfor+(一个)关键词 当不知道函数名时,要用“lookfor 关键词”去搜索。例如,想寻找计算与对数 (logarithm)有关的函数,就可以用指令“lookforlogarithm”去搜索。 输入指令> > lookfor logarithm 输出结果(列出了部分函数) log Natural logarithm. log10 Common (base 10) logarithm. log2 Base 2 logarithm and dissect floating point number. log Symbolic matrix element-wise natural logarithm. log10 Symbolic matrix element- wise common logarithm. log2 Symbolic matrix element-wise base-2 logarithm. 若要找指数(exponential)函数,使用指令“lookforexponential”。当然也可以用关键 词的一部分,如“exp”去搜索,但会得到很多额外与指数函数无关,但与“exp”有关的结 果,例如与“expression”或“exponent”有关的结果。 2.help+函数名 知道函数名时,要用“help函数名”去搜索。 从上面搜索结果的说明中,我们知道如果要计算的是自然对数函数值,就用指令 “helplog”,得到下面的结果。 输入指令输出结果 > > help log log - 自然对数 此MATLAB 函数返回数组X 中每个元素的自然对数ln(x)。 Y = log(X) 另请参阅exp, log10, log1p, log2, loglog, logm, reallog, semilogx, semilogy log 的文档 名为log 的其他函数 第3 章 数值计算 33 要得到更详细的说明与使用例子,单击带有下画线的字符“log的文档”。从上面可 以看到,指令“helplog”还显示了与自然对数有联系的其他函数。例如,常用对数log10 (log10),以2为底的对数log2(log2),指数函数exp以及名为log的其他函数等。单击带 有下画线的字符可以找到与自然对数有联系的其他函数。 关于如何使用“help”,可用“helphelp”来查询。 3.常用的内置初等函数 用指令“helpelfun”(elementaryfunction)可找到MATLAB中内置的初等函数表。 单击表上的函数名,相当于用指令“help函数名”。 (1)绝对值函数:|x|→abs(x)。x 为复数时,等于x 的模长。 例如: 输入指令输出结果 > > x= [-2, 0, 3, 3+ 4i]; abs(x) ans = 2 0 3 5 对于两个矩阵是否相等,当矩阵规模较小时,可以显示出来用眼睛检查。但矩阵规模 较大时,由于数值计算中不同方法的数值误差,在理论上应该相等的两个矩阵,实际上会 有差别,这时可以联合使用abs与sum 来检查这一差别是否在容许范围之内。 例如: 输入指令输出结果 > > a= [1,0,-2]; b= [-3,2,4]; D1= a'*b; D2= b'*a; DIF= sum(sum(abs(D1-D2'))) DIF = 0 (2)幂函数:xa → x^a;x →sqrt(x)或x^(1/2)。这里,x 可以是复数。 例如: 输入指令输出结果(以下删去了小数点后面的所有0及0i) > > x= [-4, 4, 3+ 4i] ; x2= x.^2 , xs= x.*x, xh= x.^(1/2), xq= sqrt(x) x2 = xs = 16. 16. -7. + 24i xh = xq = 0+ 2i 2. 2+ 1i (3)三角函数:函数名后+“d”,即参数x 的单位用度的标以*,否则用弧度。 正弦sin(x),*sind(x);余弦cos(x),*cosd(x)。 正切tan(x),*tand(x);余切cot(x),*cotd(x)。 正割sec(x),*secd(x);余割csc(x),*cscd(x)。 例如: 输入指令输出结果 > > S1= sin([pi/2,-pi/4,pi]), S2= sind([90,-45,180]) , S1= 1.0000 -0.7071 0.0000 S2= 1.0000 -0.7071 0 续表 34 MATLAB 与机器学习应用 输入指令输出结果 T= tan(pi/4), C= csc(pi) T = 1.0000 C = 8.1656e+ 15 (4)反三角函数:其函数名是在对应的三角函数名前加字母a,标以*的表示输出量 的单位为度,否则为弧度。 反正弦asin(x),*asind(x);反余弦acos(x),*acosd(x)。 反正切atan(x),*atand(x);反余切acot(x),*acotd(x)。 反正割asec(x),*asecd(x);反余割acsc(x),*acscd(x)。 例如: 输入指令输出结果 > > As= asin([1, -sqrt(2)/2, 0]), Asd= asind([1, -sqrt(2)/2, 0]) As= 1.5708 -0.7854 0 Asd= 90.0000 -45.0000 0 (5)指数函数:ex →exp(x); ax =exlna→exp(x*log(a))。 例如: 输入指令输出结果 > > Ex= exp([log(2), 1, -1]), a= 2; x= 3; ax= exp(x*log(a)), ax1= a^x Ex = 2.0000 2.7183 0.3679 ax = 8.0000 ax1= 8 (6)对数函数:以e为底→log(x);以10为底→log10(x);以2为底→log2(x)。 这里,x 可以是复数和负数。 例如: 输入指令输出结果 > > L1= log(-1), AL1= abs(log(-1)), L2= log2(4), L10= log10(0.01), LP= log(1+ i) L1 = 0.0000 + 3.1416i AL1 = 3.1416 L2 = 2, L10 = -2 LP = 0.3466 + 0.7854i 3.4.2 取整的内置函数 不少计算机语言中的变量分为整型与实型。这样整除运算就可以运用通常的除法运 算符,只要a 与b 在程序一开始的说明语句中都说明为整型变量,得到的结果就是整数。 例如,8整除以3,得到2。MATLAB的变量不分整型与实型,要整除运算不能用通常的 除法运算符,但它有内置函数,可以实现同样的目的。它们的实参是矩阵(包括向量和 数),对每个元素取整;矩阵的元素可以是复数,此时它们把此元素的实部与虚部分别 第3 章 数值计算 35 取整。 (1)round(x):四舍五入取整。 (2)floor(x):向下取整或向负无穷方向取整。等于数轴上左侧最接近x 的整数。 (3)ceil(x):向上取整或向正无穷方向取整。等于数轴上右侧最接近x 的整数。 (4)fix(x):截尾取整或向零取整。等于在数轴上朝原点方向最接近x 的整数。 如表3.2所示是对向量x 的值与以上4个取整函数的结果比较。 表3.2 取整函数结果比较 x [-1.9, -0.2, 3.4, 5.6, 7.0, 2.4+3.5i] round(x) -2 0 3 6 7 2+4i floor(x) -2 -1 3 5 7 2+3i ceil(x) -1 0 4 6 7 3+4i fix(x) -1 0 3 5 7 2+3i 内置函数的参数可以是数值,也可以是表达式,但涉及的变量必须先赋值。 例3.1 已知年y 与从元旦到某日的天数c,求那一天是星期几。例如,2017年的春 节(1月28日)是星期几? 其中,c=28。 解:令x=y -1,先计算s =x+【x/4】-【x/100】+【x/400】+c,其中,【z】为z 取 整数部分;然后作带余除法s÷7,余几即为星期几(余数=0:星期日)。 作两个整数s(被除数)与t 的带余除法的正确方法是:先求出它的整数部分n(上述 被除数x,s>0,所以用向下取整floor或截尾取整fix均可)。再求出余数部分r=s-nt。 输入指令串: 输入指令输出结果 > > c= 28; x= 2017-1; s= x+ fix(x/4)-fix(x/100)+ fix(x/400)+ c n= fix(s/7), r= s-n*7 s= 2533 n= 361, r= 6, 星期六 如果先用通常的除法求出s/7的带小数的值z,再取它的整数部分n 与小数部分(分 数6/7的小数值)b,再作“b*7”,用fix或floor转换为整数,必须十分小心。例如,把上 面第3行的两个指令改为: 输入指令输出结果 > > z= s/7, n= fix(z), b= z-n, d= b*7, r1= fix(d) z= 361.8571,n= 361,b= 0.8571 d= 6.0000, r1= 5 实际上,b 的准确值是6/7,它是循环小数,循环节是857143。若在“formatlong”下 运行,显示d=5.99999999999983。从而r1的结果会是5。所以在用fix或floor取整前 应先加一个0.1,而在用ceil取整前应先减去一个0.1,即 36 MATLAB 与机器学习应用 r1=fix(d+0.1), r2=floor(d+0.1), r3=ceil(d-0.1) 都会得到正确的结果6。 此外,当s 与t 都是正数,而且仅要求余数时,可以用内置函数rem(s,t)或mod(s,t)。 详情可用help来查询。 如果要的是s 除以7 所得余数,程序的最后一行可改为“r=rem(s,7)”或“r= mod(s,7)”都会得到正确答案6。 3.5 随机数的产生 有各种类型的随机数,这里只介绍两种。其一为一致分布(uniformlydistributed)的 随机数,另一为正态分布(normallydistributed)的随机数。其他类型的随机数可用指令 lookforrandom 来获得详情。 3.5.1 一致分布的随机数 一致分布的随机数由内置函数rand()产生。 1.内置函数rand(m,n)和rand([m,n]) 内置函数rand(m,n)和rand([m,n])都得到m ×n 矩阵,其元素是单位区间[0,1] 内一致分布的随机数。rand(n)得到n×n 方阵,其元素是单位区间[0,1]内一致分布的 随机数。rand(1,1)与rand()无参数的结果都得到一个在单位区间[0,1]内一致分布的 随机数。 例如: 输入指令输出结果 > > x= rand(1,10) % 在[0,1] 内得到的10 个随机数 x= 0.0975 0.2785 0.5469 0.9575 0.9649 0.1576 0.9706 0.9572 0.4854 0.8003 与“hist(x)”配合会得到直方图。例如: >>x=rand(1,1000); %不要忘了加分号! hist(x) %得到直方图如图3.1 所示 如果把分量数增加到10万个,则直方图的所有矩形的顶端都差不多高。 2.一致分布的随机数 要产生区间[a,b]内(10个)一致分布的随机数(行向量),则应该用下列语句,其中 “*”表示“乘以”的运算符: r = a + (b-a)*rand(1,10); 第3 章 数值计算 37 图3.1 一致分布的随机数的直方图 内置函数rand的其他调用方法用指令“helprand”查看详情。 3.5.2 正态分布的随机数 1.内置函数randn(m,n)和randn([m,n]) 内置函数randn(m,n)或randn([m,n])都得到m ×n 矩阵,其元素是标准正态分布 的随机数。期望值为0(μ=0),标准差为1(σ=1)。正态分布函数的图形是一条钟形曲 线,直方图的外包曲线接近钟形曲线。randn(n)得到n×n 方阵,其元素是标准正态分布 的随机数。 例如: >>xn=randn(1,1000); %不要忘了加分号! hist(xn) %得到正态分布直方图如图3.2 所示 图3.2 标准正态分布的随机数的直方图 38 MATLAB 与机器学习应用 2.正态分布的随机数 要产生期望值为a(μ=a),标准差为b(σ=b)的(100个)正态分布的随机数(行向 量)则应该用下列语句: rn = a + b*randn(1,100); 3.6 创建和运行M 文件 前面讲的都是直接在指令窗口中调用内置函数,更必须学会编制程序并保存为 MATLAB的文件(M 文件)和运行它。 3.6.1 创建函数子程序文件 MATLAB有一些内置的function(子)程序,例如dot、sum、cross等内置函数,可以 被其他的function程序或主程序调用。虽然function程序并不都包含函数,但一般还是 称它们为函数(子程序),以区别于主程序。存放的M 文件称为“函数文件”。创建一个函 数文件的好处就在于我们可以用一个其他文件来调用它。在多个程序中,如果都有一组 仅变量名不同而功能一样的语句,或者在一个程序中反复出现一组(仅变量名不同而功能 一样的)语句,就可以把这组语句编成函数子程序,那些“变量”就成为名字相同的形式(输 入、输出)参数。然后被多个程序调用或被一个程序反复调用。 用“>> helpfunction”以及单击所显示的信息的最底下的“doc_function”可发现编 制函数程序的方法如下。 (1)函数头行:function[out1,out2,…]=funname(in1,in2,…)。 注意: . 函数子程序(头行)不能在指令窗口的提示符下输入。 .out1,out2,…是输出(output)形式变量(名)或形式参数,简称输出形参。只有一 个变量时,可省去方括号。例如,functiony=funname(in1,in2,…)。 .funname是我们取的函数名字,也是保存时计算机自动取的M 文件名。 .in1,in2,… 是输入(input)形参。圆括号不能省去;即使没有输入变量,也要输入 空的圆括号。例如,functiony= Qudr(),其中,Qudr是函数名。 (2)函数表达式。 把函数表达式,即因变量(输出变量)与自变量(输入变量)的关系式,写在执行语句中。 例3.2 下面是一个自编的计算二次多项式值的MATLAB函数。 %求多项式ax2+bx+c 的函数值,x 是自变量,y 是因变量。 %调用格式: y=Qudr(a,b,c,x); function y=Qudr(a,b,c,x); y=a*x*x+b*x+c; return; 39 第 3 章 数值计算 前面已经提到,“%”后面的是注释(comment)语句(输入“%”后,计算机自动会把% 与此后的说明变成绿色), 不执行任何计算。一个语句前加上“%”,它就被“屏蔽”了,不再 被执行。初学者可以把前两行的说明复制到新建文件中。 1. 新建一个文件 单击“主页”左上角“新建(脚本)”按钮,将在编辑器中新建一个名为“Untitled”的文件, 在“编辑器”3显示了一个在已有TRem. 最右处列出。图3.m文件下新建一个文件的状态, 此时,(“) 编辑器”里有两个文件,左边是原有打开的TRem.m文件,新建文件Untitled排在最 右面。如果原来没有已打开文件,那么Untitled将在“编辑器”最左处列出。如果连续单击 “新建(脚本)按(”) 钮,将在“编辑器”右边依次列出“Untitled2”“Untitled3”等。 图3.新建一个文件 3 2. 保存一个文件 “Untitled”“Untitled2”“Untitled3等(”) 是系统给出的默认文件名,可以在保存时将文 件名改成设计者指定的名字存放。如图3.4所示是将“Untitled”保存为“Qudr.m”文件。 如果保存成功,编(“) 辑器-Untitled”下一行原来的“Untitled”会自动改为“Qudr.m”。 如果把例3.rm文件中( unction的前面或后面 2的两行说明也输入到Qud输入到f 都可以), 在命令窗口中输入“helpQudr”后,两行(.) 说明就会显示。 3. 打开已存在的 M 文件 要打开(比如想修改)一个已存在的M文件时,可单击左上角的“打开”图标(图3. 系统会在“最近使用的文件”中列出最近的文件,选择其中需要打开的文件即可。 5), 40 MATLAB 与机器学习应用 图3.保存一个文件 4 图3.打开已有的文件 5 第3 章 数值计算 41 3.6.2 运行M 文件 1.运行函数子程序 有以下两种方法来运行函数子程序。 (1)在命令行(指令)窗口中输入与前面“函数头行”相对应的指令。 [OUT1, OUT2, …] = funname(IN1, IN2, …) 其中,OUT1,OUT2,…是输出实参,可以与输出形参out1,out2,…不同名,但要 一一对应;IN1,IN2,…是输入实参,可以与输入形参in1,in2,…不同名,但也要一一对 应。输入实参,可用赋值语句,也可以把数值直接写在funname后的圆括号中。 例3.3 下面是一个简单的执行Qudr.m 函数子程序的例子。注意大小写(Y 与y) 是不同的变量。 输入指令输出结果 > > a= 1; b= 2; c= 3; d= 1; y=Qudr(a,b,c,d) y= 6 > > Y= Qudr (1,2,3,1) Y= 6 (2)也可以把上述两行指令串各自写成M 文件(称为主程序)并分别取名为Test.m 与Test0.m,然后在指令窗口中输入主程序的名字(省去扩展名“.m”),即可调用(运行) 函数子程序Qudr.m。 例3.4 下面列出了这两个主程序与调用指令以及输出结果。 输入指令主程序文件输出结果 > > Test a= 1; b= 2; c= 3; d= 1; y=Qudr(a,b,c,d) y= 6 > > Test0 Y= Qudr (1,2,3,1) Y= 6 2.运行主程序 除了上面在指令窗口中输入主程序(其中可以没有调用函数子程序的语句)的名字来 运行主程序,还可以在“运行界面”上来运行。 通过“打开”功能,找到想要运行的M 文件(例如“Test.m”),将在“当前文件夹”中出 现该文件(如果显示找不到该文件,则需要设置路径),用右键单击它,在弹出菜单中单击 “运行”,就会在“命令行窗口”(数值运算)或弹出的Figure窗口(图形输出)中输出结果 (图3.6)。 3.6.3 创建调用函数的M 文件与输入数据 函数子程序Qudr.m 被其他函数子程序或主程序调用时,其中的赋值语句要改为输 入语句。这样就不必在改变变量值的时候,去修改调用语句。下面介绍几种方法来输入 42 MATLAB 与机器学习应用 图3.6 运行M 文件及其结果 数据。 (1)应用内置函数input(‘prompt’)与键盘输入数据。 例3.5 建立一个名为“Test1.m”用键盘输入数据的M 文件: %这是一个应用内置函数input(‘prompt’)与键盘输入数据 %并调用函数子程序Qudr.m 的测试程序 a=input('a='); b=input('b='); c=input('c='); x=input('x='); y = Qudr (a,b,c,x) %调用函数子程序Qudr.m 写在单引号中的提示(prompt)字符串‘a=’,‘b=’,‘c=’与‘x=’会逐个显示在 指令窗口中,紧接着后面用键盘输入该变量的值,这个值赋给“=”号前的变量。 以下是指令窗口中输入和输出的内容。在输入指令栏,“a=”“b=”“c=”“d=”是系 统自己输出的,其他都是操作者输入的。最后在“输出结果”栏得到主程序Test1的最后 一行调用语句“y=Qudra(a,b,c,x)”(后面没有分号)后的结果。 输入指令输出结果 > > Test1 a= 2 b= -1 c= 3 x= -2 y = 13 (2)向量输入法:把上面的4个数作为一个向量的元素。 第3 章 数值计算 43 例3.6 以下的Test2.m 文件中,只有一句输入语句,赋给向量p。 %Name: Test2.m, 改为输入向量p=[a,b,c,x] %调用函数子程序Qudr.m 的测试程序 p=input('p=[a,b,c,x]='); y=Qudr(p(1), p(2), p(3), p(4)); 这里向量p 有a,b,c 与x 四个分量。在提示字符串后要输入“[2,-1,3,-2]”。必 须用方括号表示向量,各分量之间用逗号或空格来分隔。此时,a=p(1)=2,b=p(2)= -1,c=p(3)=3,x=p(4)=-2。所以,实参是p 的4个分量,用它们代入4个形参。指 令窗口上显示的全过程为: 输入指令输出结果 > > Test2; p= [a, b, c, x]= [2, -1, 3, -2] > > y % Test2.m 中调用语句后有分号! % “p= [a, b, c, x]= ”是指令窗口显示的 y = 13 (3)用指令“load+ 输入文件名”来输入数据。 例3.7 打开“文本文件”,新建一个名为“Test3Data.txt”(存为txt)的输入文件,其中 与输入数据有关的第2行内容为“2,-1,3,-2”(或用空格分隔),而第1行是以“%”开 头的说明,写上是为了以后能知道这个文件的功能,输入指令不会读入,见图3.7。 图3.7 名为“Test3Data.txt”的数据文件 这4个数值是以输入文件名(去掉扩展名)为向量名(即Test3Data)的4个分量。然 后创建M 文件Test3.m(第2个语句最后无分号时才会自动输出y的值)。 %Name: Test3.m, 用load Test3Data.txt 输入向量Test3Data %调用函数子程序Qudr.m 的测试程序 load Test3Data.txt y=Qudr(Test3Data (1), Test3Data (2), Test3Data (3), Test3Data (4)) 注意,Test3Data.txt与Test3.m 要存放在同一个子目录(文件夹)中。运行时,在命 令窗口中输入“>> Test3”,马上得到答案:y=13。 用这种方法,在需要根据不同数据来计算函数值的时候,只要把有关的数据文件复制 为Test3Data.txt,然后运行Test3.m。