Compartir a través de


Solución de 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

Cuando trabaje con números de punto flotante (tipo de datos único y tipo de datos doble), recuerde que se almacenan como fracciones binarias. Esto significa que no pueden contener una representación exacta de ninguna 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 mantener como valores precisos, mientras que 0,2 (= 1/5) y 0,3 (= 3/10) solo pueden ser aproximaciones.

Debido a esta imprecisión, no puede confiar en resultados exactos cuando opera en valores de punto flotante. En concreto, dos valores que teóricamente son iguales podrían tener representaciones ligeramente diferentes.

Para comparar cantidades de punto flotante
1. Calcule el valor absoluto de su diferencia utilizando el Abs método de la Math clase en el System espacio de nombres.
2. Determine una diferencia máxima aceptable, de modo que pueda considerar que las dos cantidades son iguales para fines 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 una 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 una mayor precisión que la CStr palabra clave . El valor predeterminado es de 15 dígitos, pero el formato "G17" lo extiende a 17 dígitos.

El operador Mod no devuelve el 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 usa la representación de punto flotante. Muchos números que están inexactos en Single y Double son exactos en Decimal (por ejemplo, 0.2 y 0.3). Aunque la aritmética es más lenta en Decimal que en el punto flotante, puede que valga la pena la disminución del rendimiento para lograr una mayor precisión.

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

En el ejemplo siguiente se muestra la posible 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 una mayor precisión que la CStr palabra clave . El valor predeterminado es de 15 dígitos, pero el formato "G17" lo extiende a 17 dígitos.

Dado zeroPointTwo que es Double, su valor para 0,2 es una fracción binaria repetida infinitamente con un valor almacenado de 0,200000000000000001. Dividir 2,0 por esta cantidad produce 9,99999999999999999995 con un resto de 0,199999999999999999999991.

En la expresión para decimalRemainder, el carácter D de tipo literal fuerza ambos operandos a Decimaly 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 a Decimalo usan Double de forma predeterminada y decimalRemainder recibe el mismo valor inexacto que doubleRemainder.

El tipo booleano no se convierte al 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 los números. Para la compatibilidad con versiones anteriores, Visual Basic proporciona palabras clave de conversión (Operador de CType, CBool, CInt, etc.) para convertir entre Boolean tipos numéricos y . Sin embargo, otros lenguajes a veces realizan estas conversiones de forma diferente, como hacen 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 el uso de Boolean variables a los valores lógicos para los que están diseñados. Si debe combinar Boolean y valores numéricos, asegúrese de comprender el método de conversión que seleccione.

Conversión en Visual Basic

Cuando se usan las CType palabras clave de conversión o CBool para convertir tipos de datos numéricos en Boolean, 0 se convierten False en y todos los demás valores se convierten en True. Al convertir 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

El ToInt32 método de la Convert clase del System espacio de nombres se convierte True 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 use.

Literal de caracteres genera el error del compilador

En ausencia de cualquier carácter de tipo, Visual Basic asume los tipos de datos predeterminados para los literales. El tipo predeterminado para un literal de caracteres ,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 asignar a una variable o constante
1. Declare la variable o constante como Char.
2. Incluya el valor de carácter entre comillas (" ").
3. Siga la comilla doble de cierre con el carácter C de tipo literal para forzar el literal a Char. Esto es necesario si el modificador de comprobación de tipos (Option Strict Statement) es Ony es deseable en cualquier caso.

En el ejemplo siguiente se muestran asignaciones incorrectas y correctas 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 a StringChar puede producir un error si el String valor contiene más de un carácter. Por lo tanto, es mejor programar para usar el carácter de C tipo.

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

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

Cuando el modificador de comprobación de tipos (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 operador CType, que dirigen a .NET Framework para intentar la conversión.

Nota:

El error de conversión de restricción se suprime 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 "Conversiones de restricción" en For Each... Siguiente instrucción.

Protección de conversión de restricción

La desventaja de restringir conversiones es que pueden producir errores en tiempo de ejecución. Por ejemplo, si una String variable contiene algo 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 probar 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 try... Atrapar... Finally (Instrucción). Esto le permite tratar un error en tiempo de ejecución.

Matrices de caracteres

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

Valores sin significado

En general, String los valores no son significativos en otros tipos de datos y la conversión es altamente artificial y peligrosa. Siempre que sea posible, debe restringir el uso de variables a las secuencias de String 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