Как я могу избежать деления на ноль без слишком большого количества условных выражений?

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

Например, если количество итераций для каждого прогона равно 1000, то параметр FREQ будет равен 5, если я хочу, чтобы событие происходило каждые 200 итераций. Однако я хочу иметь возможность изменять количество итераций, но сохранять соотношение одинаковым, а также иметь возможность установить для параметра FREQ значение 0, если я не хочу, чтобы событие происходило вообще.

Вот что я сейчас использую:

int N_ITER = 1000;
int FREQ = 5;

void doRun(){
    int count = 0;
    for (int i = 0; i < N_ITER; ++i){
        if (FREQ > 0){
            if (count < N_ITER/FREQ){
                doSomething();
                count++;
            }
            else{
                doSomethingElse();
                count = 0;
            }
        }
        else{
            doSomething();
        }            
    }
}

Это отлично работает, но мне не подходят вложенные условные операторы, особенно когда у меня есть две партии doSomething(), я чувствую, что это должно быть выполнено проще, чем это.

Я попытался сделать одно условное if (FREQ > 0 && count < N_ITER/FREQ), но, очевидно, это выдало Floating point exception из-за деления на ноль.

Я также пытался использовать блок try/catch, но с точки зрения беспорядка он ничем не отличался от использования вложенных условных выражений. Есть ли более элегантное решение этой проблемы?


person guskenny83    schedule 03.11.2018    source источник
comment
Я попытался сделать одно условное if (FREQ > 0 && count < N_ITER/FREQ), но, очевидно, это вызвало исключение с плавающей запятой из-за деления на ноль. Это невозможно. && замкнуло бы и предотвратило оценку N_ITER/FREQ, если бы FREQ > 0 было ложно.   -  person HolyBlackCat    schedule 03.11.2018
comment
continue помогает уменьшить вложенность   -  person Mateen Ulhaq    schedule 03.11.2018
comment
@HolyBlackCat: я тоже так думал, но это так, я проверю, не может ли что-то еще вызвать исключение, но я так не думаю   -  person guskenny83    schedule 03.11.2018
comment
Кроме того, обратите внимание, что, несмотря на имя исключения с плавающей запятой, на самом деле это не исключение, и вы не можете catch его. Скорее, это сигнал.   -  person HolyBlackCat    schedule 03.11.2018
comment
@guskenny83 В этом коде используются только целые числа. Если вы получаете исключение с плавающей запятой, проблема, скорее всего, в другом.   -  person janm    schedule 03.11.2018
comment
@janm Целочисленное деление на ноль может увеличить SIGFPE. Демонстрация: coliru.stacked-crooked.com/a/3b7791e2684a52a2   -  person HolyBlackCat    schedule 03.11.2018
comment
хм, извините, что беспокою вас, но оказалось, что я поставил символ «больше чем» неправильно, так что это не вызвало короткого замыкания.. :-$ эээ, я думаю, это то, что происходит, когда вы смотрите на тот же код целую вечность скучаешь по таким глупостям..   -  person guskenny83    schedule 03.11.2018
comment
@HolyBlackCat Увлекательно. И плавающее деление на ноль, вероятно, в этом случае возвращает NaN.   -  person janm    schedule 03.11.2018


Ответы (1)


Как насчет того, чтобы изменить условие? Вместо count < N_ITER/FREQ используйте count*FREQ < N_ITER. Если FREQ = 0, выражение все равно будет истинным.

int N_ITER = 1000;
int FREQ = 5;

void doRun() {
    int count = 0;
    for (int i = 0; i < N_ITER; ++i) {
        if (count*FREQ < N_ITER) {
            doSomething();
            count++;
        } else {
            doSomethingElse();
            count = 0;
        }
    }
}
person Nelfeal    schedule 03.11.2018
comment
Однако это может вызвать другой тип UB из-за переполнения целого числа со знаком. - person user7860670; 03.11.2018
comment
@VTT Ну, все зависит от максимального значения N_ITER+FREQ, которое далеко не достаточно большое значение в примере OP. Кроме того, тип всегда можно изменить на что-то большее, например unsigned long. - person Nelfeal; 03.11.2018