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

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

Мне нужно -

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), но должно быть что-то умнее этого.

Ответ 1

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

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) {
   }

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

Ответ 2

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

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

if (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

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

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

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

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

Ответ 3

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

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;
}

Ответ 4

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

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;
    });
}

Для простоты я использовал полиморфную лямбду (С++ 14) вместо явного аргумента pair. Вероятно, это также должно быть связано с использованием < и == для соответствия стандартным алгоритмам, но оно работает так, пока Elem имеет <=, определенный для него. Во всяком случае, его можно использовать следующим образом:

std::pair<int, int> intervals[]{
    {11, 20}, {31, 40}, {51, 60}, {71, 80}, {91, 100}
};

const int num = 15;
std::cout << in_any_interval(std::begin(intervals), std::end(intervals), num);

Вот живой пример здесь.

Ответ 5

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

// Check if it 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 { ... }

Ответ 6

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

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
}

Ответ 7

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

if ( ( num % 10 ) == 0)

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

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

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

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

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

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

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

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

Ответ 8

Вы можете переусердствовать над этим.

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

Первая строка if (x % 10) работает, потому что (a) значение, которое кратно 10 вычисляется как '0', другие числа приводят к их остатку, (b) считается значение 0 в if t23 > , любое другое значение 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 перед тестированием.

Ответ 9

Подтверждение читаемости

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

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

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

#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");
}

Ответ 10

Для первого:

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, ..

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

Ответ 11

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

        // 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
        }

Ответ 12

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

Там, где это может помочь, это сделать вашу программу более гибкой, если позже вы решите, что вам нужна версия для малышей на доске 6 x 6 или расширенная версия (которую вы можете играть всю ночь) плата 40 x 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
  }
}

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

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

Ответ 13

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

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

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

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

enter image description here

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

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

Ответ 14

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

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

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

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;
}