Определение того, является ли число кратным десяти или находится в пределах определенного набора диапазонов


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

мне нужно

if (num is a multiple of 10) { do this }

if (num is within 11-20, 31-40, 51-60, 71-80, 91-100) { do this }
else { do this } //this part is for 1-10, 21-30, 41-50, 61-70, 81-90

Это для настольной игры змеи и лестницы, если это имеет больше смысла для моего вопроса.

Я предполагаю, что первое утверждение if мне нужно будет использовать модуль, будет if (num == 100%10) быть правильным?

второй я понятия не имею. Я могу написать это как if (num > 10 && num is < 21 || etc) но там должно быть что-то умнее.

14 105

14 ответов:

для первого, чтобы проверить, если число кратно использования:

if (num % 10 == 0) // its divisible by 10

второй:

if(((num - 1) / 10) % 2 == 1 && num <= 100)

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


Теперь, когда вы дали лучшее представление о том, что вы делаете, я напишу второй:
   int getRow(int num) {
      return (num - 1) / 10;   
   }

   if (getRow(num) % 2 == 0) {
   }

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

если (число кратно 10) { сделай это }

if (num % 10 == 0) {
  // Do something
}

если (num находится внутри 11-20, 31-40, 51-60, 71-80, 91-100) { сделай это }

фокус здесь в том, чтобы искать какую-то общность среди диапазонов. Конечно, вы всегда можете использовать метод "грубой силы":

if ((num > 10 && num <= 20) ||
    (num > 30 && num <= 40) ||
    (num > 50 && num <= 60) ||
    (num > 70 && num <= 80) ||
    (num > 90 && num <= 100)) {
  // Do something
}

но вы можете заметить, что, если вычесть 1 С num, вы будете иметь диапазоны:

10-19, 30-39, 50-59, 70-79, 90-99

другими словами, все 2-значные числа, первая цифра которых нечетна. Далее, вам нужно придумать формулу, которая выражает это. Вы можете получить первую цифру, разделив на 10, и вы можете проверить, что это нечетно, проверив остаток от 1, Когда вы делите на 2. Складывая все это вместе:

if ((num > 0) && (num <= 100) && (((num - 1) / 10) % 2 == 1)) {
  // Do something
}

учитывая компромисс между более длинным, но поддерживаемым кодом и более коротким "умным" кодом, я бы выбрал более длинный и четкий каждый раз. По крайней мере, если вы пытаетесь быть умным, пожалуйста, включите комментарий, который объясняет именно то, что вы пытаетесь достичь.

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

Если вы используете GCC или любой компилятор, который поддерживает Случае Диапазоны вы можете сделать это, но ваш код будет не будет

switch(num)
{
case 11 ... 20:
case 31 ... 40:
case 51 ... 60:
case 71 ... 80:
case 91 ... 100:
    // do something
    break;
default:
    // do something else
    break;
}

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

template<typename It, typename Elem>
bool in_any_interval(It first, It last, const Elem &val) {
    return std::any_of(first, last, [&val](const auto &p) {
        return p.first <= val && val <= p.second;
    });
}

для простоты я использовал полиморфную лямбду (C++14) вместо явного

Первый легко, вам просто нужно применить оператор по модулю к вашему значению num:

if ( ( num % 10 ) == 0)

поскольку c++ оценивает каждое число, которое не равно 0, как true, вы также можете написать:

if ( ! ( num % 10 ) )  //does not have a residue when devided by 10

для второго я думаю, что это чище, чтобы понять:

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

чтобы получить их тоже, просто используйте num-1 или лучше num+19, Чтобы не иметь дело с отрицательными числами.

if ( ( ( num + 19 ) % 20 ) > 9 )

это предполагает, что шаблон повторяется навсегда, поэтому для 111-120 он будет применяться снова, и так далее. В противном случае вам нужно ограничить число до 100:

if ( ( ( ( num + 19 ) % 20 ) > 9 ) && ( num <= 100 ) )

С парой хороших комментариев в коде, он может быть написан довольно лаконично и читабельно.

// Check if it's a multiple of 10
if (num % 10 == 0) { ... }

// Check for whether tens digit is zero or even (1-10, 21-30, ...)
if ((num / 10) % 2 == 0) { ... }
else { ... }

вы в основном объяснили ответ сами, но вот код на всякий случай.

if((x % 10) == 0) {
  //do this
}
if((x > 10 && x < 21) || (x > 30 && x < 41) || (x > 50 && x < 61) || (x > 70 && x < 81) || (x > 90 && x < 101)) {
  //do this
}

вы, возможно, слишком много думаете об этом.

if (x % 10)
{
   .. code for 1..9 ..
} else
{
   .. code for 0, 10, 20 etc.
}

первая строка if (x % 10) работает, потому что (а) значение, кратное 10 вычисляется как '0', другие числа приводят к их остатку, (б) значение 0 в if является false, любое другое значение true.

Edit:

чтобы переключаться туда-сюда в двадцатые годы, используйте тот же трюк. На этот раз ключевое число -10:

if (((x-1)/10) & 1)
{
  .. code for 10, 30, ..
} else
{
   .. code for 20, 40, etc.
}

x/10 возвращает любое число от 0 до 9, а 0, от 10 до 19 как 1 и так далее. Тестирование по четным или нечетным-в & 1 -- говорит вам, если это четное или нечетное. Поскольку ваши диапазоны на самом деле" 11 до 20", вычесть 1 перед тестированием.

просьба о читаемости

это должно обернуть любые "умные" операторы в функцию, которая точно показывает (с ее именем), что она делает. В то время как есть незначительное влияние на производительность (от "function calling overhead") это действительно незначительно в такой игровой ситуации.

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

#include <stdio.h>

enum {NO, YES, WINNER};
enum {OUT_OF_RANGE=-1, ODD, EVEN};

int notInRange(int square) {
  return(square < 1 || square > 100)?YES:NO;
}

int isEndOfRow(int square) {
  if (notInRange(square)) return OUT_OF_RANGE;
  if (square == 100) return WINNER; // I am making this up...
  return (square % 10 == 0)? YES:NO;
}

int rowType(unsigned int square) {
  // return 1 if square is in odd row (going to the right)
  // and 0 if square is in even row (going to the left)
  if (notInRange(square)) return OUT_OF_RANGE; // trap this error
  int rowNum = (square - 1) / 10;
  return (rowNum % 2 == 0) ? ODD:EVEN; // return 0 (ODD) for 1-10, 21-30 etc.
                                       // and 1 (EVEN) for 11-20, 31-40, ...
}

int main(void) {
  int a = 12;
  int rt;
  rt = rowType(a); // this replaces your obscure if statement

  // and here is how you handle the possible return values:
  switch(rt) {
  case ODD:
    printf("It is an odd row\n");
    break;
  case EVEN:
    printf("It is an even row\n");
    break;
  case OUT_OF_RANGE:
    printf("It is out of range\n");
    break;
  default:
    printf("Unexpected return value from rowType!\n");
  }

  if(isEndOfRow(10)==YES) printf("10 is at the end of a row\n");
  if(isEndOfRow(100)==WINNER) printf("We have a winner!\n");
}

первый:

if (x % 10 == 0)

применяется для:

10, 20, 30, .. 100 .. 1000 ...

второй:

if (((x-1) / 10) % 2 == 1)

применяется для:

11-20, 31-40, 51-60, ..

мы в основном сначала делают x-1 для:

10-19, 30-39, 50-59, ..

затем мы делим их на 10 для:

1, 3, 5, ..

поэтому мы проверяем, если этот результат является нечетным.

вы можете попробовать следующее:

        // multiple of 10
        if ((num % 10) == 0)
        {
           // Do something
        }
        else if (((num / 10) % 2) != 0)
        {
            //11-20, 31-40, 51-60, 71-80, 91-100
        }
         else
        {
            //other case
        }

где это может помочь в создании вашей программы более гибкой, в случае, если вы решите позже, что вы хотите версию малыша игры на 6 х 6 борту, или расширенную версию (что вы можете играть всю ночь напролет) на 40 х 50 борту.

поэтому я бы закодировал его как следует:

// What is the size of the game board?
#define ROWS            10
#define COLUMNS         10

// The numbers of the squares go from 1 (bottom-left) to (ROWS * COLUMNS)
// (top-left if ROWS is even, or top-right if ROWS is odd)
#define firstSquare     1
#define lastSquare      (ROWS * COLUMNS)
// We haven't started until we roll the die and move onto the first square,
// so there is an imaginary 'square zero'
#define notStarted(num) (num == 0)
// and we only win when we land exactly on the last square
#define finished(num)   (num == lastSquare)
#define overShot(num)   (num > lastSquare)

// We will number our rows from 1 to ROWS, and our columns from 1 to COLUMNS
// (apologies to C fanatics who believe the world should be zero-based, which would
//  have simplified these expressions)
#define getRow(num)   (((num - 1) / COLUMNS) + 1)
#define getCol(num)   (((num - 1) % COLUMNS) + 1)

// What direction are we moving in?
// On rows 1, 3, 5, etc. we go from left to right
#define isLeftToRightRow(num)    ((getRow(num) % 2) == 1)
// On rows 2, 4, 6, etc. we go from right to left
#define isRightToLeftRow(num)    ((getRow(num) % 2) == 0)

// Are we on the last square in the row?
#define isLastInRow(num)    (getCol(num) == COLUMNS)

// And finally we can get onto the code

if (notStarted(mySquare))
{
  // Some code for when we haven't got our piece on the board yet
}
else
{
  if (isLastInRow(mySquare))
  {
    // Some code for when we're on the last square in a row
  }


  if (isRightToLeftRow(mySquare))
  {
    // Some code for when we're travelling from right to left
  }
  else
  {
    // Some code for when we're travelling from left to right
  }
}

Да, это многословно, но это дает понять, что именно происходит на игровом поле.

Если бы я разрабатывал эту игру для отображения на телефоне или планшете, я бы сделал переменные строк и столбцов вместо констант, чтобы они могли быть установлены динамически (в начале игры), чтобы соответствовать размеру экрана и ориентации. Я бы также позволил изменить ориентацию экрана в любое время, в середине игры - все, что вам нужно сделать, это переключить значения строк и столбцов, в то время как оставляя все остальное (текущее квадратное число, на котором находится каждый игрок, и начальные/конечные квадраты всех змей и лестниц) без изменений. Затем вы "просто" должны красиво нарисовать доску и написать код для своей анимации (я предполагаю, что это было целью вашего if заявления) ...

Я знаю, что на этот вопрос есть так много ответов, но я все равно брошу свой здесь... Взято из кода Стива Макконнелла полное 2-е издание: "Лестнично-Ступенчатые Таблицы Доступа:
Еще одним видом доступа к столу является лестнично-ступенчатый метод. Этот метод доступа не таков прямая, как структура индекса, но она не тратит столько места для данных. Общая идея ступенчатые структуры, показано на рис. 18-5, заключается в том, что записи в таблицы действительны для диапазонов данных, а не для различных данные точки. enter image description here

рисунок 18-5 лестнично-ступенчатый подход классифицирует каждую запись, определяя уровень на который он попадает в " лестницу."Шаг, на который он попадает, определяет его категорию.

например, если вы пишете программу оценивания, диапазон ввода "B" может быть от 75 до 90 процентов. Вот диапазон оценок, которые вам, возможно, придется когда-нибудь программировать: enter image description here

чтобы использовать метод stair-step, вы помещаете верхний конец каждого диапазона в таблицу и затем напишите цикл, чтобы проверить счет против верхнего конца каждого диапазона. Когда вы найдете точка, в которой оценка сначала превышает верхнюю часть диапазона, вы знаете, что оценка есть. С методом лестнич-шага, вы должны быть осторожны отрегулировать конечные точки диапазоны правильно. Вот код в Visual Basic, который присваивает оценки группе stu- вмятины на основе этого примера:

enter image description here

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

код полный 2-е издание страницы 426-428 (Глава 18). Надеюсь, это поможет и извините, что я не преобразовал код в c++, но вы знаете, что старая китайская поговорка: "Не давайте рыбу нищему, дайте ему удочку!":)

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

ответ ООП вашего кода здесь:

(Я надеюсь, что вы будете писать свои коды объектно-ориентированные в следующем году)

enter image description here

#include <iostream>
#include <exception>
#include <stdexcept>

using namespace std;

class checker
{
public:

    checker(void)
        : m_num(0)
    {
        // Nothing.
    }

    ~checker(void)
    {
        // Nothing.
    }

    inline void set_num(int num)
    {
        if (num < 0)
        {
            throw invalid_argument("Invalid argument: num.");
        }

        m_num = num;
        return;
    }

    inline int get_num(void) const
    {
        return m_num;
    }

protected:

    int m_num;
};

/**********************************************************/

class multiple_checker
    : public checker
{
public:

    static const int MULTIPLE_OF = 10;

    multiple_checker(void)
    {
        // Nothing.
    }

    ~multiple_checker(void)
    {
        // Nothing.
    }

    virtual void do_this_for_multiple_checker(void) = 0;

    void check_multiple_of(void)
    {
#if defined _DEBUG
        if (MULTIPLE_OF == 0)
        {
            throw exception("MULTIPLE_OF should not be zero.");
        }
#endif
        if (m_num % MULTIPLE_OF == 0)
        {
            do_this_for_multiple_checker();
        }
        return;
    }
};

/**********************************************************/

class range_checker
    : public checker
{
public:

    range_checker(void)
    {
        // Nothing.
    }

    ~range_checker(void)
    {
        // Nothing.
    }

    virtual void do_this_1_for_range_checker(void) = 0;

    virtual void do_this_2_for_range_checker(void) = 0;

    void check_in_range(void)
    {
        return;
    }

    void check_range(void)
    {
        if (is_in_range())
        {
            do_this_1_for_range_checker();
        }
        else
        {
            do_this_2_for_range_checker();
        }
    }

private:

    bool is_in_range(void) const
    {
        if
        (
               (m_num > 10 && m_num < 21)
            || (m_num > 30 && m_num < 41)
            || (m_num > 50 && m_num < 61)
            || (m_num > 70 && m_num < 81)
            || (m_num > 90 && m_num < 101)
        )
        {
            return true;
        }
        else
        {
            return false;
        }
    }
};

/**********************************************************/

class game
    : public multiple_checker, public range_checker
{
public:

    game(void)
    {
        // Nothing.
    }

    ~game(void)
    {
        // Nothing.
    }

    virtual void do_this_for_multiple_checker(void)
    {
        cout << "Number is a multiple of " << MULTIPLE_OF << "." << endl;
    }

    virtual void do_this_1_for_range_checker(void)
    {
        cout << "Number is in range." << endl;
    }

    virtual void do_this_2_for_range_checker(void)
    {
        cout << "Number is not in range." << endl;
    }
};

/**********************************************************/

int main(int argc, char* argv[])
{
    game* g = new game();

    g->multiple_checker::set_num(50);
    g->range_checker::set_num(13);

    g->check_multiple_of();

    g->check_range();

    delete g;
    g = NULL;

    return 0;
}