Nota
O acesso a esta página requer autorização. Pode tentar iniciar sessão ou alterar os diretórios.
O acesso a esta página requer autorização. Pode tentar alterar os diretórios.
Esta página lista alguns problemas comuns que podem ocorrer quando você executa operações em tipos de dados intrínsecos.
Floating-Point expressões não se comparam como iguais
Ao trabalhar com números de vírgula flutuante (Tipo de Dados Único e Tipo de Dados Duplo), lembre-se de que eles são armazenados como frações binárias. Isso significa que eles não podem manter uma representação exata de qualquer quantidade que não seja uma fração binária (da forma k / (2 ^ n) onde k e n são 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) podem ser apenas aproximações.
Devido a essa imprecisão, você não pode confiar em resultados exatos quando opera com valores de vírgula flutuante. Em particular, dois valores que são teoricamente iguais podem ter representações ligeiramente diferentes.
| Para comparar quantidades de vírgula flutuante |
|---|
| 1. Calcule o valor absoluto de sua diferença usando o Abs método da Math classe no System namespace. 2. Determine uma diferença máxima aceitável, de modo que você possa considerar as duas quantidades iguais para fins práticos se sua diferença não for maior. 3. Comparar o valor absoluto da diferença com a diferença aceitável. |
O exemplo a seguir demonstra a 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 usa o ToString método da Double estrutura para que ele possa especificar uma precisão melhor do que a CStr palavra-chave usa. O padrão é 15 dígitos, mas o formato "G17" o estende para 17 dígitos.
Operador Mod não retorna resultado preciso
Devido à imprecisão do armazenamento de ponto flutuante, o operador Mod pode retornar um resultado inesperado quando pelo menos um dos operandos é de ponto flutuante.
O tipo de dados decimal não usa representação de vírgula flutuante. Muitos números que são inexatos e Single são exatos em Decimal (Doublepor exemplo, 0,2 e 0,3). Embora a aritmética seja mais lenta em Decimal termos de ponto flutuante, pode valer a pena a diminuição do desempenho para obter uma melhor precisão.
| Para encontrar o número inteiro restante de quantidades de vírgula flutuante |
|---|
1. Declare as variáveis como Decimal.2. Use o caractere D de tipo literal para forçar literais a Decimal, caso seus valores sejam muito grandes para o Long tipo de dados. |
O exemplo a seguir demonstra a imprecisão potencial de operandos de ponto 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 usa o ToString método da Double estrutura para que ele possa especificar uma precisão melhor do que a CStr palavra-chave usa. O padrão é 15 dígitos, mas o formato "G17" o estende para 17 dígitos.
Porque zeroPointTwo é Double, seu valor para 0,2 é uma fração binária infinitamente repetitiva com um valor armazenado de 0,2000000000000001. Dividindo 2,0 por esta quantidade, obtém-se 9,99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999
Na expressão para decimalRemainder, o caractere D de tipo literal força ambos os operandos para Decimal, e 0.2 tem uma representação precisa. Portanto, o Mod operador produz o restante esperado de 0,0.
Note-se que não é suficiente declarar decimalRemainder como Decimal. Você também deve forçar os literais para Decimal, ou eles usam Double por padrão e decimalRemainder recebe o mesmo valor impreciso que doubleRemainder.
Tipo booleano não converte em tipo numérico com precisão
Os valores de Tipo de Dados Booleanos 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 (CType Operator, CBool, CInte assim por diante) para converter entre Boolean e tipos numéricos. No entanto, outras linguagens às vezes executam essas conversões de forma diferente, assim como os métodos do .NET Framework.
Você nunca deve escrever código que dependa de valores numéricos equivalentes para True e False. Sempre que possível, você deve restringir o uso de Boolean variáveis aos valores lógicos para os quais elas foram projetadas. Se tiver de misturar Boolean valores numéricos, certifique-se de que compreende o método de conversão selecionado.
Conversão em Visual Basic
Quando você usa as CType palavras-chave ou CBool conversão para converter tipos de dados numéricos em Boolean, 0 torna-se e todos os outros valores tornam-se FalseTrue. Quando você converte Boolean valores em tipos numéricos usando as palavras-chave de conversão, False torna-se 0 e True torna-se -1.
Conversão no quadro
O ToInt32 método da Convert classe no namespace converte SystemTrue para +1.
Se você precisar converter um Boolean valor em um tipo de dados numéricos, tenha cuidado com o método de conversão usado.
Literal de caractere gera erro de compilador
Na ausência de caracteres de tipo, o Visual Basic assume tipos de dados padrão para literais. O tipo padrão para um literal de caractere — entre aspas (" ") — é String.
O String tipo de dados não é ampliado para o tipo de dados Char. Isso significa que, se você quiser atribuir um literal a uma Char variável, deverá 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 caractere entre aspas ( " ").3. Siga as aspas duplas de fechamento com o caractere C de tipo literal para forçar o literal para Char. Isso é necessário se a opção de verificação de tipo (Option Strict Statement) for On, e é desejável em qualquer caso. |
O exemplo a seguir demonstra atribuições malsucedidas e bem-sucedidas de um literal para 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")
Há sempre um risco em usar conversões de estreitamento, porque elas podem falhar em tempo de execução. Por exemplo, uma conversão de String para Char pode falhar se o String valor contiver mais de um caractere. Portanto, é melhor programar para usar o C caractere tipo.
A conversão de cadeia de caracteres falha em tempo de execução
O tipo de dados String participa de muito poucas conversões de ampliação.
String alarga apenas para si mesmo e Object, e apenas Char e Char() (uma Char matriz) amplia para String. Isso ocorre porque String variáveis e constantes podem conter valores que outros tipos de dados não podem conter.
Quando a opção de verificação de tipo (Option Strict Statement) é On, o compilador não permite todas as conversões de estreitamento implícitas. Isto inclui os que envolvem String. Seu código ainda pode usar palavras-chave de conversão, como CStre CType Operator, que direcionam o .NET Framework para tentar a conversão.
Observação
O erro de estreitamento-conversão é suprimido para conversões dos elementos em uma For Each…Next coleção para a variável de controle de loop. Para obter mais informações e exemplos, consulte a seção "Estreitando conversões" em Para cada um... Próxima declaração.
Estreitando a proteção de conversão
A desvantagem de restringir as conversões é que elas podem falhar em tempo de execução. Por exemplo, se uma String variável contiver algo diferente de "True" ou "False", ela não poderá ser convertida em Boolean. Se contiver caracteres de pontuação, a conversão para qualquer tipo numérico falhará. A menos que você saiba que sua String variável sempre contém valores que o tipo de destino pode aceitar, você não deve tentar uma conversão.
Se você precisar converter de para outro tipo de dados, o procedimento mais seguro é incluir a tentativa de String conversão no Try... Pegar... Finalmente Declaração. Isso permite que você lide com uma falha em tempo de execução.
Matrizes de caracteres
Um único Char e um conjunto de Char elementos se ampliam para String. No entanto, String não se alarga a Char(). Para converter um String valor em uma Char matriz, você pode usar o ToCharArraySystem.String método da classe.
Valores sem sentido
Em geral, String os valores não são significativos em outros tipos de dados e a conversão é altamente artificial e perigosa. Sempre que possível, você deve restringir o uso de variáveis às sequências de String caracteres para as quais elas foram projetadas. Você nunca deve escrever código que dependa de valores equivalentes em outros tipos.