|Important||This document may not represent best practices for current development, links to downloads and other resources may no longer be valid. Current recommended version can be found here.|
Troubleshooting Data Types
This page lists some common problems that can occur when performing operations on intrinsic data types.
When you work with floating-point numbers (k / (2 ^ n) where k and n are integers). For example, 0.5 (= 1/2) and 0.3125 (= 5/16) can be held as precise values, while 0.2 (= 1/5) and 0.3 (= 3/10) can be only approximations.and ), keep in mind that they are stored as binary fractions. This means they cannot hold an exact representation of any quantity that is not a binary fraction (of the form
Because of this imprecision, you cannot rely on exact results when you operate on floating-point values. In particular, two values that are theoretically equal might have slightly different representations.
To compare floating-point quantities
Calculate the absolute value of their difference, using themethod of the class in the namespace.
Determine an acceptable maximum difference, such that you can consider the two quantities to be equal for practical purposes if their difference is no greater.
Compare the absolute value of the difference to the acceptable difference.
The following example demonstrates both improper and proper comparison of two Double values.
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))
The preceding example uses themethod of the structure so that it can specify greater precision than the CStr keyword uses. The default is 15 digits, but the "G17" format extends it to 17 digits.
Because of the imprecision of floating-point storage, thecan return an unexpected result when at least one of the operands is floating-point.
Thedoes not use floating-point representation. Many numbers that are inexact in Single and Double are exact in Decimal (for example 0.2 and 0.3). Although arithmetic is slower in Decimal than in floating-point, it might be worth the performance decrease to achieve greater precision.
To find the integer remainder of floating-point quantities
Declare variables as Decimal.
Use the literal type character D to force literals to Decimal, in case their values are too large for the Long data type.
The following example demonstrates the potential imprecision of floating-point operands.
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))
The preceding example uses the ToString method of the Double structure so that it can specify greater precision than the CStr keyword uses. The default is 15 digits, but the "G17" format extends it to 17 digits.
Because zeroPointTwo is Double, its value for 0.2 is an infinitely repeating binary fraction with a stored value of 0.20000000000000001. Dividing 2.0 by this quantity yields 9.9999999999999995 with a remainder of 0.19999999999999991.
In the expression for decimalRemainder, the literal type character D forces both operands to Decimal, and 0.2 has a precise representation. Therefore the Mod operator yields the expected remainder of 0.0.
Note that it is not sufficient to declare decimalRemainder as Decimal. You must also force the literals to Decimal, or they default to Double and decimalRemainder receives the same inaccurate value as doubleRemainder.
values are not stored as numbers, and the stored values are not intended to be equivalent to numbers. For compatibility with previous versions, Visual Basic provides conversion keywords ( , CBool, CInt, and so on) to convert between Boolean and numeric types. However, other languages sometimes perform these conversions differently, as do the .NET Framework methods.
You should never write code that relies on equivalent numeric values for True and False. Whenever possible, you should restrict usage of Boolean variables to the logical values for which they are designed. If it is necessary to mix Boolean and numeric values, be sure that you understand the conversion method you choose.
Conversion in Visual Basic
When you use the CType or CBool conversion keywords to convert numeric data types to Boolean, 0 becomes False and all other values become True. When you convert Boolean values to numeric types using the conversion keywords, False becomes 0 and True becomes -1.
Conversion in the Framework
Themethod of the class in the System namespace converts True to +1.
If you need to convert a Boolean value to a numeric data type, take care which conversion method you use.
In the absence of any type characters, Visual Basic assumes default data types for literals. The default type for a character literal — enclosed within double quotes (" ") — is String.
The String data type does not widen to the. This means that if you want to assign a literal to a Char variable, you must either make a narrowing conversion or force the literal to the Char type.
To create a Char literal to assign to a variable or constant
Declare the variable or constant as Char.
Enclose the character value within double quotation marks (" ").
Follow the closing double quotation mark with the literal type character C to force the literal to Char. This is necessary if the type checking switch () is On, and it is desirable in any case.
The following example demonstrates both unsuccessful and successful assignments of a literal to a Char variable.
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")
There is always a risk in using narrowing conversions, because they can fail at run time. For example, a conversion from String to Char can fail if the String value contains more than one character. Therefore, it is better programming to use the C type character.
Theparticipates in very few widening conversions. String widens only to itself and Object, and only Char and Char() (a Char array) widen to String. This is because String variables and constants can contain values that other data types cannot accommodate.
When the type checking switch () is On, the compiler disallows all implicit narrowing conversions, including those involving String. Your code can still use conversion keywords such as CStr and , which direct the .NET Framework to attempt the conversion.
Narrowing Conversion Protection
The disadvantage of narrowing conversions is that they can fail at run time. For example, if a String variable contains anything other than "True" or "False", it cannot be converted to Boolean. If it contains punctuation characters, conversion to any numeric type fails. Unless you know that your String variable always holds values that the destination type can accept, you should not attempt a conversion.
If you need to convert from String to another data type, the safest procedure is to enclose the attempted conversion in the. This allows you to deal with a run-time failure.
A single Char and an array of Char elements both widen to String. However, String does not widen to Char(). To convert a String value to a Char array, you can use themethod of the class.
In general, String values are not meaningful in other data types, and conversion is highly artificial and dangerous. Whenever possible, you should restrict usage of String variables to the character sequences for which they are designed. You should never write code that relies on equivalent values in other types.