Řešení potíží s datovými typy (Visual Basic)
Tato stránka obsahuje některé běžné problémy, ke kterým může dojít při provádění operací s vnitřními datovými typy.
Floating-Point Výrazy se nesrovnávají jako rovny
Při práci s čísly s plovoucí desetinnou čárkou (jeden datový typ a datový typ Double) mějte na paměti, že jsou uloženy jako binární zlomky. To znamená, že nemohou obsahovat přesnou reprezentaci žádného množství, které není binární zlomek (ve tvaru k / (2 ^ n), kde k a n jsou celá čísla). Například hodnoty 0,5 (= 1/2) a 0,3125 (= 5/16) lze uchovávat jako přesné hodnoty, zatímco hodnoty 0,2 (= 1/5) a 0,3 (= 3/10) mohou být pouze přibližné hodnoty.
Z důvodu této nepřesné hodnoty se při práci s hodnotami s plovoucí desetinou čárkou nemůžete spoléhat na přesné výsledky. Konkrétně dvě hodnoty, které jsou teoreticky stejné, můžou mít mírně odlišné reprezentace.
Porovnání množství s plovoucí desetinou čárkou |
---|
1. Vypočítejte absolutní hodnotu jejich rozdílu Abs pomocí metody Math třídy v System oboru názvů. 2. Určete přijatelný maximální rozdíl tak, abyste mohli obě množství považovat za rovnanou pro praktické účely, pokud jejich rozdíl není větší. 3. Porovnejte absolutní hodnotu rozdílu s přijatelným rozdílem. |
Následující příklad ukazuje nesprávné a správné porovnání dvou Double
hodnot.
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))
Předchozí příklad používá metodu ToStringDouble struktury, aby bylo možné zadat lepší přesnost, než CStr
používá klíčové slovo . Výchozí hodnota je 15 číslic, ale formát "G17" ho rozšiřuje na 17 číslic.
Operátor Mod nevrací přesný výsledek
Z důvodu nepřesné úložiště s plovoucí desetinou čárkou může operátor Mod vrátit neočekávaný výsledek, pokud je alespoň jeden operand s plovoucí desetinou čárkou.
Datový typ Decimal nepoužívá reprezentaci s plovoucí desetinnou čárkou. Mnoho čísel, která jsou nepřesná v Single
a Double
jsou přesná ( Decimal
například 0,2 a 0,3). I když je aritmetika pomalejší Decimal
než hodnota s plovoucí desetinnou čárkou, může být snížení výkonu pro dosažení lepší přesnosti vhodné.
Vyhledání celočíselného zbytku množství s plovoucí desetinou čárkou |
---|
1. Deklarujte proměnné jako Decimal .2. Použijte znak D literálového typu k vynucení literálů pro Decimal , pokud jsou jejich hodnoty pro Long datový typ příliš velké. |
Následující příklad ukazuje potenciální nepřesné operandy s plovoucí desetinou čárkou.
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))
Předchozí příklad používá metodu ToStringDouble struktury, aby bylo možné zadat lepší přesnost, než CStr
používá klíčové slovo . Výchozí hodnota je 15 číslic, ale formát "G17" ho rozšiřuje na 17 číslic.
Protože zeroPointTwo
je Double
, jeho hodnota pro 0,2 je nekonečně se opakující binární zlomek s uloženou hodnotou 0,200000000000001. Vydělením čísla 2,0 tímto množstvím získáme 9,9999999999999999 se zbytkem 0,199999999999999991.
Ve výrazu pro decimalRemainder
vynucuje znak D
literálového typu oba operandy na Decimal
a 0.2 má přesné znázornění. Mod
Operátor proto získá očekávaný zbytek hodnoty 0,0.
Všimněte si, že nestačí deklarovat decimalRemainder
jako Decimal
. Literály je také nutné vynutit, jinak Decimal
použijí Double
ve výchozím nastavení a decimalRemainder
obdrží stejnou nepřesnou hodnotu jako doubleRemainder
.
Logický typ se nepřevádí na číselný typ přesně
Logické hodnoty datového typu se neukládají jako čísla a uložené hodnoty nemají být ekvivalentní číslům. Z důvodu kompatibility s dřívějšími verzemi jazyka Visual Basic poskytuje klíčová slova převodu (funkce CType, CBool
, CInt
atd.) pro převod mezi Boolean
a číselnými typy. Jiné jazyky však někdy provádějí tyto převody odlišně, stejně jako metody rozhraní .NET Framework.
Nikdy byste neměli psát kód, který se spoléhá na ekvivalentní číselné hodnoty pro True
a False
. Kdykoli je to možné, měli byste použití proměnných Boolean
omezit na logické hodnoty, pro které jsou navrženy. Pokud potřebujete kombinovat Boolean
číselné hodnoty a , ujistěte se, že vybrané metodě převodu rozumíte.
Převod v jazyce Visual Basic
Když k převodu CType
CBool
číselných datových typů Boolean
použijete nebo , stane se False
hodnota 0 a všechny ostatní hodnoty na True
. Když převedete Boolean
hodnoty na číselné typy pomocí klíčových slov převodu, False
stane se hodnota 0 a True
-1.
Převod v architektuře
Metoda ToInt32Convert třídy v System oboru názvů se převede True
na +1.
Pokud potřebujete převést Boolean
hodnotu na číselný datový typ, dávejte pozor na to, jakou metodu převodu použijete.
Chyba kompilátoru generuje znakový literál
Při absenci znaků typu předpokládá Visual Basic výchozí datové typy pro literály. Výchozí typ znakového literálu – uzavřený do uvozovek (" "
) – je String
.
Datový String
typ se nerozšíře na datový typ Char. To znamená, že pokud chcete k proměnné přiřadit literál Char
, musíte buď provést zužující převod, nebo vynutit literál na Char
typ.
Vytvoření literálu Char pro přiřazení proměnné nebo konstantě |
---|
1. Deklarujte proměnnou nebo konstantu jako Char .2. Hodnotu znaku uzavřete do uvozovek ( " " ).3. Použijte uzavírací uvozovky se znakem C typu literálu, aby se literál vynutil na Char . To je nezbytné, pokud je přepínač kontroly typu (Option Strict Statement) On a v každém případě je to žádoucí. |
Následující příklad ukazuje neúspěšné i úspěšné přiřazení literálu Char
k proměnné.
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")
Použití zužující převody vždy představuje riziko, protože za běhu můžou selhat. Například převod z String
na může selhat Char
, pokud String
hodnota obsahuje více než jeden znak. Proto je lepší programovat použití znaku C
typu.
Převod řetězce selže za běhu
Datový typ String se účastní velmi málo rozšiřujících převodů. String
rozšiřuje pouze na sebe a a Object
pouze Char
a Char()
( Char
pole) rozšiřuje na String
. Je to proto, že String
proměnné a konstanty mohou obsahovat hodnoty, které jiné datové typy nemohou obsahovat.
Pokud je On
přepínač kontroly typu (Option Strict Statement) , kompilátor zakáže všechny implicitní zužující převody. To zahrnuje i ty, které zahrnují String
. Váš kód může stále používat klíčová slova převodu, jako CStr
je a funkce CType, která nasměrují rozhraní .NET Framework k pokusu o převod.
Poznámka
Chyba zužujícího převodu je potlačena pro převody z prvků v For Each…Next
kolekci na řídicí proměnnou smyčky. Další informace a příklady najdete v části "Zužující převody" v tématu For Each... Next – příkaz.
Zužující ochrana převodu
Nevýhodou zúžení převodů je to, že za běhu můžou selhat. Pokud například proměnná String
obsahuje cokoli jiného než "Pravda" nebo "Nepravda", nelze ji převést na Boolean
. Pokud obsahuje interpunkční znaméne, převod na libovolný číselný typ se nezdaří. Pokud nevíte, že proměnná String
vždy obsahuje hodnoty, které cílový typ může přijmout, neměli byste zkusit převod.
Pokud potřebujete převést z na String
jiný datový typ, nejbezpečnějším postupem je uzavřít pokus o převod do pole Zkuste... Chytit... Příkaz Finally. To vám umožní řešit selhání za běhu.
Pole znaků
Jeden Char
prvek a pole Char
prvků se rozšiřují na String
. Nevztahuje se String
však na Char()
. Chcete-li převést String
hodnotu na Char
pole, můžete použít metodu ToCharArraySystem.String třídy .
Bezvýznamné hodnoty
Obecně platí, že String
hodnoty v jiných datových typech nejsou smysluplné a převod je vysoce umělý a nebezpečný. Kdykoli je to možné, měli byste použití proměnných String
omezit na sekvence znaků, pro které jsou navrženy. Nikdy byste neměli psát kód, který spoléhá na ekvivalentní hodnoty v jiných typech.