Resolução de Problemas de Tipos de Dados (Visual Basic)
Esta página lista alguns problemas comuns que podem ocorrer quando realiza operações em tipos de dados intrínsecos.
Floating-Point Expressões Não Comparam como Iguais
Quando trabalhar com números de vírgula flutuante (Tipo de Dados Único e Tipo de Dados Duplo), lembre-se de que são armazenados como frações binárias. Isto significa que não podem conter uma representação exata de qualquer quantidade que não seja uma fração binária (do formulário k / (2 ^ n) em que k e n são números inteiros). Por exemplo, 0,5 (= 1/2) e 0,3125 (= 5/16) podem ser mantidos como valores precisos, enquanto 0,2 (= 1/5) e 0,3 (= 3/10) só podem ser aproximações.
Devido a esta imprecisão, não pode depender de resultados exatos quando opera em valores de vírgula flutuante. Em particular, dois valores teoricamente iguais podem ter representações ligeiramente diferentes.
Para comparar as quantidades de vírgula flutuante |
---|
1. Calcule o valor absoluto da diferença ao utilizar o Abs método da Math classe no System espaço de nomes. 2. Determine uma diferença máxima aceitável, de modo a considerar que as duas quantidades são iguais para fins práticos se a diferença não for maior. 3. Compare o valor absoluto da diferença com a diferença aceitável. |
O exemplo seguinte demonstra uma comparação incorreta e correta de dois 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))
O exemplo anterior utiliza o ToString método da Double estrutura para que possa especificar uma maior precisão do que a CStr
palavra-chave utiliza. A predefinição é de 15 dígitos, mas o formato "G17" expande-o para 17 dígitos.
O Operador Mod não devolve o resultado exato
Devido à imprecisão do armazenamento de vírgula flutuante, o Operador Mod pode devolver um resultado inesperado quando pelo menos um dos operandos é flutuante.
O Tipo de Dados Decimais não utiliza representação de vírgula flutuante. Muitos números que são inexatos Single
e Double
estão exatos em Decimal
(por exemplo, 0,2 e 0,3). Embora a aritmética seja mais lenta do que em Decimal
vírgula flutuante, pode valer a pena a diminuição do desempenho para obter uma maior precisão.
Para encontrar o resto inteiro das quantidades de vírgula flutuante |
---|
1. Declarar variáveis como Decimal .2. Utilize o caráter D literal para forçar literais a Decimal , caso os respetivos valores sejam demasiado grandes para o Long tipo de dados. |
O exemplo seguinte demonstra a potencial imprecisão dos operandos de vírgula flutuante.
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))
O exemplo anterior utiliza o ToString método da Double estrutura para que possa especificar uma maior precisão do que a CStr
palavra-chave utiliza. A predefinição é de 15 dígitos, mas o formato "G17" expande-o para 17 dígitos.
Como zeroPointTwo
é Double
, o seu valor para 0,2 é uma fração binária de repetição infinita com um valor armazenado de 0,20000000000000000001. A divisão de 2,0 por esta quantidade gera 9,9999999999999999995 com um resto de 0,1999999999999991.
Na expressão para decimalRemainder
, o caráter D
literal força ambos os operandos a Decimal
e 0,2 tem uma representação precisa. Por conseguinte, o Mod
operador produz o restante esperado de 0,0.
Tenha em atenção que não é suficiente declarar decimalRemainder
como Decimal
. Também tem de forçar os literais a Decimal
, ou estes utilizam Double
por predefinição e decimalRemainder
recebe o mesmo valor impreciso que doubleRemainder
.
O Tipo booleano não é convertido num tipo numérico com precisão
Os valores booleanos do Tipo de Dados não são armazenados como números e os valores armazenados não se destinam a ser equivalentes a números. Para compatibilidade com versões anteriores, o Visual Basic fornece palavras-chave de conversão (Função CType, CBool
, CInt
e assim sucessivamente) para converter entre Boolean
tipos numéricos. No entanto, por vezes, outros idiomas executam estas conversões de forma diferente, assim como os métodos de .NET Framework.
Nunca deve escrever código que dependa de valores numéricos equivalentes para True
e False
. Sempre que possível, deve restringir a utilização de Boolean
variáveis aos valores lógicos para os quais foram concebidas. Se tiver de misturar Boolean
e numéricos valores, certifique-se de que compreende o método de conversão que seleciona.
Conversão no Visual Basic
Quando utiliza as CType
palavras-chave de conversão ou CBool
para converter tipos de dados numéricos False
em Boolean
, 0 torna-se e todos os outros valores tornam-se True
. Quando converte Boolean
valores em tipos numéricos com as palavras-chave de conversão, False
torna-se 0 e True
torna-se -1.
Conversão no Framework
O ToInt32 método da Convert classe no espaço de nomes converte-se True
em System +1.
Se tiver de converter um Boolean
valor num tipo de dados numérico, tenha cuidado com o método de conversão que utiliza.
Literal de Carateres Gera Erro do Compilador
Na ausência de qualquer tipo de carateres, o Visual Basic assume tipos de dados predefinidos para literais. O tipo predefinido para um literal de carateres , entre aspas (" "
) é String
.
O String
tipo de dados não se alarga ao Tipo de Dados de Caráter. Isto significa que, se pretender atribuir um literal a uma Char
variável, tem de fazer uma conversão de estreitamento ou forçar o literal ao Char
tipo.
Para criar um literal char para atribuir a uma variável ou constante |
---|
1. Declare a variável ou constante como Char .2. Coloque o valor do caráter entre aspas ( " " ).3. Siga a aspas de fecho dupla com o caráter C de tipo literal para forçar o literal a Char . Isto é necessário se o comutador de verificação do tipo (Instrução Estrita da Opção) for On , e for desejável em qualquer caso. |
O exemplo seguinte demonstra atribuições sem êxito e bem-sucedidas de um literal a uma Char
variável.
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")
Existe sempre o risco de utilizar conversões de restrição, uma vez que podem falhar no tempo de execução. Por exemplo, uma conversão de String
para Char
pode falhar se o String
valor contiver mais de um caráter. Por conseguinte, é melhor programar utilizar o caráter de C
tipo.
A Conversão de Cadeias falha no Tempo de Execução
O Tipo de Dados de Cadeia participa em muito poucas conversões de alargamento. String
alarga-se apenas a si próprio e Object
, e apenas Char
e Char()
(uma Char
matriz) alargam-se para String
. Isto deve-se ao facto String
de as variáveis e as constantes poderem conter valores que outros tipos de dados não podem conter.
Quando o comutador de verificação do tipo (Instrução Estrita da Opção) for On
, o compilador não permite todas as conversões de restrição implícitas. Isto inclui os que envolvem String
. O código ainda pode utilizar palavras-chave de conversão, como CStr
a Função CType, que direciona o .NET Framework para tentar a conversão.
Nota
O erro de conversão de restrição é suprimido para conversões dos elementos numa For Each…Next
coleção para a variável de controlo de ciclo. Para obter mais informações e exemplos, veja a secção "Conversões de Restrição" em Para Cada... Instrução Seguinte.
Restringir a Proteção de Conversão
A desvantagem de restringir as conversões é que podem falhar no tempo de execução. Por exemplo, se uma String
variável contiver algo diferente de "Verdadeiro" ou "Falso", não pode ser convertida em Boolean
. Se contiver carateres de pontuação, a conversão para qualquer tipo numérico falhará. A menos que saiba que a variável String
contém sempre valores que o tipo de destino pode aceitar, não deve tentar uma conversão.
Se tiver de converter para outro tipo de String
dados, o procedimento mais seguro é incluir a conversão tentada na Tentativa... Apanhar... Por fim, Instrução. Isto permite-lhe lidar com uma falha de tempo de execução.
Matrizes de Carateres
Uma única Char
e uma matriz de Char
elementos alargam-se para String
. No entanto, String
não alarga para Char()
. Para converter um String
valor numa Char
matriz, pode utilizar o ToCharArray método da System.String classe.
Valores Sem Sentido
Em geral, String
os valores não são significativos noutros tipos de dados e a conversão é altamente artificial e perigosa. Sempre que possível, deve restringir a utilização de String
variáveis às sequências de carateres para as quais foram concebidas. Nunca deve escrever código que dependa de valores equivalentes noutros tipos.