2013-06-26 14 views
8

Jeśli wpiszesz poniższy tekst w bezpośrednim oknie, pojawi się błąd Runtime "6": Przepełnienie.Przepełnienie po pomnożeniu liczb całkowitych i przypisaniu do wartości Long

MsgBox 24 * 60 * 60 

Dlaczego tak jest?

ta zawodzi również:

Dim giveTime As Long 
giveTime = 24 * 60 * 60 

Dlaczego tak jest? giveTime jest zadeklarowany jako typ długi, więc 24 × 60 × 60 = 86400 powinien wygodnie pasować.

+0

W związku z tym. - jeśli wstawię msgbox 26 * 60^2 w bezpośrednim oknie, nie ma problemu. Czy jest to kwestia porządku pierwszeństwa? To wydaje się mało prawdopodobne ... –

+0

Dzieje się tak dlatego, że operator '^' zwraca Double, który omija problem opisany w mojej odpowiedzi poniżej. –

Odpowiedz

22

To dziwne dziwactwo VBA. Jestem zaskoczony, że nigdy nie wpadłem na to.

Dim x As Long 
x = 24 * 60 * 60 ' Overflow 
x = 32767 + 1 ' Overflow. 
x = 32768 + 1 ' Works fine! 

Wygląda więc na to, że operatorzy * i + zwracać liczbę całkowitą w pierwszych dwóch przykładach. Rzeczywiście, w pliku pomocy dla operatora * (podobny do operatora +):

result = number1 * number2

[...]

The data type of result is usually the same as that of the most precise expression.

Twoje literałów 24, 60 i 60 są typu Integer domyślnie, więc operator * (lub +) zwraca liczbę całkowitą, która przepełnia, ponieważ wynik jest większy niż 32 767.

Jednak dosłownie 32 768 w trzecim przykładzie jest domyślnie typu Long (ponieważ jest zbyt duży, aby być liczbą całkowitą), a więc + zwraca wartość Long; brak przepełnienia.

Plik pomocy również mówi w ten sposób:

If [...] the data type of result is an Integer variant that overflows its legal range [...] Then result is [...] converted to a Long variant.

Nacisk kopalni. Teraz ta mała zasada brzmi zdroworozsądkowo i każdy mógłby rozsądnie założyć, że ma ona zastosowanie w twoim przypadku. Ale twoje liczby są typu Integer, a nie Variant/Integer, więc VBA nie stosuje tej reguły! Nie ma dla mnie absolutnie żadnego sensu, ale tak właśnie jest i tak mówi dokumentacja.

Rozwiązanie: jeden z argumentów twojego operatora * powinien być bardziej precyzyjny niż Integer (na przykład Long), a problem zniknie.

x = CLng(24) * 60 * 60 ' Result is Long, works fine. 

W rzeczywistości, a to pewnie dlatego nigdy nie wpadł na to dziwactwo, robię zwyczaj deklarowania wszystkich moich zmiennych Integer tak długo, zamiast tego, o ile istnieje szczególne obawy, że zamiast posiadające typu Long Liczby całkowite spowodują problemy z wykorzystaniem pamięci lub czasem wykonania (co prawie nigdy się nie zdarza). To prawda, że ​​nie pomoże to w przypadkach, gdy operujesz na literałach mniejszych niż 32 768, ponieważ domyślnie są to typy typu Integer.


Pytasz w a comment czym jest wariant/liczba całkowita. Wariant jest w zasadzie typem kontenera dla dowolnego innego typu danych. W szczególnym przypadku, w którym można zrobić to zawierać Integer:

Dim a As Variant ' a is now Empty 
a = CInt(32767) ' a is now Variant/Integer 
x = a + 1 ' works fine 

Ale jak wspomniano powyżej, zwykły stary Integer wyzwala błąd przepełnienia:

Dim b As Integer 
b = 32767 
x = b + 1 ' overflow 
+0

Z pewnością jest dziwactwem! Jaka jest różnica między wariantem/liczbą całkowitą a liczbą całkowitą? Zakładam, że jedno jest zadeklarowane w kodzie, drugie jest zadeklarowane wewnętrznie? –

+0

lub 'x = [24 * 60 * 60]' –

+1

Dobrze. Cóż, '[]' nawiasy kwadratowe są skrótem dla metody ['Evaluate'] (http://office.microsoft.com/client/helppreview14.aspx?AssetId=HV080005401&lcid=2057&NS=EXCEL.DEV&Version=14&tl=2&respos=0&CTT = 1 & queryid = 0b704676-cdcb-458a-b300-1bf8775c4ed3). Wzywasz więc interpretera programu Excel do oceny wyrażenia w VBA. Brzmi jak coś, co dodaje dużo narzutów, jeśli jest wykonywane powtarzalnie, ale myślę, że jest w porządku, jeśli używa się go przy okazji. –

1

Po każdej liczby, miejsce #. Określa każdą liczbę jako podwójną.Pomyśl o tym, ponieważ każda liczba jest umieszczana w pamięci dla obliczeń jako rodzaj zmiennej tymczasowej. Jeśli zdefiniujesz każdy numer, pozwoli on na wystarczającą ilość miejsca na obliczenia.

np

Dim x tak długo

x = 24 # 60 * # * 60 #

lub 24 & „oznacza długo

Powiązane problemy