此页列出了对内部数据类型执行作时可能发生的一些常见问题。
Floating-Point 表达式不相等
处理浮点数(单数据类型 和 双数据类型)时,请记住,它们存储为二进制分数。 这意味着它们不能保留任何不是二进制分数(形式 k / (2 ^ n) 且 k 和 n 是整数的任何数量的确切表示形式。 例如,0.5 (= 1/2) 和 0.3125 (= 5/16) 可以保留为精确值,而 0.2 (= 1/5) 和 0.3 (= 3/10) 只能是近似值。
由于这种不精确性,因此在对浮点值进行作时,不能依赖确切的结果。 具体而言,理论上相等的两个值可能略有不同表示形式。
| 比较浮点数量 |
|---|
| 1. 使用Abs命名空间中System类的方法计算其差的Math绝对值。 2. 确定可接受的最大差值,这样,如果两个数量的差异不大,则可以将其视为相等的实用用途。 3.将差异的绝对值与可接受的差值进行比较。 |
下面的示例演示了两 Double 个值的不正确和正确的比较。
Dim oneThird As Double = 1.0 / 3.0
Dim pointThrees As Double = 0.333333333333333
' The following comparison does not indicate equality.
Dim exactlyEqual As Boolean = (oneThird = pointThrees)
' The following comparison indicates equality.
Dim closeEnough As Double = 0.000000000000001
Dim absoluteDifference As Double = Math.Abs(oneThird - pointThrees)
Dim practicallyEqual As Boolean = (absoluteDifference < closeEnough)
MsgBox("1.0 / 3.0 is represented as " & oneThird.ToString("G17") &
vbCrLf & "0.333333333333333 is represented as " &
pointThrees.ToString("G17") &
vbCrLf & "Exact comparison generates " & CStr(exactlyEqual) &
vbCrLf & "Acceptable difference comparison generates " &
CStr(practicallyEqual))
前面的示例使用 ToString 结构的方法 Double ,以便它可以指定比 CStr 关键字使用的精度更好的方法。 默认值为 15 位数字,但“G17”格式将其扩展到 17 位。
Mod 运算符不返回准确的结果
由于浮点存储不精确,当至少有一个作数为浮点时, Mod 运算符 可能会返回意外的结果。
十进制数据类型不使用浮点表示形式。 许多数字不相交 Single 且 Double 精确 Decimal (例如 0.2 和 0.3)。 尽管算术比 Decimal 浮点慢,但性能可能值得降低,以实现更好的精度。
| 查找浮点数量的整数余数 |
|---|
1. 将变量声明为 Decimal.2. 使用文本类型字符 D 强制文本 Decimal,以防其值太大而 Long 无法用于数据类型。 |
以下示例演示浮点作数的潜在不精确性。
Dim two As Double = 2.0
Dim zeroPointTwo As Double = 0.2
Dim quotient As Double = two / zeroPointTwo
Dim doubleRemainder As Double = two Mod zeroPointTwo
MsgBox("2.0 is represented as " & two.ToString("G17") &
vbCrLf & "0.2 is represented as " & zeroPointTwo.ToString("G17") &
vbCrLf & "2.0 / 0.2 generates " & quotient.ToString("G17") &
vbCrLf & "2.0 Mod 0.2 generates " &
doubleRemainder.ToString("G17"))
Dim decimalRemainder As Decimal = 2D Mod 0.2D
MsgBox("2.0D Mod 0.2D generates " & CStr(decimalRemainder))
前面的示例使用 ToString 结构的方法 Double ,以便它可以指定比 CStr 关键字使用的精度更好的方法。 默认值为 15 位数字,但“G17”格式将其扩展到 17 位。
正因为如此zeroPointTwoDouble,0.2 的值是无限重复的二进制分数,其存储值为 0.20000000000000001。 将 2.0 除以此数量可产生 9.999999999999999955,其余部分为 0.199999999999991。
在表达式 decimalRemainder中,文本类型字符 D 强制两个作数, Decimal而 0.2 具有精确的表示形式。 因此, Mod 运算符将生成 0.0 的预期余数。
请注意, decimalRemainder 声明为 Decimal. 还必须强制文本 Decimal,或者它们默认使用 Double ,并 decimalRemainder 接收与相同的不准确值 doubleRemainder。
布尔类型不会准确转换为数值类型
布尔数据类型 值不存储为数字,并且存储的值不等于数字。 为了与早期版本兼容,Visual Basic 提供了转换关键字(CType 运算符、CBoolCInt等),用于在数字类型之间进行Boolean转换。 但是,其他语言有时会以不同的方式执行这些转换,就像 .NET Framework 方法一样。
不应编写依赖于等效数值 True 的代码和 False。 应尽可能将变量的使用 Boolean 限制为设计变量的逻辑值。 如果必须混合 Boolean 和数值,请确保了解所选的转换方法。
Visual Basic 中的转换
使用 CType 或 CBool 转换关键字将数值数据类型 Boolean转换为时,0 将变为 False 其他所有值 True。 使用转换关键字将值转换为 Boolean 数值类型时, False 变为 0,变为 True -1。
框架中的转换
ToInt32命名空间中System类的方法Convert转换为 True +1。
如果必须将值转换为 Boolean 数值数据类型,请注意所使用的转换方法。
字符文本生成编译器错误
在没有任何类型字符的情况下,Visual Basic 假定文本的默认数据类型。 字符文本的默认类型 (括在引号 (" ") 中 ) 为 String。
数据类型 String 不会扩大为 Char 数据类型。 这意味着,如果要向变量分配文本 Char ,则必须进行缩小转换或强制文本转换为 Char 类型。
| 创建 Char 文本以分配给变量或常量 |
|---|
1. 将变量或常量声明为 Char.2. 将字符值括在引号 ( " ") 中。3. 按照右双引号和文本类型字符 C 强制文本 Char。 如果类型检查开关(Option Strict 语句)是必需的 On,并且在任何情况下都是可取的。 |
以下示例演示文本向变量赋值失败和成功赋 Char 值。
Dim charVar As Char
' The following statement attempts to convert a String literal to Char.
' Because Option Strict is On, it generates a compiler error.
charVar = "Z"
' The following statement succeeds because it specifies a Char literal.
charVar = "Z"c
' The following statement succeeds because it converts String to Char.
charVar = CChar("Z")
使用缩小转换始终存在风险,因为它们在运行时可能会失败。 例如,如果String值包含多个字符,则从String转换到Char失败。 因此,最好使用类型字符进行 C 编程。
字符串转换在运行时失败
字符串数据类型参与的转换很少。
String 只扩大到自身, Object只有 Char 和 Char() (数组 Char )扩大到 String。 这是因为 String 变量和常量可以包含其他数据类型不能包含的值。
当类型检查开关(Option Strict Statement)为 On时,编译器禁止所有隐式缩小转换。 这包括涉及 String的那些。 代码仍可以使用转换关键字(如 CStrCType 运算符)来指示 .NET Framework 尝试转换。
注释
对于从集合中的 For Each…Next 元素到循环控制变量的转换,禁止显示窄转换错误。 有关详细信息和示例,请参阅 For Each... 中的“缩小转换”部分 ...Next 语句。
缩小转换保护范围
缩小转换的缺点是它们在运行时可能会失败。 例如,如果 String 变量包含除“True”或“False”以外的任何内容,则无法将其转换为 Boolean。 如果它包含标点符号字符,则转换为任何数值类型将失败。 除非你知道变量 String 始终保留目标类型可以接受的值,否则不应尝试转换。
如果必须从 String 另一个数据类型转换,则最安全的过程是将尝试的转换括在 Try...抓住。。。Finally 语句。 这样,便可以处理运行时故障。
字符数组
单个 Char 元素和元素数组 Char 都扩大为 String。 但是, String 不会扩大到 Char()。 若要将 String 值转换为 Char 数组,可以使用 ToCharArray 类的方法 System.String 。
无意义值
通常, String 值在其他数据类型中没有意义,转换非常人为和危险。 应尽可能将变量的使用 String 限制为设计变量的字符序列。 不应编写依赖于其他类型的等效值的代码。