IPB
ЛогинПароль:

> ПРАВИЛА РАЗДЕЛА!!!

1. Заголовок или название темы должно быть информативным
2. Все тексты программ должны помещаться в теги [CODE=asm] [/CODE]
3. Прежде чем задавать вопрос, см. "FAQ",если там не нашли ответа, воспользуйтесь ПОИСКОМ, возможно, такую задачу уже решали!
4. Не предлагайте свои решения на других языках, кроме Ассемблера. Исключение только с согласия модератора.
5. НЕ используйте форум для личного общения! Все, что не относиться к обсуждению темы - на PM!
6. Проверяйте программы перед тем, как выложить их на форум!!

 
 Ответить  Открыть новую тему 
> Исключения FPU
сообщение
Сообщение #1


Злостный любитель
*****

Группа: Пользователи
Сообщений: 1 755
Пол: Мужской

Репутация: -  62  +


Создаю тут, потому что мне кажется, что это относится к асму.


{$APPTYPE CONSOLE}

var
a: extended;
begin
a := sqrt(-1);
writeln(a);
readln;
end.




Я хочу, чтобы это программа вывела на экран NAN. Меня вполне устраивает значение "не число". Неопределённый результат - тоже результат, что такого-то. Но программа вылетает. Причём вылет происходит не в момент вычисления корня, а при выгрузке результата в память. Что надо сделать, чтобы программа не вылетала? (Вариант writeln('NAN') - не предлагать).


--------------------
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #2


Гость






Не имеет это никакого отношения к ассемблеру. И Дельфи и FPC прекрасно сами способны обработать подобную ситуацию:

{$APPTYPE CONSOLE}

uses SysUtils, Math;
var
a: extended;

begin
try
a := sqrt(-1);
except
on E: EInvalidOp do // модуль SysUtils
begin
a := NaN; // модуль Math
end;
end;

writeln(a); // Вот тут и напечатается "nan"
readln;
end.
 К началу страницы 
+ Ответить 
сообщение
Сообщение #3


Злостный любитель
*****

Группа: Пользователи
Сообщений: 1 755
Пол: Мужской

Репутация: -  62  +


Я в курсе про обработку исключений. Но в данном случае костыль какой-то получается.
Можно отключить исключение, происходящее при записи НАНа в память? Или другие программы пострадают?


--------------------
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #4


Гость






Костыль будет, если отключить обработку исключения. В твоей программе тебе нужно определенное поведение - значит, лови исключение в своей программе, а не заставляй все остальные программы играть по твоим правилам.
 К началу страницы 
+ Ответить 
сообщение
Сообщение #5


Злостный любитель
*****

Группа: Пользователи
Сообщений: 1 755
Пол: Мужской

Репутация: -  62  +


Дело в том, что я хочу вывести график некой функции (допустим, введённой пользователем). В некоторых точках функция может оказаться не определена.
Чтобы программа это дело обработала, можно ввести проверки (if(abs(a)<1E+1000) and (abs(b)<1E+1000) then c := a*b), но хотелось бы, чтобы программа вычисляла всё, что можно вычислить. Поэтому я таки ввёл исключения, и с ними и жил. Но меня не покидало ощущение, что я делаю что-то не то. Особенно, если надо вычислить значение во многих точках, что требует времени.
Кстати, как выкручивались в ТурбоПасе, в котором try except не было?

Добавлено через 4 мин.
> Костыль будет, если отключить обработку исключения.

То есть просто записать NAN в память - это костыль, а перейти в блок обработки исключения, там сделать ещё кучу действий по определению типа исключения и потом всё равно записать в память этот NAN - это не костыль? Мне вот с чисто эстетической точки зрения это дико не нравится.

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

То есть даже если я запомню состояние FPU и потом при выходе его восстановлю, то параллельно работающим программам это сильно не понравится?
Кстати, Delphi же вызовы некоторых системных функций оборачивает с переводом FPU в режим повышенной точности. И ничего.


--------------------
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #6


Гость






Цитата
Кстати, как выкручивались в ТурбоПасе, в котором try except не было?
То, что не было зарезервированных слов try/except - еще ни о чем не говорит: См. здесь
 К началу страницы 
+ Ответить 
сообщение
Сообщение #7


Злостный любитель
*****

Группа: Пользователи
Сообщений: 1 755
Пол: Мужской

Репутация: -  62  +


Кстати, а вот почему делить на ноль можно (и безо всякого исключения получить +inf или -inf, в зависимости от знака делимого), а извлекать корень из минус единицы - нельзя?


--------------------
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #8


Гость






Цитата
а вот почему делить на ноль можно (и безо всякого исключения получить +inf или -inf, в зависимости от знака делимого)
Правда что-ли? А мужики-то не знают:
var
a, b: extended;
begin
b := 0.0;
a := -1.23;

a := a / b;
writeln(a);
readln;
end.

Что будет выведено на печать? Что-нибудь ВООБЩЕ будет выведено? (если что, меня древние версии ПО мало интересуют, за заявлением "делить на 0 можно" стоит утверждение, что процессор в принципе не производит никаких исключительных действий, которые ловятся программой. Значит, я должен получить результат -inf, откомпилировав код ЛЮБОЙ версией Дельфи и запустив программу. Договорились. Стандартные настройки, Дельфи 2009/2010. Вопрос - прежний, что я увижу на экране?)

А вот так:
uses math, sysutils;
var
a, b: extended;
begin
b := 0.0;
a := -1.23;

try
a := a / b;
except
on E: Exception do
begin
writeln(e.ClassName);
end;
end;

writeln(a);
readln;
end.
? Что я теперь увижу? (если "без исключений" - значит, я не должен видеть ничего, кроме как -inf?)
 К началу страницы 
+ Ответить 
сообщение
Сообщение #9


Злостный любитель
*****

Группа: Пользователи
Сообщений: 1 755
Пол: Мужской

Репутация: -  62  +


И вправду вылетает.
Да, мне теперь самому интересно, почему безо всяких исключений выводит +inf (и у меня, и у всех пользователей) программа, вычисляющая радиус дуги, сопрягающей два отрезка, в случае параллельных отрезков. Концы у отрезков целые, но для вычисления все вещественные.
Ничего такого я там с сопроцессором не делал!


--------------------
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #10


Гость






Упоминание о подобной проблеме присутствует на форуме Embarcadero: Delphi 2010 and Floating Point Exceptions

Мне лично воспроизвести не удалось, хотя честно пытался (и создавал проект в Д6, и потом его открывал Д2009, и по всякому извращался с настройками среды/режимами компиляции) - ничего не получилось, упорно выбрасывается исключение. Судя по обсуждению - не у меня одного это не воспроизводится...

Все-таки, перенести тему в раздел "Дельфи", или будем решать проблемы через ... хм, ассемблер?
 К началу страницы 
+ Ответить 
сообщение
Сообщение #11


Злостный любитель
*****

Группа: Пользователи
Сообщений: 1 755
Пол: Мужской

Репутация: -  62  +


uses OpenGL;


--------------------
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #12


Гость






Что Uses OpenGL?

Не делай Uses OpenGL... Смысла в моем сообщении ровно столько, сколько в #11...
 К началу страницы 
+ Ответить 
сообщение
Сообщение #13


Гость






Ах, ты о том, что при использовании модуля OpenGL
uses OpenGL;

var
a, b: double;
begin
b := 0.0;
a := -1.23;
a := a / b;

writeln(a);
readln;
end.

выдает -Inf , а не выбрасывает исключение? Так, это само собой: в секции инициализации модуля OpenGL есть код, который устанавливает маску исключений. Что-то вроде
SetExceptionMask(
[exInvalidOp, exDenormalized, exZeroDivide,exOverflow, exUnderflow, exPrecision]
);

(то, что я привел - это из исходников FPC, в Дельфи тоже что-то подобное, но исходников его у меня сейчас нет под рукой).

Где
  TFPUException = (
exInvalidOp, exDenormalized, exZeroDivide,
exOverflow, exUnderflow, exPrecision);

TFPUExceptionMask = set of TFPUException;

function SetExceptionMask(const Mask: TFPUExceptionMask): TFPUExceptionMask;
var
CtlWord: Word;
begin
CtlWord := Get8087CW;
Set8087CW( (CtlWord and $FFC0) or Byte(Longint(Mask)) );
if has_sse_support then
SetSSECSR((GetSSECSR and $ffffe07f) or (dword(Mask) shl 7));
softfloat_exception_mask:=dword(Mask);
Result := TFPUExceptionMask(Longint(CtlWord and $3F));
end;

(а это - уже из модуля Math)

Так что не мудрено, что при использовании модуля OpenGL становится возможным деление на 0 (и многое другое). Только вот хорошо ли это? А если у меня написан код, когда я его писал - совершенно логично считал, что любая попытка делить что-либо на 0 закончится выбрасыванием исключения, ловил это исключение в блоке Except, а потом подключил модуль OpenGL, и вся логика улетела в тартарары, ни один блок Except не отработал, зато теперь результат содержит мне на фиг не нужное +/- (Inf).

"А?... Это хорошо? Это противно..." (С) А. Райкин, "Дефицит"...
 К началу страницы 
+ Ответить 
сообщение
Сообщение #14


Злостный любитель
*****

Группа: Пользователи
Сообщений: 1 755
Пол: Мужской

Репутация: -  62  +


> Так, это само собой: в секции инициализации модуля OpenGL есть код, который устанавливает маску исключений.

Я об этом и спрашивал с самого начала. Вот, наконец-то я знаю ответ на изначальный вопрос.

> Только вот хорошо ли это?

Да. Потому что если я рисую график логарифма, и у меня по умолчанию интервал от -10 до 10, то для половины точек значение не определено. Обрабатывать исключение для половины точек - это идиотизм. Исключения - они на то и исключечния, что нужны для нештатных ситуаций. В случае построения графика функции неопределённое значение - это штатная ситуация.
ПС. Я не против исключений, я против их неуместного использования.


--------------------
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 

 Ответить  Открыть новую тему 
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 




- Текстовая версия 17.08.2018 1:18
Хостинг предоставлен компанией "Веб Сервис Центр" при поддержке компании "ДокЛаб"