2.1 数据类型
MATLAB中的数据类型主要包括数值类型、逻辑类型、字符串、函数句柄、结构体和单元数组类型。这6种基本的数据类型都是按照数组形式存储和操作的。
MATLAB中还有两种用于高级交叉编程的数据类型,分别是用户自定义的面向对象的用户类类型和Java类类型。
2.1.1 数值类型
基本的数值类型主要有整数、单精度浮点数和双精度浮点数,如表2-1所示。
表2-1 数值类型数据的分类
MATLAB中数值类型的数据包括有符号和无符号整数、单精度浮点数和双精度浮点数。在未加说明与特殊定义时,MATLAB对所有数值按照双精度浮点数类型进行存储和操作。
在需要时,可以指定系统按照整数类型或单精度浮点数类型对指定的数字或数组进行存储、运算等操作。相对于双精度浮点数类型,整数类型与单精度浮点数类型的优点在于节省变量占用的内存空间,当然要在满足精度要求的前提下。
○提示
MATLAB会自动进行记忆体的使用和回收,而不像C语言,必须由使用者一一指定。这些功能使得MATLAB易学易用,使用者可专心致力于撰写程序。
1.整数类型
MATLAB中提供了8种内置的整数类型,这8种整数类型的存储占用位数、能表示的数值范围和转换函数均不相同,如表2-2所示。
不同的整数类型所占用的位数不同,因此能够表示的数值范围也不同。在实际应用中,应根据实际需要合理选择合适的整数类型。
由于MATLAB中数值的默认存储类型是双精度浮点数类型,因此将变量设置为整数类型时,需要使用相应的转换函数,将双精度浮点数转换为指定的整数类型。
表2-2 MATLAB中的整数类型
在转换过程中,MATLAB默认将待转换数值转换为与之最为接近的整数值,若小数部分为0.5,则转换后的结果为与该浮点数最接近的两个整数中绝对值较大的一个。
另外,这些转换函数也可以将其他数据类型转换为指定的数据类型。在不超出数值范围的情况下,任意两个整数类型之间也可以通过转换函数进行相互转换。同时,由于不同的整数类型能够表示的数值范围不同,因此当运算结果超出相应的整数类型能够表示的范围时,就会出现错误,运算结果被置为该整数类型能够表示的最大值或最小值。
MATLAB中还包含了几类不同运算法则的取整函数,也可以把浮点数转换成整数。这些取整函数及相应的转换方式如表2-3所示。
表2-3 MATLAB中的取整函数
2.浮点数类型
MATLAB中提供了单精度浮点数类型和双精度浮点数类型,其存储位宽、能够表示的数值范围、数值精度各方面均不相同,具体如表2-4所示。
由表2-4可知,单精度浮点数类型的占用位数少,因此占用内存小,但能够表示的数值范围和数值的精度都比双精度浮点数类型小。
由于MATLAB中的默认数值类型为双精度浮点数类型,因此与创建整数类型数值一样,也可以通过转换函数来实现创建单精度浮点数类型。
表2-4 MATLAB中的浮点数类型
双精度浮点数在参与运算时,返回值的类型依赖于参与运算的其他数据类型。当参与运算的其他数据为逻辑类型、字符类型时,返回结果为双精度浮点数类型;当参与运算的其他数据为整数类型时,返回结果为相应的整数类型;当参与运算的其他数据为单精度浮点数类型时,返回结果为相应的单精度浮点数类型。
○提示
在MATLAB中,单精度浮点数类型不能与整数类型进行算术运算。
例2-1:浮点数参与的运算。
在命令行窗口中输入:
输出结果:
在命令行窗口中输入:
输出结果:
在命令行窗口中输入:
输出结果:
在命令行窗口中输入:
输出结果:
在命令行窗口中输入:
输出结果:
在命令行窗口中输入:
输出结果:
由于浮点数只占用一定的存储位宽,其中只有有限位分别用来存储指数部分和小数部分,因此,浮点数类型能够表示的实际数值是有限且离散的,任何两个最近相邻的浮点数之间都有微小间隙,而处在间隙中的数值只能用这两个相邻的浮点数之中的一个来表示。MATLAB中提供了eps函数,可以获取一个数值和最接近该数值的浮点数之间的间隙。
例2-2:浮点数的精度。
在命令行窗口中输入:
输出结果:
在命令行窗口中输入:
输出结果:
3.复数
复数包括实部和虚部两部分。MATLAB中默认使用字符i或j作为虚部标志。在创建复数时,可以直接按照复数形式进行输入或者使用complex函数。MATLAB库函数中关于复数的相关函数如表2-5所示。
表2-5 MATLAB库函数中关于复数的相关函数
4.无穷量(Inf)和非数值量(NaN)
MATLAB中使用Inf和-Inf分别代表正无穷量和负无穷量,NaN表示非数值量。正负无穷量的产生一般是由于运算溢出,产生了超出双精度浮点数数值范围的结果;非数值量则是由于0/0或Inf/Inf类型的非正常运算而产生的,这两个NaN彼此是不相等的。
除了异常运算结果,MATLAB还提供了特定函数Inf和NaN来创建指定数值类型的无穷量和非数值量,生成结果默认为双精度浮点数类型。还有一种特殊的指数类型的数据叫作非数,通常表示运算得到的数值结果超出了运算范围。非数的实部用NaN表示,虚部用InF表示。
例2-3:无穷量及非数值量的产生和性质。
在命令行窗口中输入:
输出结果:
2.1.2 逻辑类型
逻辑类型的数据是指布尔类型的数据及数据之间的逻辑关系。除了传统的数学运算,MATLAB还支持关系和逻辑运算。这些运算的目的是提供求解真/假命题的答案。
作为所有关系和逻辑表达式的输入,MATLAB把任何非零数值当作真,把零当作假。所有关系和逻辑表达式的输出:对于真,输出为1;对于假,输出为0。
逻辑类型数据在进行运算时需要用到关系操作符和逻辑运算符。
MATLAB中的关系操作符如表2-6所示。
表2-6 MATLAB中的关系操作符
续表
MATLAB中的关系操作符能用来比较两个同样大小的数组,或用来比较一个数组和一个标量。在后一种情况中,标量和数组中的每一个元素相比较,结果与数组大小一样。
例2-4:判断两个数组中的元素是否相等。
在命令行窗口中输入:
输出结果:
在命令行窗口中输入:
输出结果:
○提示
“=”和“==”在MATLAB中的意义是不同的。“==”是对等号两边的两个变量进行比较,当它们相等时返回1,不相等时返回0;而“=”则被用来将运算的结果赋给一个变量。
逻辑运算符提供了一种组合或否定关系表达式,如表2-7所示。
表2-7 MATLAB中的逻辑运算符
例2-5:判断两个数组中的元素是否相等。
在命令行窗口中输入:
输出结果:
除了上述关系操作符与逻辑运算符,MATLAB还提供了大量其他关系与逻辑函数。
(1)xor(x,y)指令的功能为异或运算,x和y同为零(假)或非零(真)时返回0,否则返回1。
(2)any(x)指令的功能为判断是否为零向量或零矩阵(向量或矩阵中的元素全部为零),如果是非零向量或非零矩阵,则返回1,否则返回0。
除此之外,MATLAB还提供了大量的函数,在运算过程中用来测试特殊值或条件是否存在,并返回相应的表示结果的逻辑值,如表2-8所示。
表2-8 测试函数
2.1.3 字符和字符串
在MATLAB中,文本当作特征字符串或简单地当作字符串。字符串能够显示在屏幕上,也可以用来构成一些命令,这些命令在其他的命令中用于求值或者被执行。
在MATLAB中可能会遇到对字符和字符串的操作。一个字符串是存储在一个行向量中的文本,这个行向量中的每一个元素代表一个字符。实际上,元素中存放的是字符的内部代码,即ASCII码。
当在屏幕上显示字符变量的值时,显示出来的是文本,而不是ASCII数字。由于字符串是以向量的形式来存储的,因此可以通过它的下标对字符串中的任何一个元素进行访问。字符矩阵也可以通过下标索引进行访问,但是矩阵的每行字符数必须相同。
字符串一般是ASCII值的数值数组,它作为字符串表达式进行显示。
例2-6:字符串属性示例。
在命令行窗口中输入:
输出结果:
在命令行窗口中输入:
输出结果:
一个字符串是由单引号括起来的简单文本。在字符串中的每个字符是数组中的一个元素,字符串的存储要求每个字符8字节,如同MATLAB的其他变量。
因为ASCII字符只要求1字节,故这种存储要求是浪费的,7/8所分配的存储空间无用。然而,对字符串保持同样的数据结构可以简化MATLAB的内部数据结构。所给出的字符串操作并不是MATLAB的基本特点,但这种表达是方便和可接受的。
为了了解下面字符串的ASCII表达,只需对字符串执行一些算术运算。最简单和计算上最有效的方法是取数组的绝对值。
例2-7:字符串的ASCII表达。
在命令行窗口中输入:
输出结果:
在命令行窗口中输入:
输出结果:
在上例中,加零到字符串并没有改变它的ASCII表达。
因为字符串是数值数组,所以它们可以用MATLAB中所有可利用的数组操作工具进行操作。
例2-8:字符串数组的索引示例。
在命令行窗口中输入:
输出结果:
在命令行窗口中输入:
输出结果:
在上例中,字符串像数组一样进行编址。这里元素7~10包含单词good。
字符串中的单引号是由两个连续的单引号来表示的。
例2-9:字符串中的单引号。
在命令行窗口中输入:
输出结果:
字符串的连接可以通过直接将字符串数组连接来实现。
例2-10:字符串的连接。
在命令行窗口中输入:
输出结果:
2.1.4 函数句柄
在MATLAB平台中,对函数的调用方法分为直接调用法和间接调用法。
● 直接调用函数,被调用的函数通常被称为子函数。但是子函数只能被与其M文件同名的主函数或在M文件中的其他函数所调用,一个文件中只能有一个主函数。
● 使用函数句柄对函数进行调用可以避免上述问题。函数句柄提供了一种间接调用函数的方法。创建函数句柄需要用到操作符@。对MATLAB库函数中提供的各种M文件中的函数和使用者自主编写的程序中的内部函数,都可以创建函数句柄,从而可以通过函数句柄来实现对这些函数的间接调用。
创建函数句柄的一般句法格式为:
其中:
● Function_Filename是函数所对应的M文件的名称或MATLAB内部函数的名称。
● @是句柄创建操作符。
● Function_Handle变量保存了这一函数句柄,并在后续的运算中作为数据流进行传递。
例如,F_Handle=@cos就创建了MATLAB内部函数cos的句柄,并将其保存在F_Handle变量中,在后续的运算过程中就可以通过F_Handle(x)来实现cos(x)的功能。
在通过函数句柄调用函数时,也需要指定函数的输入参数。例如,可以通过F_Handle(arg1,arg2,…,argn)这样的调用格式来调用具有多个输入参数的函数。
对于那些没有输入参数的函数,在使用句柄调用时,在句柄变量之后的圆括号中不填写变量名即可,即F_Handle()。
例2-11:函数句柄的创建与调用。
在命令行窗口中输入:
输出结果:
在命令行窗口中输入:
输出结果:
MATLAB库函数中提供了大量关于处理函数句柄的操作函数,将函数句柄的功能与其他数据类型联系起来,扩展了函数句柄的应用。函数句柄的简单操作函数如表2-9所示。
表2-9 函数句柄的简单操作函数
例2-12:函数句柄的基本操作。
在命令行窗口中输入:
输出结果:
在命令行窗口中输入:
输出结果:
在命令行窗口中输入:
输出结果:
在命令行窗口中输入:
输出结果:
在命令行窗口中输入:
输出结果:
2.1.5 结构体类型
MATLAB中的结构体与C语言中的结构体类似,一个结构体可以通过字段存储多个不同类型的数据。因此,结构体相当于一个数据容器,把多个相关联的不同类型的数据封装在一个结构体对象中。
如图2-1所示,结构体student中有4个字段,姓名字段name中存储了一个字符串类型的数据;年级字段grade中存储了一个浮点数值;科目字段subject中存储了一个一维字符串数组;成绩字段result中存储了一个一维数组。
图2-1 结构体student的示意图
一个结构体中可以有多个字段,每个字段又可以存储不同类型的数据,通过这种方式就把多个不同类型的数据组织在一个结构体对象中。
创建结构体对象的方法有两种,可以直接通过赋值语句给结构体的字段赋值,也可以使用结构体创建函数struct。两种方法的具体操作步骤如下。
(1)通过字段赋值创建结构体。在对结构体的字段进行赋值时,赋值表达式的变量名使用“结构体名称.字段名称”的形式书写,对同一个结构体可以进行多个字段的赋值。
例2-13:通过字段赋值创建结构体。
在命令行窗口中输入:
输出结果:
在命令行窗口中输入:
输出结果:
在上例中,通过对4个字段赋值,创建了结构体对象Student,然后用whos函数分析出Student是一个1×1的结构体数组。
○注意
在进行字段赋值操作时,没有明确赋值的字段,MATLAB默认赋值为空数组。通过圆括号索引进行字段赋值,还可以创建任意尺寸的结构体数组。需要注意的是,同一个结构体数组中的所有结构体对象具有相同的字段组合。
(2)利用struct函数创建结构体。
struct函数的句法形式为:
上述语句可以创建结构体对象StrArray,并将其n个字段分别赋值为var1,var2,…,varn。
例2-14:利用struct函数创建结构体。
在命令行窗口中输入:
输出结果:
在命令行窗口中输入:
输出结果:
在命令行窗口中输入:
输出结果:
在命令行窗口中输入:
输出结果:
在命令行窗口中输入:
输出结果:
在命令行窗口中输入:
输出结果:
在命令行窗口中输入:
输出结果:
在命令行窗口中输入:
输出结果:
2.1.6 数组类型
在MATLAB中进行运算的所有数据类型,都是按照数组及矩阵的形式进行存储和运算的,二者在MATLAB中的基本运算性质不同,数组强调元素对元素的运算,而矩阵则采用线性代数的运算方式。本节主要介绍数组类型,关于矩阵的详细运算语法在第3章中讲解。
数组的属性及数组之间的逻辑关系,是编写程序时非常重要的两个方面。在MATLAB平台上,数组的定义是广义的,数组的元素可以是任意数据类型,例如可以是数值、字符串、指针等。
利用数组的构建方法可以直接对变量进行赋值。
例2-15:对变量赋值创建数组。
在命令行窗口中输入:
输出结果:
在MATLAB中可以使用冒号“:”来代表一系列数值,有时也使用它来定义数组。其句法格式如下:
创建从i开始、步长为1、到k结束的数字序列,即i,i+1,i+2,…,k。如果i>k,MATLAB则返回一个空矩阵。数字i和k不必是整数,该序列的最后一个数小于或等于k。
创建从i开始、步长为j、到k结束的数字序列,即i,i+j,i+2j,…,k。如果j=0,则返回一个空矩阵。数字i、j和k不必是整数,该序列的最后一个数小于或等于k。
还有一些预定义函数也可以用来创建线性序列和逻辑序列。
在区间[a,b]上创建一个有100个元素的向量,这100个数把整个区间线性分隔。
在区间[a,b]上创建一个有n个元素的向量。这个命令和冒号表示形式相近,但是它直接定义了数据的个数。
例2-16:创建等差数列。
在命令行窗口中输入:
输出结果:
当数组的元素个数为0时,就称数组为空。空数组是特殊的数组,它不含有任何元素。空数组主要用于逻辑运算、数组声明、数组的清空等。
例2-17:创建空数组。
在命令行窗口中输入:
输出结果:
2.1.7 单元数组类型
1.概述
单元(Cell)数组是一种无所不包的广义矩阵。组成单元数组的每一个元素称为一个单元。每一个单元可以包括一个任意数组,如数值数组、字符串数组、结构体数组或另外一个单元数组,因而每一个单元可以具有不同的尺寸和内存占用空间。
○注意
和一般的数值数组一样,单元数组的维数不受限制,可以是一维、二维或多维。
MATLAB中使用单元数组的目的在于,它可以把不同类型的数据归并到一个数组中。
○注意
单元数组的创建有两种方法:使用赋值语句创建单元数组和利用cell函数创建空单元数组。
(1)使用赋值语句创建单元数组。与一般数组有所不同的是,单元数组使用花括号“{}”来创建,使用逗号“,”或空格来分隔每一个单元,使用分号“;”来分行。
例2-18:创建单元数组。
在命令行窗口中输入:
程序运行结果如下:
(2)利用cell函数创建空单元数组。
cell函数的调用格式如下:
该函数创建一个m×n的空单元数组,其每一个单元均为空矩阵。
例2-19:创建空单元数组。
在命令行窗口中输入:
程序运行结果如下:
同一般的数值数组一样,单元数组的内存空间也是动态分配的。因此,使用cell函数创建空单元数组的主要目的是为该单元数组预先分配连续的存储空间,以节约内存占用,提高执行效率。
2.单元数组的寻访
在单元数组中,单元和单元中的内容是两个不同范畴的东西,因此,寻访单元和单元中的内容是两种不同的操作。MATLAB为上述两种操作设计了相对应的操作对象:单元外标识(Cell Indexing)和单元内编址(Content Addressing)。
对于单元数组C,C(m,n)指的是单元数组中第m行第n列的单元,而C{m,n}指的是单元数组中第m行第n列单元中的内容。
例2-20:单元数组的寻访。
在命令行窗口中依次输入以下命令:
依次得到的结果如下:
3.单元数组的操作
单元数组的操作包括合并、删除单元数组中的指定单元、改变单元数组的形状等。
(1)单元数组的合并。
例2-21:单元数组的合并。
在命令行窗口中依次输入以下命令:
得到的结果如下:
(2)单元数组中指定单元的删除。
如果要删除单元数组中指定的某个单元,则只需要将空矩阵赋给该单元,即:
例2-22:有一个单元数组C,删除其中的某个单元。
在命令行窗口中依次输入下列命令:
得到的结果如下:
(3)使用reshape函数改变单元数组的形状。
reshape函数的调用格式为:
该函数将单元数组C改变成一个具有M行N列的新单元数组。
例2-23:将例2-22中的单元数组C(1×4)改变成newC(4×1)。
在命令行窗口中输入:
得到的结果如下:
2.1.8 map容器类型
1.map容器类型及map类概述
map的本意是映射,就是可以将一个量映射到另一个量。比如将一个字符串映射为一个数值,则该字符串就是map的键(key),数值就是map的数据(value)。因此,可以将map容器理解为一种快速查找数据结构的键。
对一个map元素进行寻访的索引称为“键”。一个键可以是以下任何一种数据类型:
● 1×N字符串。
● 单精度或双精度实数标量。
● 有符号或无符号标量整数。
这些键和其对应的数据存储在map中。一个map的每一个条目都包括唯一的键和相对应的数据。map中存储的数据可以是任何类型的,包括数值类型、字符或字符串类型、结构体类型、单元类型或其他map。
一个map是MATLAB类的一个对象。map类的所有对象具有3种属性,如表2-10所示。用户不能直接对这些属性进行修改,但可以通过作用于map类的函数进行修改。
表2-10 map类的属性
map类的属性的查看方法为map名+小数点“.”+map的属性名。例如,为了查看mapW对象包括的数据类型,需要使用mapW.ValueType。
2.创建map对象
map是一个map类中的对象,由MATLAB中名为“容器”的一个包来定义,可以通过构造函数来创建,其创建方法如下:
当键和值是字符串时,需要对上述语法稍作变更,即:
例2-24:创建一个名为schedulemap的map对象来存储如表2-11所示的课程表。
表2-11 课程表
创建过程如下:
得到的结果如下:
此外,map对象的创建可以分为两个步骤:首先创建一个空map对象;然后使用keys和values方法对其内容进行补充。空map对象的创建方法如下:
得到的结果如下:
3.查看/读取map对象
(1)查看map对象。
map对象中的每个条目包括两个部分:一个唯一的键及其对应的值。可以通过使用keys函数查看map对象中包含的所有键;通过values函数查看所有的值。
例2-25:查看例2-24中创建的map对象。
在命令行窗口中依次输入:
得到的结果如下:
(2)读取map对象。
在创建好一个map对象后,用户可以对其进行数据的寻访。寻访指定键(keyName)所对应的值(valueName)使用的格式如下:
当键名是一个字符串时,需使用单引号将键名括起来。
例2-26:通过使用键名访问例2-24中创建的schedulemap对象中的内容。
在命令行窗口中输入:
得到的结果如下:
如果需要对多个键进行访问,则可以使用values函数,如:
得到的结果如下:
○提示
在对多个键进行访问时,不能像在其他数据类型中那样使用冒号“:”,这将导致错误的产生。例如输入:
结果弹出如下错误信息:
警告:冒号操作数必须为实数标量。
4.编辑map对象
(1)从map对象中删除keys/values对。
用户可以使用remove函数从map对象中删除keys/values对,该函数的调用格式为:
式中,mapName和keyName分别为map对象名称及需要删除的键名。执行该命令后,MATLAB系统删除指定的键名及其相对应的值。
例2-27:删除schedulemap对象中的“星期四”及其对应的科目。
在命令行窗口中依次输入:
得到的结果如下:
(2)添加keys/values对。
当用户向一个map对象中写入新元素的值时,需要提供键名,而且该键的类型必须和map中的其他键一致。该操作的调用格式为:
例2-28:为schedulemap对象添加“星期六”及其对应的科目“public elective course”。
在命令行窗口中依次输入:
得到的结果如下:
(3)修改keys。
如果需要在保持值不变的情况下对键名进行更改,则首先要删除键名和其对应的值,然后再添加一个有正确键名的新条目。
例2-29:根据例2-28中的schedulemap对象的结果,修改“星期六”及其对应的科目“公共选修课”为“星期天”及其对应的科目“MBA”。
在命令行窗口中依次输入:
程序运行结果如下:
(4)修改values。
通过赋值操作,覆盖原有的值,即可对map对象中的值进行修改。
例2-30:修改“星期一”的科目为“英语”。
在命令行窗口中依次输入:
程序运行结果如下: