Jak w temacie. Mam w kodzie takie wyrażenie, napisane celowo aby owy błąd wywołać:
kod := Round(5 / 0);
Jednak o dziwo EDivByZero się nie pojawia a zmienna kod (integer) po wykonaniu Round przyjmuje wartość 0. Jakieś pomysły?
Jak w temacie. Mam w kodzie takie wyrażenie, napisane celowo aby owy błąd wywołać:
kod := Round(5 / 0);
Jednak o dziwo EDivByZero się nie pojawia a zmienna kod (integer) po wykonaniu Round przyjmuje wartość 0. Jakieś pomysły?
x:=0;
y:=5/x;
Widocznie następuje jakaś magia i Delphi zamienia ci te liczby na floaty PRZED wykonaniem dzielenia. Zgodnie ze standardem IEEE-cośtam dzielenie przez zero skutkuje powstaniem wartości nieskończoność. Widocznie Round zamienia INFINITY na 0.
Ok, to działa
Jednak program nie wchodzi w obsługę wyjątku EDivByZero
try
x:=0;
y:=5/x;
//reszta kodu
except
on EDivByZero do
begin
ShowMessage('ERRRRRRRRR');
end;
end;
Debugger wyrzuca okienku z informacją o błędzie dzielenia przez zero i po kliknięciu Continue nie przechodzi do ShowMessage('ERRRRRRRRR'); Aplikacja staje i wyświetla się okienko z komunikatem "Floating point division by zero." i po kliknięciu ok dalej stoi....
Rozwiązane. Zła klasa wyjątku. Wszystko jest jak powinno dla EZeroDivide.
try
x:=0;
y:=5 div x;
//reszta kodu
except
on EDivByZero do
begin
ShowMessage('ERRRRRRRRR');
end;
end;
Funkcja
Round
jest odporna na ten błąd, ponieważ sprawdza, czy dzielenie nie odbywa się przez zero.
Var A, B, C: Integer;
Begin
A := 5;
B := 0;
C := Round(A/B);
End.
Wynik: SIGFPE na Win32, FPC 2.6.0.
Var A: Integer;
Begin
A := Round(5/0);
End.
Wynik: range check error
podczas kompilacji przy wyrażeniu 5/0
.
Constant expression violates subrange bounds
podczas kompilacji.Delphi 7
var
x, y: Integer;
begin
try
y:= 0;
x:= Round(5/y);
except
on E: EXception do
ShowMessage(Format('Error: %0:s %1:s', [E.ClassName, E.Message]));
end;
end;
Jak widać następuje konwersja liczby na zmiennoprzecinkową i umieszczenie jej na stosie a później dzielenie na liczbach zmiennoprzecinkowych więc nie dziwne że wywala EZeroDivide a nie EDivByZero.
kAzek napisał(a)
Jak widać następuje konwersja liczby na zmiennoprzecinkową i umieszczenie jej na stosie a później dzielenie na liczbach zmiennoprzecinkowych więc nie dziwne że wywala EZeroDivide a nie EDivByZero.
Oczywiście, że tak - żeby się tego dowiedzieć wystarczyło sprawdzić klasę i komunikat wyjątku:
on E: Exception
ClassName: EZeroDivide
Message: Floating point division by zero
No i jak byk napisane jest: Floating point;
Ale dlaczego w ogóle jest konwersja do liczb zmiennoprzecinkowych zamiast starej, dobrej instrukcji div
?
Azarien napisał(a):
Ale dlaczego w ogóle jest konwersja do liczb zmiennoprzecinkowych zamiast starej, dobrej instrukcji
div
?
div
działa tylko na operandach będących liczbami całkowitymi.
Widocznie kompilator tylko dzielenie całkowite robi div
No i poprawnie, bo tak stoi w standardzie:
6.7.2.1
Operator | Operation | Type of operands | Type of result |
---|---|---|---|
div | Division with truncation | integer-type | integer-type |