Как написать булеву функцию C ++, которая n раз использует троичное выражение условия? - PullRequest
0 голосов
/ 26 октября 2018

У меня очень простой вопрос, я очень смущен тем, как я могу это реализовать. Я хочу создать логическую переменную в одну строку, состоящую из тернарного оператора, например:

логический = а? b: (c? d: (e? f: (g? i: j);

Это работает для 1, 2 или 3 таких сложных условий для целей моих кодов, но я должен написать это так, чтобы я мог выбрать, сколько таких троичных условий я хочу поместить друг в друга, чтобы определить логическое значение переменная.

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

Условие не является полностью независимым друг от друга, существуют интервалы (координаты в пространстве), которые каким-то образом следуют друг за другом. Так, например, «a» в моем примере было бы что-то вроде 11, а затем продолжалось бы, когда оно ложно, с новым условием, говоря 22 и так далее. Отсюда и моя идея ввести какой-то счетчик в условия.

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

Я пытаюсь что-то вроде:

bool f(double x, double value, double z, double d, double n, double step, int &count);{
         bool result;
         count++;
         if (count == n) {return result}
         result = (x >=value+count*step  && x<value+(count+1)*step) ? z>=d : f(x,value,z,d,n,step, &count);
   }

Так что, конечно, помимо многих ошибок в написании рекурсивной функции, поскольку я никогда не использую их и обычно не использую C или C ++, может показаться, что при последнем вызове функции мы будем иметь что-то вроде? b: без последнего параметра, если утверждение ложно.

Я старался быть настолько ясным, насколько мог. Вы можете задавать вопросы, если не поняли. И любая помощь приветствуется, рекурсивные функции, нормальные функции или способ сделать это вообще без функции ...

С уважением и заранее спасибо за ваши ответы!

Edit:

Код с if должен выглядеть примерно так:

if (a){
    b}
else{
    if (c){
        d}
    else{
        if(e){
           f}
        else{
           if(g){
              I}
           else{
              j}

Возможно, я забыл некоторые скобки, но я надеюсь, что это понятно. И этот момент заключается в том, чтобы продолжить, скажем, n, если подобные операторы в одной строке создать булеву переменную, а затем иметь возможность выбирать n вместо переписывания нового кода каждый раз, когда я хочу добавить оператор if.

РЕДАКТИРОВАТЬ о рекурсии:

Может кто-нибудь объяснить мне, почему такая функция создает бесконечный цикл?

bool f(double x, double l, double z, double d,  double step, int &count){
         int  n = (int)l/step;\\number of steps
         count++;
         if (count <  n)
                return  (x >=l+count*step  && x<l+(count+1)*step) ? z>=d*count : f(x,l,z,d,step,count);

         else               
                return z>=d*(count-1);
   }

Я установил счетчик 'count' в -1 перед вызовом функции, и это, похоже, является проблемой. Он делает цикл правильно, но затем перезапускается снова и снова, так что я даже не могу проверить, имеет ли мой код смысл для моей цели. Я думал, что после каждого возврата, вызывающего функцию рекурсивно, это увеличивает счетчик, но как только он достигает n, он должен возвращать что-то еще и выходить из функции, а не перезапускать счетчик и делать все снова ...

Ответы [ 3 ]

0 голосов
/ 27 октября 2018

Удобочитаемость и эффективность

Дело в том, что я не хочу, чтобы мой код был элегантным или читабельным, но эффективным.

Честно,Я думаю, что это не очень хорошая стратегия.Неэффективный код не элегантен.Это, конечно, не означает, что читаемый код автоматически эффективен.Однако гораздо проще случайно не допустить, чтобы компилятор выполнил оптимизацию, вместо того, чтобы заставить его генерировать лучший код, чем он это делает в любом случае.Читаемый код содержит меньше ошибок и помогает избежать очевидной неэффективности.При этом, ...

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

Помимо читабельности, есть еще одна вещь, которую следует учитывать: короткое замыкание.С простым условным условием

bool x = condition ? t : some_other_function_call();

в случае, если condition равно true, some_other_function_call() не будет оцениваться, тогда как в

bool x = foo(t,some_other_function_call());

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

Что делать вместо этого?

Ответ Пита Беккера наглядно демонстрирует, как правильно написать условия (наиболее важно, что вам не нужно вкладыватьслучаи, когда они взаимоисключающие (они для троичного!)).

Как бы то ни было ... как можно написать условную функцию с переменными числами?

Просто для полноты, вот как можно написать такую ​​функцию для замены bool x = a ? b : (c ? d : (e ? f : (g ? i : j ); с помощью вызова функции (пожалуйста, не надо):

// DISCLAIMER: DONT DO THIS
bool my_conditional(std::vector<bool> x){
    if (x.size() == 1) return *x.begin();
    bool condition = *x.begin();
    bool true_value = *(x.begin()+1);
    return condition ? true_value : my_ternary({x.begin()+2,x.end()});
}

Вы можете назвать это так:

my_conditional({ condition1, true_value1, condition2, true_value2, false_value});

например

std::cout << my_conditional({false,false,false,false,false});

печать 0.

0 голосов
/ 27 октября 2018

[4-й вариант ответа, с учетом комментариев]

В частном случае из первого предоставленного простого примера можно написать переменную функцию.Здесь параметр template ... args указывает переменное количество параметров.Можно вызвать f (false, false, true) или f (false, false, false, true, true) или несколько параметров.

bool ff(bool a, bool b, bool c) {
    return a ? b : c;
}
template<class ...Args>
bool ff(bool a, bool b, Args ...args){
    return a ? b : ff(args...);
}

Как упомянуло user463035818, существует риск короткого замыкания в этом первом вызове функции ff (.) (По основному), когда все логические значения могут быть оценены во время этого первого вызова.Я не знаю, что на самом деле произойдет с оптимизацией компилятором, с возможными встраиванием и развертыванием, но подчеркивать компилятор бесполезно.

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

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

#include    <iostream>

   bool f(double x, double xmin, double range, double z, double d,  double step, int &count){
         int  n = range/step;   //number of steps
         count++;
         if (count <  n) {
             double a = xmin + count*step;
             return  ((x >=a)  && (x< a + step)) ? z>=d*count : f(x,xmin,range,z,d,step,count);
        } else               
             return z>=d*(count-1);
   }

  int main () {
      int count = -1;
      double xmin = 0.0;
      double x = 2.0;
      double range = 4.0;
      double step = 1.0;
      double d = 1.0;
      double z = 2.0;
      bool test = f (x, xmin, range, z, d, step, count);
      std::cout << "test = " << test << "\n";
      std::cout << "count = " << count << "\n";
      return 0;
  }

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

0 голосов
/ 26 октября 2018

Чтобы написать эту if ... else if лестницу более четко, избавьтесь от скобок и избавьтесь от отступа.Вот так:

if (a)
    boolean = b;
else if (c)
    boolean = d;

и так далее.Но я был бы склонен написать это как функцию:

if (a)
    return b;
else if (c)
    return d;

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

boolean = a ? b
    : c ? d
    : e ? f
    : g;
...