Solucionar problemas de tipos de datos (Visual Basic)

En esta página se enumeran algunos problemas comunes que pueden producirse al realizar operaciones en tipos de datos intrínsecos.

Floating-Point expresiones no se comparan como iguales

Al trabajar con números de punto flotante (tipo de datos único y tipo de datos Double), recuerde que se almacenan como fracciones binarias. Esto significa que no pueden contener una representación exacta de cualquier cantidad que no sea una fracción binaria (de la forma k/(2 ^ n), donde k y n son enteros). Por ejemplo, 0,5 (= 1/2) y 0,3125 (= 5/16) se pueden conservar como valores precisos, mientras que 0,2 (= 1/5) y 0,3 (= 3/10) solo pueden ser aproximaciones.

Debido a este imprecisión, no se puede confiar en los resultados exactos cuando se trabaja en valores de punto flotante. En concreto, dos valores que son teóricamente iguales pueden tener representaciones ligeramente diferentes.

Para comparar las cantidades de punto flotante
1. Calcule el valor absoluto de su diferencia mediante el Abs método de la Math clase en el System espacio de nombres.
2. determinar una diferencia máxima aceptable, por lo que puede considerar que las dos cantidades son iguales a efectos prácticos si su diferencia no es mayor.
3. Compare el valor absoluto de la diferencia con la diferencia aceptable.

En el ejemplo siguiente se muestra la comparación incorrecta y correcta de dos Double valores.

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))

En el ejemplo anterior se usa el ToString método de la Double estructura para que pueda especificar mejor precisión de la que CStr utiliza la palabra clave. El valor predeterminado es 15 dígitos, pero el formato "G17" lo extiende hasta 17 dígitos.

El operador mod no devuelve un resultado preciso

Debido a la imprecisión del almacenamiento de punto flotante, el operador mod puede devolver un resultado inesperado cuando al menos uno de los operandos es de punto flotante.

El tipo de datos decimal no utiliza la representación de punto flotante. Muchos números que son inexactos en Single y Double son exactos en Decimal (por ejemplo 0,2 y 0,3). Aunque la aritmética es más lenta Decimal que en punto flotante, podría merecer la pena la disminución del rendimiento para lograr una mayor precisión.

Para buscar el resto entero de las cantidades de punto flotante
1. declarar variables como Decimal .
2. Use el carácter de tipo literal D para forzar literales a Decimal , en caso de que sus valores sean demasiado grandes para el Long tipo de datos.

En el ejemplo siguiente se muestran los posibles imprecisión de operandos de punto flotante.

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))

En el ejemplo anterior se usa el ToString método de la Double estructura para que pueda especificar mejor precisión de la que CStr utiliza la palabra clave. El valor predeterminado es 15 dígitos, pero el formato "G17" lo extiende hasta 17 dígitos.

Dado que zeroPointTwo es Double , su valor para 0,2 es una fracción binaria repetida infinitamente con un valor almacenado de 0.20000000000000001. La división de 2,0 por esta cantidad produce 9.9999999999999995 con un resto de 0.19999999999999991.

En la expresión para decimalRemainder , el carácter de tipo literal D fuerza ambos operandos a Decimal y 0,2 tiene una representación precisa. Por lo tanto, el Mod operador produce el resto esperado de 0,0.

Tenga en cuenta que no es suficiente declarar decimalRemainder como Decimal . También debe forzar los literales en Decimal , o usar Double de forma predeterminada y decimalRemainder recibir el mismo valor inexacto que doubleRemainder .

El tipo Boolean no se convierte en un tipo numérico con precisión

Los valores de tipo de datos booleanos no se almacenan como números y los valores almacenados no están diseñados para ser equivalentes a números. Por compatibilidad con versiones anteriores, Visual Basic proporciona palabras clave de conversión (función ctype, CBool , CInt , etc.) para convertir entre Boolean tipos numéricos y. Sin embargo, a veces otros lenguajes realizan estas conversiones de manera diferente, al igual que los métodos de .NET Framework.

Nunca debe escribir código que se base en valores numéricos equivalentes para True y False . Siempre que sea posible, debe restringir Boolean el uso de variables a los valores lógicos para los que están diseñadas. Si debe mezclar Boolean valores numéricos y, asegúrese de que comprende el método de conversión que seleccione.

Conversión en Visual Basic

Cuando se utilizan las CType CBool palabras clave de conversión o para convertir tipos de datos numéricos en Boolean , 0 se convierte en False y todos los demás valores se True convierten en. Cuando se convierten Boolean valores en tipos numéricos mediante las palabras clave de conversión, False se convierte en 0 y True se convierte en-1.

Conversión en el marco de trabajo

El ToInt32 método de la Convert clase en el System espacio de nombres True convierte en + 1.

Si debe convertir un Boolean valor en un tipo de datos numérico, tenga cuidado con el método de conversión que utilice.

El literal de carácter genera un error del compilador

En ausencia de caracteres de tipo, Visual Basic asume los tipos de datos predeterminados para los literales. El tipo predeterminado para un literal de carácter, entre comillas ( " " ), es String .

El String tipo de datos no se amplía al tipo de datos char. Esto significa que, si desea asignar un literal a una Char variable, debe realizar una conversión de restricción o forzar el literal al Char tipo.

Para crear un literal char para asignarlo a una variable o constante
1. declare la variable o la constante como Char .
2. Escriba el valor de carácter entre comillas ( " " ).
3. Siga las comillas dobles de cierre con el carácter de tipo literal C para forzar el literal a Char . Esto es necesario si el modificador de comprobación de tipo (Option Strict Statement) es On , y es deseable en cualquier caso.

En el ejemplo siguiente se muestran las asignaciones correctas y erróneas de un literal a una 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")

Siempre hay un riesgo en el uso de conversiones de restricción, ya que pueden producir errores en tiempo de ejecución. Por ejemplo, una conversión de String a Char puede producir un error si el String valor contiene más de un carácter. Por lo tanto, es mejor programar el uso del C carácter de tipo.

Error de conversión de cadena en tiempo de ejecución

El tipo de datos de cadena participa en muy pocas conversiones de ampliación. String solo se amplía a sí mismo y Object , y solo Char y Char() (una Char matriz) se amplía a String . Esto se debe String a que las variables y constantes pueden contener valores que otros tipos de datos no pueden contener.

Cuando el modificador de comprobación de tipo (Option Strict Statement) es On , el compilador no permite todas las conversiones de restricción implícitas. Esto incluye los que implican String . El código todavía puede usar palabras clave de conversión como CStr y la función ctype, que dirigen el .NET Framework para intentar la conversión.

Nota

Se suprime el error de conversión de restricción para las conversiones de los elementos de una For Each…Next colección a la variable de control de bucle. Para obtener más información y ejemplos, vea la sección acerca de las conversiones de restricción en for each... Instrucción siguiente.

Protección de conversión de restricción

El inconveniente de las conversiones de restricción es que pueden producir errores en tiempo de ejecución. Por ejemplo, si una String variable contiene un valor distinto de "true" o "false", no se puede convertir en Boolean . Si contiene caracteres de puntuación, se produce un error en la conversión a cualquier tipo numérico. A menos que sepa que la String variable siempre contiene valores que el tipo de destino puede aceptar, no debe intentar realizar una conversión.

Si debe convertir de String a otro tipo de datos, el procedimiento más seguro consiste en incluir la conversión intentada en la instrucción try... Detectar... Finally. Esto le permite tratar con un error en tiempo de ejecución.

Matrices de caracteres

Una sola Char y una matriz de Char elementos se amplían a String . Sin embargo, no String se amplía a Char() . Para convertir un String valor en una Char matriz, puede utilizar el ToCharArray método de la System.String clase.

Valores sin sentido

En general, String los valores no son significativos en otros tipos de datos y la conversión es muy artificial y peligrosa. Siempre que sea posible, debe restringir String el uso de variables a las secuencias de caracteres para las que están diseñadas. Nunca debe escribir código que se base en valores equivalentes en otros tipos.

Consulte también