数值和布尔数据
数值
控件
通常,LabVIEW 控件选板上排在第一位的就是放置数值控件的选板:

这一栏中的控件虽然在前面板上的外观各不相同,但是它们所表示的数据类型是相同的,都属于数值类型。选板右上方两个控件的数据类型是“时间”,也是数值数据的一种显示方式。还有其它一些控件,尽管位于别的选板,但它们的数据类型也是数值型的,比如下拉列表控件、列表框控件等。
这个控件选板上头两个控件是最常用的数值类型控件,尽管它们的外观是最简单。他们的区别只在于第一个是输入控件,第二个是显示控件。输入控件比显示控件的底色更浅,同时在左侧多了两个增减按钮。在鼠标键盘操作的系统中,这两个按钮比较鸡肋,但是在触摸屏操作的系统上还是有实用性的。除了这两个基本控件,编程人员还可以根据数据的应用环境和表达的具体意义来选定一种控件。例如,在工厂生产流程中,表示某个油罐内的储存油量时,可以选择液罐控件;模拟汽车仪表盘的时候应该选仪表控件;等等。
LabVIEW 数值控件还有丰富的各种设置和显示方式,有一些在控件的鼠标右键菜单中就能发现,比如设置数据的进制、单位等:

而更多的设置是在控件的属性对话框中。在控件的右键菜单上点击“属性”,就会打开属性对话框:

我们可以在属性对话框中设置控件的状态、尺寸、数据范围等等。这里大多数设置是比较直观的,看到名字就能够理解。比如,设置数值范围可以对数据的范围加以限制,避免程 序运行时出现数值越界错误。设置显示格式可以方便用户观察数据。
在属性对话框的显示格式页上,我们可以选择用何种方式显示一个数据,比如以小数方式、科学计数法或工程计数法来显示,对于整数还可以选择进制,比如二进制、十六进制等。如果我们正在设置的数值表示的是一个时间,使用单一的数值来显示时间显然不符合我们识别时间的习惯,我们需要让它以年月日的格式显示时间值。设置时间显示方式,相对复杂一些,尤其当我们需要使用自定义的格式时。这时,可以在显示格式页面中,先选择需要设置的类型是“绝对时间”(或“相对时间”),然后在下方选择“高级编辑模式”,就可以为控件设置显示方式了(如上图)。例如,在 "格式字符串" 一栏中输入 %<%Y-%m-%d %H:%M:%S>T,可以让控件按照 "年-月-日 时:分:秒" 的格式把一个实数数值显示出来。
实数“0.0”用绝对时间格式表示如下:
当一个实数用来表示绝对时间时,其含义是指 通用协调时间 (UTC) 1904 年 1 月 1 日 00:00:00 这一时刻之后的多少秒。LabVIEW 在显示时间时,会根据当前计算机的时区设置,自动将其转换为本地时间(例如北京时间)进行显示,比如 0 表示北京时间 1904 年 1 月 1 日 早 8 点整。
常量
鼠标右键点击某一个数值型数据常量,可以看到其快捷菜单中 "匹配至输入数据" 一项是默认选中的。也就是说,常量将会根据输入值自动选择表示法。例如,在常量中输入一个正数,假设为 "34",常量的类型会自动变为 I32 整型(蓝色 );假如输入为 "34.3",常量的类型会自动变为 DBL 实数型(橙黄色
)。如果要输入实数型 34,则应该输入 "34.0"。
数值型控件并无这一选项。也就是说,对数值型控件而言,必须视需要人为选择控件的表示法。
表示法
一个数值型数据还可以有多种不同的表示法,用来表示不同范围和精度的数据。我们可以认为数值类型属于一种数据类型,而 I32,U8 等只是不同的表示法;也可以把数值类型的不同表示法视作不同数据类型。在文本编程语言中,一般都是把 I32,U8 等当作不同的数据类型处理的。
在 VI 的前面板上放置一个数值型控件,或在程序框图上放置一个数值常量,在它们的右键菜单中可以查看或更改其表示法(Representation):
在 LabVIEW 帮助的索引中搜索“数值”,打开数值分类下的数据,可以查看到每种表示法的详细解释。从表示法的图标中可以很清楚地看出,每种表示法的区别在于数据长度不同。计算机使用的是二进制,每一位可以表示 0 或 1 两个值,8 位为 1 字节。每种表示法的长度如下表所示。
| EXT | 扩展精度实数,字节长取决于平台 | DBL | 双精度实数,8 字节长 |
| SGL | 单精度实数,4 字节长 | FXP | 定点数,最大 8 字节长 |
| I64 | 带符号 64 位整数 | I32 | 带符号 32 位整数 |
| I16 | 带符号 16 位整数 | I8 | 带符号 8 位整数 |
| U64 | 无符号 64 位整数 | U32 | 无符号 32 位整数 |
| U16 | 无符号 16 位整数 | U8 | 无符号 8 位整数 |
| CXT | 扩展精度复数,2×16 字节长 | CDB | 双精度复数,2×8 字节长 |
| CSG | 单精度复数,2×4 字节长 |
EXT(扩展精度)的实际长度和精度取决于操作系统。在 Windows 平台上,它通常映射为双精度实数(8 字节),并不提供比 DBL 更高的精度。在 macOS 或 Linux 上,它可能提供更高的精度(如 80-bit 浮点数,占用 12 或 16 字节)。
一般来说,长度越长,可以表示的数值范围就越大、精度也越高,但计算速度越慢,占用存储空间也越大。
选择表示法首先要考虑能够满足程序需求。比如说 I16 表示法能够支持的数值范围是 - 32768 到 32767 之间的整数,这个范围甚至不够计算 300×300 这样的简单算术运算。我们可 以现在就编写一个程序:新建一个 VI,在 VI 上放置两个值为 300 的 I16 常量,然后相乘,将乘积用一个 I16 的数值控件来显示,看看他们的积是多少。这种错误叫做“溢出”,也就是需要表示的数值已经大于一个控件可以表示的最大数值了。此类错误如果隐藏在一个大工程内,查找起来是颇为困难的。
I64 可以表示的范围就要大很多,可以达到 数量级。但这样的数量级如果用于计算阶乘,最多也只能算到 20 的阶乘(即 20!)。需要更广泛的数值范围,或者用到小数时,就要使用实数表示法。某些科学计算中还需要用到复数。
其次,要考虑程序的运行效率和存储效率。计算机对于实数的运算速度要大大慢于整数运算。所以,程序中的数据,若能够以整数表示的,如表示人数、物件个数等只可能出现整数的物理量,数值又不会太大时,尽量使用整数,而不要用实数。
复数是由两个分别表示实数部和虚数部的实数组成的,运算速度更慢。
对于单个数据而言,使用 U16 与使用 U32 表示法相比,不过相差两字节。这个长度上的差别可以忽略不计,对程序占用的存储空间根本不会有什么影响。为安全起见,不妨尽量使用长度较大的表示法。但如果数据量较大时,选择不同表示法会导致程序内存占用的巨大差异,需要慎重选择。比如用于一个包含大量元 素的数组,若数组有 1,000 个元素时,元素采用 U16 与 U32 表示法相比,则有 2K 字节存储空间的差别;若数组有 1,000,000 个元素时,差别达到 2M 字节,已经相当可观。
数值表示法之间的转换
数值表示法之间,通常不需要经过特殊函数进行转换。用连线把一个数值,连接到另一种表示法数值类型的接线端上,数据就会自动转换成新的表示法。有些函数,如加法函数,可以接受任何表示法的数据。若有两个不同表示法的数据作为加数传递给加法函数,加法函数会把表示范围较小的那个数据转换为范围较大的表示法,结果数据当然也采用后一种表示法。数据表示法发生变化的地方会出现一个红点(强制转换点),以提醒编程者的注意:
一般来说,这些强制转换点并不会影响程序运行。但它们毕竟是编程时无意识造成的,有可能存在潜在危险。比如编程者不小心使用了一个短数据类型来显示一个原本是长数据类型的数据,就有潜在的数值溢出的可能。所以,为了消除这些潜在威胁,应当消除所有的强制转换点(函数上那个红点)。如果程序中确实需要进行强制转换,可以使用表示法转换函数(在函数选板 "编程 -> 数值 -> 转换" 中),以避免在无意识情况下造成的数值转换错误:
一些特殊的实数
前面提到整数运算在产生溢出时,程序不会报错,但是用户看到的数值却是一个错误的数据了。那么实数运算会产生溢出吗?实数虽然能够表示的的数据范围要大的多,但也是有限的。双精度实数 DBL 可以表示的最大数值大约为 。如果数据超出这个范围,LabVIEW同样不会报错,而是会使用一个特殊的符号,Inf(正无穷大),来表示所有比这个范围还大的数。当然对应的还有 -Inf,负无穷大。
比如,在 LabVIEW 中计算 ,结果就是 Inf。在很多其它编程语言中,除以零会抛出异常,而不是得到一个特殊结果。0 除以任何数都等于零,任何数除以 0 都等于无穷大,那么 0 除以 0 等于几?在 LabVIEW 中 会得到另一个符号 NaN,表示这不是一个数值。在其它一些情况下,也会得到 NaN,比如 NaN 和数值做运算都会得到 NaN; +Inf 与 -Inf 相加会得到 NaN; Inf 除以 Inf 会得到 NaN; -1 开平方也会得到 NaN。
-1 开平方在实数域内确实没有结果,但是如果在复数域内就是一个合法的计算了。我们把输入和输出的表示法都换成双精度复数,再计算一遍:

-1 开平方的结果应该是 i,但是在笔者的电脑上得到的结果是 6.12303E-17+1i,它有一个近似为零却不是零的非常小的实数部分。这是计算中的误差造成的,双精度实数毕竟只有 8 个字节,不但能表示的数值范围有限,分辨率也有限,只能间隔的表示一段数值范围内的一部分数值,如果真实数值没有恰好是这些数值中的一个,就只能使用近似的值来表示。使用近似值产生的误差,可能是在计算过程中由中间值产生的,累积到最终结果的时候,也会被体现出来,以至于一些本来可以被精确表示的最终计算结果,也会带有误差,比如 的结果,尽管双精度复数是可以精确表示它,但这里还是显示出了误差。这也提醒我们,在比较两个实数是否相等的时候,一定要考虑误差。
常见运算
与数值数据相关的基本运算函数和节点大多位于“编程 -> 数值”函数选板下:

这些函数节点的图标非常直观地表示出了它们的功能:加、减、四舍五入、求倒数等。在“数学”函数选板中,还有一些更复杂的有关数学运算的函数和 VI。每一个函数的功能可以在 LabVIEW 帮助文档上找到,本书就不重复了。
数学运算的算法纷繁复杂,难免有时需要一个函数,却不知道它藏在哪个函数选板下。此时,可以利用函数或控件选板的搜索功能,点击函数或控件选板上方的“搜索”按钮(图标为放大镜的按钮),就可以进入选板搜索功能:

在搜索界面上输入关键词,然后选中一个搜索结果,拖放到 VI 的程序框图或前面板上即可。如果双击一个搜索结果,会跳转到这个结果所在的选板位置,这样我们就能够知道这个节点放置在哪个选板上,以后可以直接到这个选板下选择该节点。
很多数学运算函数的图标比较小输入接线端离得也比较近(比如减法函数),如果不小心把两个输入数据线连接到了错误的接线端上,或者就只是希望调换两个输入数据的位置,不需要把数据删除再重新连接。可以采用一种更便捷的方法:先把鼠标移动到加减法数的输入参数接线端上,再按下Ctrl键,光标会从绕线轴变成一个类似剪刀的形状。点击鼠标,这两个输入端的连线就会交换位置,如下图。这个方法只对有两个输入参数的函数有效。
