Russian Qt Forum
Декабрь 03, 2024, 22:25 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: 1 [2]   Вниз
  Печать  
Автор Тема: Как корректно обработать деление на 0, логарифм нуля, и т.п.  (Прочитано 10100 раз)
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2095



Просмотр профиля
« Ответ #15 : Сентябрь 24, 2013, 19:02 »

Цитировать
Точно не пройдет, но никто не мешает записать это нормально, напр
Ну это, конечно, нормально.. да)  

Банальная сдвижка сигнала и шума на маааленькую величину решает все эти проблемы)
А чтоб не осталось сомнений в том, что эта маааленькая величина не вносит хоть какие-либо искажения в конечный результат привожу два графика этого логарифма при различных epsilon (0.001 и 0.0001). Даже при таких больших значениях epsilon, я не вижу разницы между графиками..

Код
C++ (Qt)
int main()
{
   std::ofstream out("test.txt");
 
   std::uniform_real_distribution<double> dist(0.0, 1.0);
   std::mt19937 gen;
 
   const double epsilon = 0.001;
   const unsigned N = 100;
 
   for (unsigned i = 0; i < N; ++i) {
       double s = dist(gen);
       double n = dist(gen);
       out << i << " " << log((s + epsilon)/(n + epsilon)) << std::endl;
   }
 
   return 0;
}
 

  
« Последнее редактирование: Сентябрь 24, 2013, 22:36 от m_ax » Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5
zzzseregazzz
Гость
« Ответ #16 : Сентябрь 25, 2013, 08:07 »

Цитировать
Банальная сдвижка сигнала и шума на маааленькую величину решает все эти проблемы)
 
Код
C++ (Qt)
double sn = log((s + epsilon)/(n + epsilon));

А вдруг s или n оказались отрицательными? Они могли быть получены с помощью какой-то внешней функции, и кто знает какие там косяки.

Цитировать
Ни разу не видел чтобы напр sqrt, log. acos и.т.п. вызывали исключение.
Кто их знает? Обычно не бросают, но может быть есть такие ОС, в которых бросают.
« Последнее редактирование: Сентябрь 25, 2013, 08:14 от zzzseregazzz » Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #17 : Сентябрь 25, 2013, 10:27 »

Кто их знает? Обычно не бросают, но может быть есть такие ОС, в которых бросают.
Кто = стандарт, от ОС не зависит.

А вдруг s или n оказались отрицательными? Они могли быть получены с помощью какой-то внешней функции, и кто знает какие там косяки.
Совершенно верно, поэтому я привел пример где Clamp загоняет их в валидный диапазон. Это часть работы, пусть не самая творческая, но которую надо делать, а не сачковать
Записан
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2095



Просмотр профиля
« Ответ #18 : Сентябрь 25, 2013, 10:45 »

А вдруг s или n оказались отрицательными? Они могли быть получены с помощью какой-то внешней функции, и кто знает какие там косяки.

Код
C++ (Qt)
double sn = log((fabs(s) + epsilon)/(fabs(n) + epsilon));
 

Ну а если уж так хочется считать логарифм и от отрицательного аргумента, то комплексные числа никто не отменял (см. std::complex)

 
Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5
xokc
Птица говорун
*****
Offline Offline

Сообщений: 976



Просмотр профиля
« Ответ #19 : Сентябрь 26, 2013, 08:56 »

А вдруг s или n оказались отрицательными? Они могли быть получены с помощью какой-то внешней функции, и кто знает какие там косяки.
А Вы сами что предполагаете рисовать на графике, если один из "косячных" случаев всё-же случился?

Кто их знает? Обычно не бросают, но может быть есть такие ОС, в которых бросают.
Ну с такой паранойей и i++ оборачивать try/catch нужно.
Записан
zzzseregazzz
Гость
« Ответ #20 : Сентябрь 26, 2013, 10:39 »

Цитировать
Ну с такой паранойей и i++ оборачивать try/catch нужно.

А как же. Надо проверить, не будет ли переполнения.
Т.е. что-то вроде
Код
C++ (Qt)
try {
   if(i<0xffffffff) i++;
   else throw "Integer overflow";
}
catch(const char* ex)
    //...
}
Но это не кроссплатформенно, int не всегда 32 бита. Как это можно исправить?
Записан
zzzseregazzz
Гость
« Ответ #21 : Сентябрь 26, 2013, 10:49 »

А Вы сами что предполагаете рисовать на графике, если один из "косячных" случаев всё-же случился?

Ну, бесконечность можно изобразить вертикальной прямой.
Отрицательные числа, когда они недопустимы, заменить на 0.
Что делать с 0/0 вообще не знаю.
Ваши варианты?
« Последнее редактирование: Сентябрь 26, 2013, 10:53 от zzzseregazzz » Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #22 : Сентябрь 26, 2013, 12:50 »

А как же. Надо проверить, не будет ли переполнения.
Т.е. что-то вроде
Код
C++ (Qt)
try {
   if(i<0xffffffff) i++;
   else throw "Integer overflow";
}
catch(const char* ex)
    //...
}
Но это не кроссплатформенно, int не всегда 32 бита. Как это можно исправить?
Код
C++ (Qt)
std::numeric_limits<int>::max()
 
Хотя мне неизвестна ни одна современная платформа где int не 4 байта. Вот long да, где 4 а где и 8.

Вы так упорно стремитесь к исключениям как будто это хорошо/правильно и даже круто Улыбающийся В действительности же ничего хорошего в этом нет. Ну выбросили исключение, дальше-то что? Сообщить пользователю "ошибка" - это не сделает его счастливым, тем более что ситуация вполне штатная

Что делать с 0/0 вообще не знаю.
Ваши варианты?
Да как угодно, напр не рисовать вообще (только должна быть надпись "нет сигнала") или рисовать др цветом или пунктирной линией. Это вопрос дызайна.
Записан
zzzseregazzz
Гость
« Ответ #23 : Сентябрь 26, 2013, 13:19 »

Сообщить пользователю "ошибка" - это не сделает его счастливым, тем более что ситуация вполне штатная

Конечно не сделает.
Но корректно обработать ошибку еще сложнее. А ошибка может произойти почти в каждой строке, даже i++. Получается, надо на каждую строку писать обработчик. В этом обработчике в свою очередь тоже могут возникнуть ошибки...
И какой в итоге будет объём кода, где все возможные ошибки корректно обрабатываются?
Записан
mutineer
Гость
« Ответ #24 : Сентябрь 26, 2013, 14:22 »

Сообщить пользователю "ошибка" - это не сделает его счастливым, тем более что ситуация вполне штатная

Конечно не сделает.
Но корректно обработать ошибку еще сложнее. А ошибка может произойти почти в каждой строке, даже i++. Получается, надо на каждую строку писать обработчик. В этом обработчике в свою очередь тоже могут возникнуть ошибки...
И какой в итоге будет объём кода, где все возможные ошибки корректно обрабатываются?

Если учитывать все возможные ошибки, даже в i++, то объём такого кода будет 0 строк. Потому что в условиях, когда нет уверенности даже в элементарных операциях, писать что-либо невозможно
Записан
xokc
Птица говорун
*****
Offline Offline

Сообщений: 976



Просмотр профиля
« Ответ #25 : Сентябрь 26, 2013, 14:30 »

Ну, бесконечность можно изобразить вертикальной прямой.
Бесконечно вертикальной?

Отрицательные числа, когда они недопустимы, заменить на 0.
Так всё-таки допустимы отрицательные числа или нет? Если - нет, то делайте фильтр на входе типа s = qMax(1e-10, s) и n = qMax(1e-10, n) и тему можно закрывать. Если да - то Вы сначала сами для себя решите, чему равен log(-1), а потом мы Вам подскажем как это нарисовать.
Вообще говоря, в обработке сигналов обычно имеет смысл говорить об отношении мощности сигнала к мощности шума. Эти величины заведомо неотрицательны, что сразу снимает все Ваши переживания.

Что делать с 0/0 вообще не знаю.
Ваши варианты?
С учетом того, что решается задача всего лишь отображения графика, мой вариант (он неоднократно уже озвучен в этом топике) - прибавлять к сигналу и шуму по пренебрежимо малой величине. Вариант неоднократно опробирован при решении самых разных задач ЦОС, требующих гораздо большей точности, чем рисование графиков.
« Последнее редактирование: Сентябрь 26, 2013, 14:32 от xokc » Записан
Страниц: 1 [2]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.203 секунд. Запросов: 23.