Деление с плавающей запятой на ноль исключение в Delphi5

мое приложение написано на Delphi5. Я использую madExcept для отслеживания ошибок. Я отследил исключение "с плавающей запятой dvision на ноль", где его не должно быть. Сегмент кода, где он поднимается, идет следующим образом:

val:=100*Power(1.25,c);

где " c "фактически всегда имеет значение "1".

трассировка стека журнала:

main thread (8f8):
00403504 +010 MyApp.exe   System   1970  +5 @FRAC
00479148 +058 MyApp.exe   Math              Power
007ae8a6 +262 MyApp.exe   MyClass  1962 +36 TMyClass.FormMouseWheel

в какой-то момент у меня было другое исключение, где имело место деление, однако делитель был переменной, которая также имела значение '1', когда произошло исключение. Что я смог отладить и воспроизвести.

мой вопрос: что я упускаю? Есть ли ложные срабатывания в отношении деления с плавающей запятой, о которых я не знаю?

кроме того: я не использую библиотеки DLL C++ в точках исключения, поскольку они имеют тенденцию обрабатывать подразделения FP по-разному (возвращая NaN или +/ - INF, а не вызывая исключение).

любой указатели с благодарностью.

3 ответов


Я только что попробовал следующий код:

procedure TTTest.FormCreate(Sender: TObject);
var v: extended;
    one: extended;
begin
  one := 1.0;
  v := 100*Power(1.25,one);
end;

он просто компилируется и запускается, как ожидалось, в Delphi 5.

Я предполагаю, что деление на нулевой флаг может быть установлено вне вашего кода (даже если вы не ссылаетесь на код c++, вызов Direct X или такой может иметь тот же эффект), но позже, в _Frac.

единственный вызов Frac в стандартной реализации Power() проверить Frac(Exponent) = 0.0.

была модификация в реализация Frac между Delphi 5 и Delphi 6.

вот версия Delphi 5:

procedure       _FRAC;
asm
    FLD     ST(0)
    SUB     ESP,4
    FSTCW   [ESP]
    FWAIT
    FLDCW   cwChop
    FRNDINT
    FWAIT
    FLDCW   [ESP]
    ADD     ESP,4
    FSUB
end;

вот версия Delphi 6:

procedure       _FRAC;
asm
    FLD     ST(0)
    SUB     ESP,4
    FNSTCW  [ESP].Word     // save
    FNSTCW  [ESP+2].Word   // scratch
    FWAIT
    OR      [ESP+2].Word, F00  // trunc toward zero, full precision
    FLDCW   [ESP+2].Word
    FRNDINT
    FWAIT
    FLDCW   [ESP].Word
    ADD     ESP,4
    FSUB
end;

из приведенного выше кода Вы узнаете, что следующие команды вызвали отложенные исключения до выпуска Delphi 6: Trunc, Frac, Ceil.

Итак, я думаю, вы столкнулись с проблемой с Delphi 5, которая была исправлена с Delphi 6. Вы можете использовать свой вариант питания, вот так:

function Power(Base, Exponent: Extended): Extended;
begin
  if Exponent = 0.0 then
    Result := 1.0               { n**0 = 1 }
  else if (Base = 0.0) and (Exponent > 0.0) then
    Result := 0.0               { 0**n = 0, n > 0 }
  else
    Result := Exp(Exponent * Ln(Base))
end;

нет окончательного ответа, но...

исключения, связанные с Fpu, где их не должно быть, могут быть связаны со стеком FPU, который не очищается должным образом. У нас были аналогичные проблемы на одном этапе, хотя мы столкнулись с недопустимыми исключениями операции с плавающей запятой.

статьи: Delphi ошибка дня: утечка стека FPU где кто-то отследил причину недопустимого исключения операции с плавающей запятой, вызванного S := S + '*'; , помог нам устранить проблему.


вы используете TWebBrowser или любой компонент IE webbrowser, такой как EmbeddedWB?

Если это так, это может объяснить это: https://forums.embarcadero.com/thread.jspa?messageID=334125&tstart=0

Он также содержит что-то, что может решить проблему, даже если вы не используете webbrowser (Set8087CW), как описывает ссылка, предоставленная Jeroen выше.