@Acaunt

Нужно ли делать защиту при делении на ноль?

Создаю класс для работы с векторной математикой и в нескольких функциях выполняется операция деления. Чаще всего некоторое число делится на длину вектора.

И есть небольшая вероятность, что вектор будет иметь нулевые координаты vec{0,0,0} и следовательно, его длина тоже равна 0.
В принципе, программа не вылетает, просто возвращает значение +/-∞.

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

Данный класс планируется использовать в разных отраслях для личного пользования.
  • Вопрос задан
  • 301 просмотр
Решения вопроса 1
mayton2019
@mayton2019
Bigdata Engineer
Вообще ты сам себе ответил на вопрос
в разных отраслях для личного пользования.


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

Какие вообще у тебя варианты по отработке неопределенностей? Я вижу такие.
1) Возвращать бесконечность +Inf. Это нормально для floating-point. Но влияние результата на стек
вызовов дальше надо учитывать. Эта бесконечность пойдет в другие формулы порождая новые бесконечности и т.п.

2) Бросать исключение. Это не в духе С++ и не всегда удобно для выскокой производительности. Но языки высокого уровня этим часто пользуются. Здесь мы предполагаем что такой результат - крайне нежелателен и работа стека расчета векторов будет аварийно прервана.

3) Возвращать специальный контейнер с результататом (Optional или Either) или пустой контейнер. Это в духе функционального кодинга. Но весь твой стек должен тоже быть адаптированным к таким Optional параметрам результатов.

И есть еще вариант - просто найти такой базис вычислений в котором нет такой проблемы. Пускай допустим векторы так и остаются основным типом данных но расчеты ты будешь делать в каком-нибудь другом типе где эта операция на уровне математики - безопасна и всегда определена. Грубо говоря как в углах Эйлера. Чтоб не писать всякие проверки условий (if) - можно перейти к кватерниону и там вроде как вращение легче идет.
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 3
wataru
@wataru
Разработчик на С++, экс-олимпиадник.
Для облегчения отладки в будущем, стоит вставить assert какой-нибудь. Чтобы программа падала с понятной ошибкой, при попытке поделить на 0.
Ответ написан
Комментировать
@imageman
Есть еще подход: к знаменателю всегда добавлять некий маленький эпсилон. К примеру eps=0.00001
Ответ написан
@Bwana
Что касается операций с векторами, кватернионами, матрицами и прочими сущностями, которые определены на n-мерной поверхности с топологией сферы, то появление нулевой или очень маленькой нормы является признаком плохого выбора алгоритма. Это всегда приводит к катастрофической потере точности и может считаться логической ошибкой программирования. Никаких бесконечностей и прочих сингулярностей в вычислениях быть не должно. Поэтому делитель, если это что-то вроде нормы, следует всегда проверять на вшивость и если он слишком мал, просто делать аборт, после чего сесть и подумать, как модифицировать алгоритм, чтобы тот был вычислительно устойчив.
Желательно четко понимать, в каких случаях алгоритм теряет устойчивость и точность представления результата, проверять на такие условия ( пример -- алгоритм Шепперда вычисления кватерниона, эквивалентного матрице вращения) и переключаться на другой алгоритм, более устойчивый в данной области. А делитель на малость нужно проверять всегда. Обычно предел малости выбирают исходя из задачи. В общем случае при использовании 64-разрядных чисел с плав. запятой в качестве нуля можно принять полуширину интервала в 1E-14. Но лучше алгоритм протестировать в областях, где он демонстрирует плохую обусловленность, поскольку не всегда это можно оценить теоретически. Как вариант, генерируем много равномерно распределенных в поганой области векторов и определяем минимальную ширину допустимой зоны малости, увеличиваем ее на порядок и используем для проверки деления.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы