Лучший способ предотвратить/обработать деление на 0 в javascript

Каков наилучший способ предотвратить деление на 0 в javascript, который принимает пользовательский ввод. Если нет конкретного способа добиться этого, как лучше всего справиться с такой ситуацией, чтобы не препятствовать выполнению других сценариев?

Любые идеи очень ценятся.


person dibs    schedule 09.11.2011    source источник
comment
Просто подтвердите свой ввод, чтобы ввод 0 был невозможен, это может быть вариантом, проверка всегда полезна :)   -  person ChrisR    schedule 10.11.2011
comment
Лучший способ будет зависеть от вычислений, которые вы выполняете, и требований, которые у вас есть. Например, допустимо ли, чтобы вычисление всегда завершалось успешно, но возвращало неверный результат при вводе неверных данных?   -  person Frédéric Hamidi    schedule 10.11.2011


Ответы (8)


Это невозможно сделать с помощью обычных операторов / и /=.

Лучший способ делать то, что вы хотите, это с охранниками:

function notZero(n) {
  n = +n;  // Coerce to number.
  if (!n) {  // Matches +0, -0, NaN
    throw new Error('Invalid dividend ' + n);
  }
  return n;
}

а затем сделать деление как

numerator / notZero(denominator)

В качестве альтернативы вы всегда можете защитить вывод

function dividend(numerator, denominator) {
  var quotient = numerator / denominator;
  if (quotient !== quotient) { throw new Error(numerator + " / " + denominator); }
  return quotient;
}

но при этом теряется читабельность и выразительность /=.

person Mike Samuel    schedule 09.11.2011
comment
Если вам не нужен очень производительный код, я бы использовал if (n === 0 || isNaN(n)) {...}. Как бы то ни было, я бы забыл, что обрабатывается случай NaN. Я знаю, что принуждение является частью языка, но по большей части это плохая идея, IMO. Тоже dividend !== dividend? Как насчет isNaN(dividend)? - person Thomas Eding; 10.11.2011
comment
@trinithis, я согласен, isNaN(dividend) более идиоматичен и читабелен. Числовой код сложен для перевода, поэтому я склонен избегать приведения типов и функций в пользу встроенных операторов, которые, как правило, более переносимы, чем вспомогательные функции, но это может не иметь значения для вас. - person Mike Samuel; 10.11.2011
comment
Почему dividend? - person xehpuk; 29.06.2018
comment
@xehpuk Я не уверен, что понимаю ваш вопрос. - person Mike Samuel; 01.07.2018
comment
Почему это имя для функции и переменной? Разве это не должно быть частным? - person xehpuk; 01.07.2018
comment
@zehpuk, ты прав. Я неправильно использовал терминологию. Не стесняйтесь редактировать. - person Mike Samuel; 01.07.2018
comment
Мне нравится, что ты заставил его. - person PolymorphismPrince; 05.11.2018

Внезапно вы могли бы:

  1. Проверьте пользовательский ввод, чтобы увидеть, равен ли знаменатель нулю (или равен нулю, в зависимости от того, что на самом деле делает ваш скрипт).
  2. Проверьте, является ли результат действия isFinite(), и если нет, то обработайте его соответствующим образом.
person maerics    schedule 09.11.2011

как лучше всего справиться с такой ситуацией, чтобы не препятствовать выполнению других скриптов

Деление на ноль, похоже, не мешает выполнению других скриптов в JavaScript:

var a = 20;
var b = 0;
var result = a/b;
console.log(result); // returns Infinity

Если вы хотите, чтобы в случае деления на ноль произошло что-то другое, вы можете использовать

function divideIfNotZero(numerator, denominator) {
  if (denominator === 0 || isNaN(denominator)) {
        return null;
  }
  else {
        return numerator / denominator;
  }
}
person am2124429    schedule 05.11.2015
comment
Я думаю, что реализация служебного метода, подобного этому, является лучшим решением этой проблемы. Я создал пространство имен MyApp.Util и добавил туда это. Я использую его повсеместно. - person Mattkwish; 15.06.2018

Чтобы предотвратить (нежелательное) выполнение

  1. Всегда проверяйте критические вводимые пользователем данные и/или результаты.
  2. Используйте логику и/или обратные вызовы, выполнение которых можно предотвратить.
  3. В HTML-формах и т. д. вы можете использовать, например, return false; в качестве значения, чтобы остановить отправку.
person Smamatti    schedule 09.11.2011

Надеюсь, это полезно

(denominator != 0 ? numerator/denominator : Infinity)

или любое другое значение, которое вы хотите поставить в конце.

Привет.

person AlexMethod    schedule 29.06.2018
comment
это вернет ноль при делении на отрицательные значения, и это неверный результат - person derloopkat; 29.06.2018
comment
Это бесконечность, Вот почему я поставил или что вы хотите поставить в конце. Я пытался помочь, не надо так грубо! Но спасибо за ваш отзыв - person AlexMethod; 11.07.2018

Почему бы просто не проверить, равен ли знаменатель нулю?

if(x != 0) z = y / x;

Вы также можете проверить, является ли результат Infinity:

3 / 0 == Infinity

Результаты в true;

(Проверено только в хроме.)

person GAgnew    schedule 09.11.2011
comment
3 / 0 == Infinity должно быть истинным во всех браузерах, так как есть только одна последовательность битов, которая соответствует положительному значению 64b IEEE-754 с плавающей запятой, но -3 / 0 != Infinity поэтому здесь помогает встроенный isFinite. Если накладные расходы на вызов функции слишком дороги, одним из быстрых способов отфильтровать как бесконечные значения, так и NaN является x - x === 0, так как этот результат равен 0 для всех конечных чисел и NaN для специальных чисел с плавающей запятой. - person Mike Samuel; 20.11.2011

Немного отличается от остановки выполнения, но тернарный оператор — довольно удобный способ настроить назначение переменных.

var one = 1,
    zero = 0,
    customValue = 1;


var quotient = zero===0 ? customValue : one / zero;

Таким образом, задав для customVariable целое число по вашему выбору, вы можете ожидать предсказуемый результат при делении на ноль.

person ShaneSauce    schedule 29.08.2017

Лучший способ — контекстный. Но вот самый простой:

function myFunction( input ){
    input = 0 ? 0.0001 : input; // same as if( input == 0 ){ input = 0.0001; }
    return 1 / input;
}

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

Несколько предостережений не позволяют этому быть универсальным:

  • Это может привести к ложным срабатываниям, если ваш ввод принимает очень маленькие числа.
  • Он не будет запускать какой-либо код обработки ошибок, если вам нужно сделать что-то особенное, если введен ноль.

Так что это лучше всего подходит для некритических случаев общего назначения. Например, если вам нужно вернуть результат сложного вычисления и вам все равно, будет ли ответ точным до N цифр (определяется как 0,0001 против 0,00000001 и т. д.); вы просто не хотите, чтобы он сломался при делении на ноль.

Как предложил другой ответ, вы также можете создать глобальную функцию многократного использования.

function divisor( n ){ return ( n = 0 ? 0.0001 : n ); }
function myFunction( input ){ return 1 / divisor( input ); }

Возможные улучшения:

function divisor( n, orError ){
    if( typeof n == 'undefined' || isNaN( n ) || !n ){
        if( orError ){ throw new Error( 'Divide by zero.' ); }
        return 0.000000000000001;
    }else{ return 0 + n; }
}

Это будет принимать любое значение (null, число, строка, объект) и, если оно недействительно или равно нулю, вернуть отказоустойчивое нулевое значение. Это также приводило бы вывод к числу на тот случай, если бы это была строка, и вы делали что-то странное. Все это гарантирует, что ваша функция делителя всегда будет работать. Наконец, для случаев, когда вы хотите самостоятельно обрабатывать такие ошибки, вы можете установить для второго параметра значение true и использовать try/catch.

person Beejor    schedule 13.09.2018