Проверка деления на ноль

Хотите улучшить этот вопрос? Update the question so it’s on-topic for Stack Overflow на русском.

Закрыт 3 года назад .

Здесь происходит сложение, вычитание, деление, умножение и сокращение простых дробей. Необходимо сделать проверку, чтобы в знаменателе нельзя было ввести ноль. Пробовала реализовать, но не получилось ( if (this->b==0)

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

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

Деление целых чисел на ноль

Описывать процесс создания калькулятора я не буду, т.к. процесс, по сути, ни чём не отличается от калькулятора, в котором используются только целые числа, а сразу перенесёмся в конец таких уроков, когда начинают разбирать допущенные ошибки. Среди которых самая распространенная, это необработанное исключение, которое возникает в результате деления целого числа на ноль, например:

В данном примере при делении целого числа на ноль возникает исключение DivideByZeroException, после чего выполнение программы прекращается.

Обычно в такой ситуации нам предлагают использовать блоки try catch, чтобы отловить исключение, а затем выдать сообщение об ошибке, либо предложить какую-то иную логику, например:

Читайте также  После установки касперского синий экран

В этот раз при возникновении исключения попадаем в блок catch.

Посмотрев этот видеоурок, начинающие программисты очень часто делают для себя вывод, что блоки try catch, не зависимо от того, делите вы на ноль целое или дробное число, являются универсальным средством решения данной проблемы. Но, так ли это на самом деле?

Деление дробных чисел на ноль

Предлагаю взглянуть на следующий код:

Казалось бы, всё учтено, в коде добавлены блоки try catch, и теперь можно делить на ноль любые числа и ничего не боятся. Но, давайте разберём этот пример. Поставим точку остановы, и посмотрим, чему будет равно значение переменной b после операции деления на ноль. Многие скажут, что и так всё понятно возникнет исключение, которое будет обработано блоком catch. Но давайте всё-таки взглянем на результат.

продолжим выполнение программы

И так что мы видим. Главное это то, что ожидаемого выброса исключения при делении дробного числа на ноль не происходит, вместо этого переменной b было присвоено значение Infinity (бесконечность), после чего программа успешно продолжила свое выполнение. Установленные же блоки try catch не помогли нам выявить деление на ноль, потому что их работа связана с обработкой возникающих исключений, которых в данном случае — нет, как в более раннем примере с целыми числами. Поэтому в качестве результата получаем следующую картинку:

Судя по коду, программист явно не ожидал такого результата и не предполагал, что дальнейшие расчеты будут происходить со значением бесконечность. Хотя при этом, казалось бы, все сделано так, как объясняли в уроке с целыми числами, в чём же проблема?

Стандарт IEEE 754

На самом деле всё просто. Для арифметических операций с плавающей точкой используется стандарт IEEE 754 (IEEE floating point) или (The IEEE Standard for Floating-Point Arithmetic), в котором описываются: правила округления, арифметические форматы, операции, обработка исключений и многое другое.

Читайте также  Принтер бразер струйный цветной

Возникновение исключения, при делении дробного числа на ноль, так же описано в стандарте и попадает в список пяти исключений, при возникновении которых вместо exception возвращается значение по умолчанию. В данном случае таким значением является ±Infinity (которое и было получено ранее в примере). Дополнительная обработка таких ситуаций так же не требуется, поэтому добавленные блоки try catch, хоть и указаны в коде, но никакой роли не играют.

Вывод: при делении на ноль типов с плавающей точкой никогда не генерируется исключение, вместо этого всегда возвращается значение, по умолчанию описанное в стандарте, то есть ±Infinity, но так же возможно значение NaN.

Как определить, было ли выполнено деление на ноль?

Например, можно воспользоваться следующим способом: cначала позволим программе выполнить деление на ноль, в результате получаем +-infinity, а затем добавим проверку с методом float.IsInfinity() либо double.IsInfinity() в зависимости от типа. Проверка ловит, как минус, так и плюс бесконечность.

Но, здесь есть один нюанс, текст сообщения:

Данное сообщение может быть не верным, в ситуации арифметического переполнения переменной b, возникновение которого так же описано в списке пяти исключений стандарта IEEE754, когда вместо выброса исключения возвращают значение по умолчанию, которым опять же является ±Infinity.

Установленная ранее проверка float.IsInfinity() успешно отработает и на консоль будет выведено сообщение:»деление на ноль», что, конечно же, не верно.

Ещё один нюанс возникает, если переменная b будет иметь значение 0.

То есть в данном примере будем делить ноль на ноль. Всё остальное оставим как есть, нажимаем F5

Как видно на картинке в результате деления переменная b содержит NaN (Not-a-Number) или (значение, не являющееся числом). Это ещё одно значение, которое можно получить в результате операции деления дробного числа на ноль. При этом никаких исключений не выбрасывается. Добавленная проверка float.IsInfinity() в данном случаи выдает false, а значит код в блоке else выполнится успешно.

Читайте также  Программа для робота пылесоса xiaomi

Чтобы отловить этот момент в коде, можно воспользоваться методом float.IsNaN()

На этом всё. Надеюсь, это статья поможет Вам избежать подобных ошибок в вашем коде.

В языке c# существует только два типа с плавающей точкой (IEEE floating point) — это float и double, которые реализованы на основе стандарта IEEE 754. Поэтому при делении на ноль числа типа Decimal будет выброшено исключение DivideByZeroException.

Это сообщение возникает в том случае, если в алгоритме конфигурации Используется деление и не выполняется проверка значения делителя. Обычно эта ошибка возникает из-за того, что не заполнены какие-либо данные (сумма, количество, коэффициенты и т.п.). Необходимые для работы алгоритма данные должны быть заполнены, например, в документе или справочнике, элемент которого выбран в документе. Обычно эта проблема решается вводом необходимых для работы алгоритма данных и повторным запуском алгоритма (формирования отчета или проведения документов).

Решение:
в коде
Код 1C v 8.х

Ссылка на основную публикацию
Adblock
detector