Problemen met gegevenstypen oplossen (Visual Basic)
Deze pagina bevat enkele veelvoorkomende problemen die kunnen optreden wanneer u bewerkingen uitvoert op intrinsieke gegevenstypen.
Floating-Point-expressies worden niet vergeleken als gelijk
Wanneer u met getallen met drijvende komma werkt (enkel gegevenstype en dubbel gegevenstype), moet u er rekening mee houden dat deze als binaire breuken worden opgeslagen. Dit betekent dat ze geen exacte weergave kunnen bevatten van een hoeveelheid die geen binaire breuk is (van de vorm k / (2 ^ n), waarbij k en n gehele getallen zijn. 0,5 (= 1/2) en 0,3125 (= 5/16) kunnen bijvoorbeeld worden beschouwd als nauwkeurige waarden, terwijl 0,2 (= 1/5) en 0,3 (= 3/10) alleen benaderingen kunnen zijn.
Vanwege deze onnauwkeurigheid kunt u niet vertrouwen op exacte resultaten wanneer u met drijvendekommawaarden werkt. Met name twee waarden die theoretisch gelijk zijn, kunnen enigszins verschillende representaties hebben.
Drijvendekommahoeveelheden vergelijken |
---|
1. Bereken de absolute waarde van het verschil met behulp van de Abs methode van de Math klasse in de System naamruimte. 2. Bepaal een acceptabel maximumverschil, zodat u de twee hoeveelheden voor praktische doeleinden als gelijk kunt beschouwen als het verschil niet groter is. 3. Vergelijk de absolute waarde van het verschil met het acceptabele verschil. |
In het volgende voorbeeld ziet u een onjuiste en juiste vergelijking van twee Double
waarden.
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))
In het vorige voorbeeld wordt de ToString methode van de Double structuur gebruikt, zodat deze een betere precisie kan opgeven dan het CStr
trefwoord gebruikt. De standaardwaarde is 15 cijfers, maar de indeling 'G17' breidt deze uit tot 17 cijfers.
Mod-operator retourneert geen nauwkeurig resultaat
Vanwege de onnauwkeurigheid van drijvende-kommaopslag kan de operator Mod een onverwacht resultaat retourneren wanneer ten minste één van de operanden een drijvende komma is.
Het decimale gegevenstype maakt geen gebruik van drijvende-kommaweergave. Veel getallen die inexact Single
zijn en Double
exact zijn in Decimal
(bijvoorbeeld 0,2 en 0,3). Hoewel rekenkundig langzamer Decimal
is dan in drijvende komma, kan het de moeite waard zijn om de prestaties te verlagen om een betere precisie te bereiken.
Het gehele restgetal van drijvendekommagetalhoeveelheden zoeken |
---|
1. Declareer variabelen als Decimal .2. Gebruik het letterlijke typeteken D om letterlijke waarden af te dwingen naar Decimal , voor het geval de waarden te groot zijn voor het Long gegevenstype. |
In het volgende voorbeeld ziet u de mogelijke onnauwkeurigheid van operanden met drijvende komma.
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))
In het vorige voorbeeld wordt de ToString methode van de Double structuur gebruikt, zodat deze een betere precisie kan opgeven dan het CStr
trefwoord gebruikt. De standaardwaarde is 15 cijfers, maar de indeling 'G17' breidt deze uit tot 17 cijfers.
Omdat zeroPointTwo
is Double
, is de waarde voor 0,2 een oneindig herhalende binaire breuk met een opgeslagen waarde van 0,2000000000000000001. Het delen van 2,0 door deze hoeveelheid levert 9,9999999999999995 op met een rest van 0,19999999999999991.
In de expressie voor decimalRemainder
dwingt het letterlijke type teken D
beide operanden tot Decimal
, en 0,2 heeft een nauwkeurige representatie. Daarom levert de Mod
operator het verwachte restant van 0,0 op.
Houd er rekening mee dat het niet voldoende is om te declareren decimalRemainder
als Decimal
. U moet ook de letterlijke waarden afdwingen naar Decimal
, of ze gebruiken Double
standaard en decimalRemainder
ontvangen dezelfde onnauwkeurige waarde als doubleRemainder
.
Booleaans type converteert niet nauwkeurig naar numeriek type
Booleaanse gegevenstypewaarden worden niet opgeslagen als getallen en de opgeslagen waarden zijn niet bedoeld om gelijk te zijn aan getallen. Voor compatibiliteit met eerdere versies biedt Visual Basic conversietrefwoorden (CType-functie, CBool
, CInt
enzovoort) om te converteren tussen Boolean
en numerieke typen. In andere talen worden deze conversies soms echter anders uitgevoerd, net als de .NET Framework-methoden.
Schrijf nooit code die afhankelijk is van equivalente numerieke waarden voor True
en False
. Indien mogelijk moet u het gebruik van Boolean
variabelen beperken tot de logische waarden waarvoor ze zijn ontworpen. Als u numerieke waarden moet combineren Boolean
, moet u ervoor zorgen dat u de conversiemethode begrijpt die u selecteert.
Conversie in Visual Basic
Wanneer u de CType
conversietrefwoorden of CBool
gebruikt om numerieke gegevenstypen te converteren naar Boolean
, wordt False
0 en worden alle andere waarden True
. Wanneer u waarden converteert Boolean
naar numerieke typen met behulp van de conversietrefwoorden, False
wordt 0 en True
-1.
Conversie in het framework
De ToInt32 methode van de Convert klasse in de System naamruimte wordt geconverteerd True
naar +1.
Als u een Boolean
waarde moet converteren naar een numeriek gegevenstype, moet u voorzichtig zijn met de conversiemethode die u gebruikt.
Character Literal genereert compilerfout
Als er geen type tekens zijn, wordt in Visual Basic uitgegaan van standaardgegevenstypen voor letterlijke waarden. Het standaardtype voor een letterlijk teken, tussen aanhalingstekens (" "
) , is String
.
Het String
gegevenstype wordt niet uitgebreid naar het gegevenstype Char. Dit betekent dat als u een letterlijke waarde wilt toewijzen aan een Char
variabele, u een vernauwde conversie moet maken of de letterlijke waarde voor het Char
type moet afdwingen.
Een letterlijk teken maken om toe te wijzen aan een variabele of constante |
---|
1. Declareer de variabele of constante als Char .2. Plaats de tekenwaarde tussen aanhalingstekens ( " " ).3. Volg het afsluitende dubbele aanhalingsteken met het letterlijke typeteken C om de letterlijke te forceren naar Char . Dit is nodig als de schakeloptie voor typecontrole (Option Strict Statement) is On en in elk geval wenselijk is. |
In het volgende voorbeeld ziet u zowel mislukte als geslaagde toewijzingen van een letterlijke aan een Char
variabele.
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")
Er is altijd een risico bij het gebruik van narrowing conversies, omdat deze tijdens runtime kunnen mislukken. Een conversie van String
naar Char
kan bijvoorbeeld mislukken als de String
waarde meer dan één teken bevat. Daarom is het beter om te programmeren om het C
typeteken te gebruiken.
Conversie van tekenreeks mislukt tijdens runtime
Het gegevenstype Tekenreeks neemt deel aan zeer weinig verbredingsconversies. String
wordt alleen uitgebreid naar zichzelf en Object
, en alleen Char
en Char()
(een Char
matrix) breder naar String
. Dit komt doordat String
variabelen en constanten waarden kunnen bevatten die andere gegevenstypen niet kunnen bevatten.
Wanneer de schakeloptie voor typecontrole (Optie Strikte instructie) is On
, staat de compiler alle impliciete narrowing-conversies niet toe. Dit geldt ook voor die met String
. Uw code kan nog steeds conversietrefwoorden gebruiken, zoals CStr
en CType Function, waarmee de .NET Framework de conversie probeert uit te voeren.
Notitie
De narrowing-conversiefout wordt onderdrukt voor conversies van de elementen in een For Each…Next
verzameling naar de lusbesturingsvariabele. Zie de sectie Narrowing Conversions in For Each voor meer informatie en voorbeelden ... Volgende instructie.
Narrowing Conversion Protection
Het nadeel van het beperken van conversies is dat ze tijdens runtime kunnen mislukken. Als een String
variabele bijvoorbeeld iets anders bevat dan 'Waar' of 'Onwaar', kan deze niet worden geconverteerd naar Boolean
. Als deze interpunctietekens bevat, mislukt de conversie naar een willekeurig numeriek type. Tenzij u weet dat uw String
variabele altijd waarden bevat die het doeltype kan accepteren, moet u geen conversie proberen.
Als u moet converteren van String
naar een ander gegevenstype, is de veiligste procedure om de poging tot conversie in te sluiten in de Probeer... Vangen... Laatste verklaring. Hiermee kunt u een runtimefout afhandelen.
Tekenmatrices
Eén Char
en een matrix met Char
elementen worden beide breder tot String
. Wordt echter String
niet breder naar Char()
. Als u een String
waarde wilt converteren naar een Char
matrix, kunt u de ToCharArray methode van de System.String klasse gebruiken.
Betekenisloze waarden
Over het algemeen String
zijn waarden niet zinvol in andere gegevenstypen en is conversie zeer kunstmatig en gevaarlijk. Indien mogelijk moet u het gebruik van String
variabelen beperken tot de tekenreeksen waarvoor ze zijn ontworpen. Schrijf nooit code die afhankelijk is van equivalente waarden in andere typen.