Nuta
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Na tej stronie wymieniono niektóre typowe problemy, które mogą wystąpić podczas wykonywania operacji na typach danych wewnętrznych.
wyrażenia Floating-Point nie są porównywane jako równe
Podczas pracy z liczbami zmiennoprzecinkowych (pojedynczy typ danych i podwójny typ danych) pamiętaj, że są one przechowywane jako ułamki binarne. Oznacza to, że nie mogą przechowywać dokładnej reprezentacji jakiejkolwiek ilości, która nie jest ułamkiem binarnym (w postaci k / (2 ^ n), gdzie k i n są liczbami całkowitymi. Na przykład wartości 0,5 (= 1/2) i 0,3125 (= 5/16) mogą być przechowywane jako dokładne wartości, natomiast wartości 0,2 (= 1/5) i 0,3 (= 3/10) mogą być tylko przybliżeniami.
Ze względu na tę niemożliwość nie można polegać na dokładnych wynikach podczas wykonywania operacji na wartościach zmiennoprzecinkowych. W szczególności dwie wartości, które są teoretycznie równe, mogą mieć nieco inne reprezentacje.
| Aby porównać ilości zmiennoprzecinkowe |
|---|
| 1. Oblicz bezwzględną wartość ich różnicy przy użyciu Abs metody Math klasy w System przestrzeni nazw. 2. Określ akceptowalną maksymalną różnicę, tak aby można było rozważyć, że dwie ilości są równe w praktycznych celach, jeśli ich różnica nie jest większa. 3. Porównaj wartość bezwzględną różnicy z akceptowalną różnicą. |
W poniższym przykładzie pokazano zarówno niepoprawne, jak i poprawne porównanie dwóch Double wartości.
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))
W poprzednim przykładzie użyto ToString metody Double struktury, aby można było określić lepszą precyzję niż CStr używane przez słowo kluczowe. Wartość domyślna to 15 cyfr, ale format "G17" rozszerza go na 17 cyfr.
Operator mod nie zwraca dokładnego wyniku
Ze względu na niemożliwość przechowywania zmiennoprzecinkowego operator moda może zwrócić nieoczekiwany wynik, gdy co najmniej jeden z operandów jest zmiennoprzecinkowy.
Typ danych dziesiętnych nie używa reprezentacji zmiennoprzecinkowej. Wiele liczb, które są niedokładne i SingleDouble są dokładne Decimal (na przykład 0.2 i 0.3). Chociaż arytmetyka jest wolniejsza Decimal niż w zmiennoprzecinku, warto zmniejszyć wydajność, aby osiągnąć lepszą precyzję.
| Aby znaleźć pozostałą liczbę całkowitą ilości zmiennoprzecinkowych |
|---|
1. Zadeklaruj zmienne jako Decimal.2. Użyj znaku D typu literału, aby wymusić literały na Decimal, jeśli ich wartości są zbyt duże dla Long typu danych. |
W poniższym przykładzie pokazano potencjalną nieprawdopodobną liczbę operandów zmiennoprzecinkowych.
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))
W poprzednim przykładzie użyto ToString metody Double struktury, aby można było określić lepszą precyzję niż CStr używane przez słowo kluczowe. Wartość domyślna to 15 cyfr, ale format "G17" rozszerza go na 17 cyfr.
Ponieważ zeroPointTwo jest Doubleto , jego wartość dla 0,2 jest nieskończenie powtarzanym ułamkiem binarnym z przechowywaną wartością 0,200000000000001. Dzielenie 2,0 przez tę ilość daje 9,9999999999999999995 z resztą 0,199999999999999999999999991.
W wyrażeniu dla decimalRemainder, znak D typu literału wymusza zarówno operandy na Decimal, jak i 0,2 ma dokładną reprezentację. W związku z Mod tym operator daje oczekiwaną resztę 0,0.
Należy pamiętać, że nie wystarczy zadeklarować decimalRemainder jako Decimal. Należy również wymusić użycie literałów na Decimal, lub domyślnie używać DoubledecimalRemainder tych samych niedokładnych wartości co doubleRemainder.
Typ logiczny nie konwertuje na typ liczbowy dokładnie
Wartości typu danych logicznych nie są przechowywane jako liczby, a przechowywane wartości nie mają być równoważne liczbom. Aby zapewnić zgodność z wcześniejszymi wersjami, język Visual Basic udostępnia słowa kluczowe konwersji (operator CType, CBool, CIntitd.) w celu konwersji między typami Boolean liczbowymi i . Jednak inne języki czasami wykonują te konwersje inaczej, podobnie jak metody programu .NET Framework.
Nigdy nie należy pisać kodu, który opiera się na równoważnych wartościach liczbowych dla True i False. Jeśli to możliwe, należy ograniczyć użycie Boolean zmiennych do wartości logicznych, dla których są one zaprojektowane. Jeśli musisz mieszać Boolean i wartości liczbowe, upewnij się, że rozumiesz wybraną metodę konwersji.
Konwersja w Visual Basic
Gdy używasz CType słów kluczowych lub CBool konwersji do konwertowania typów danych liczbowych na Booleanwartość , wartość 0 staje się False i wszystkie inne wartości stają się .True Gdy konwertujesz Boolean wartości na typy liczbowe przy użyciu słów kluczowych konwersji, False staje się 0 i True staje się -1.
Konwersja w strukturze
ToInt32 Metoda Convert klasy w System przestrzeni nazw konwertuje True na +1.
Jeśli musisz przekonwertować Boolean wartość na typ danych liczbowych, należy zachować ostrożność przy użyciu metody konwersji.
Literał znaku generuje błąd kompilatora
W przypadku braku znaków dowolnego typu język Visual Basic zakłada domyślne typy danych literałów. Domyślny typ literału znaku — ujętego w cudzysłów (" ") — to String.
Typ String danych nie jest rozszerzany na typ danych char. Oznacza to, że jeśli chcesz przypisać literał do Char zmiennej, musisz wykonać konwersję zawężającą lub wymusić literał na Char typ.
| Aby utworzyć literał char do przypisania do zmiennej lub stałej |
|---|
1. Zadeklaruj zmienną lub stałą jako Char.2. Ujmij wartość znaku w cudzysłowie ( " ").3. Postępuj zgodnie z zamykającym podwójnym cudzysłowem z znakiem C typu literału, aby wymusić literał na Char. Jest to konieczne, jeśli przełącznik sprawdzania typów (Instrukcja ścisłej opcji) jest On, i jest pożądane w każdym przypadku. |
W poniższym przykładzie pokazano zarówno nieudane, jak i pomyślne przypisania literału do zmiennej Char .
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")
Zawsze istnieje ryzyko użycia konwersji zawężających, ponieważ mogą one zakończyć się niepowodzeniem w czasie wykonywania. Na przykład konwersja z String na Char może zakończyć się niepowodzeniem, jeśli String wartość zawiera więcej niż jeden znak. W związku z tym lepszym programowaniem C jest użycie znaku typu.
Konwersja ciągu kończy się niepowodzeniem w czasie wykonywania
Typ danych ciągu uczestniczy w bardzo niewielu konwersji rozszerzających.
String rozszerza się tylko do siebie i Object, i tylko Char i Char() (tablica Char ) rozszerza się do String. Dzieje się tak, ponieważ String zmienne i stałe mogą zawierać wartości, których nie mogą zawierać inne typy danych.
Gdy przełącznik sprawdzania typów (instrukcja Strict Option) to On, kompilator nie zezwala na wszystkie niejawne konwersje zawężania. Dotyczy to również tych, które obejmują Stringelement . Kod nadal może używać słów kluczowych konwersji, takich jak CStr i CType, które umożliwiają programowi .NET Framework podjęcie próby konwersji.
Uwaga / Notatka
Błąd konwersji zawężającej jest pomijany dla konwersji z elementów w For Each…Next kolekcji do zmiennej sterującej pętli. Aby uzyskać więcej informacji i przykładów, zobacz sekcję "Zawężanie konwersji" w temacie Dla każdego... Następna instrukcja.
Zawężanie ochrony konwersji
Wadą zawężania konwersji jest to, że mogą one zakończyć się niepowodzeniem w czasie wykonywania. Jeśli na przykład zmienna String zawiera coś innego niż "Prawda" lub "Fałsz", nie można przekonwertować na Booleanwartość . Jeśli zawiera znaki interpunkcyjne, konwersja na dowolny typ liczbowy kończy się niepowodzeniem. Jeśli nie wiesz, że String zmienna zawsze przechowuje wartości, które typ docelowy może zaakceptować, nie należy próbować konwersji.
Jeśli musisz przekonwertować plik z String na inny typ danych, najbezpieczniejszą procedurą jest dołączenie próby konwersji w try... Łapać... Finally, instrukcja. Umożliwia to radzenie sobie z błędem czasu wykonywania.
Tablice znaków
Pojedyncza Char i tablica Char elementów poszerzą do String.
String Jednak nie rozszerza się na Char(). Aby przekonwertować String wartość na tablicę Char , możesz użyć ToCharArray metody System.String klasy .
Wartości bez znaczenia
Ogólnie rzecz biorąc, String wartości nie są istotne w innych typach danych, a konwersja jest wysoce sztuczna i niebezpieczna. Jeśli to możliwe, należy ograniczyć użycie String zmiennych do sekwencji znaków, dla których zostały zaprojektowane. Nigdy nie należy pisać kodu, który opiera się na równoważnych wartościach w innych typach.