Перевернуть счетчик, пропуская ноль

Может быть, простой вопрос, но я не могу уложиться в голове.

Я делаю какой-то счетчик месяцев, идея в том, что пользователь может нажать - или + и все равно достичь нужного месяца: например, у меня: Сегодня февраль, так что-то вроде этого Пользователь нажимает - 2 1 12 11 10 9 ...... Некоторые идут для + Проблема в том, что я не хочу, чтобы отображался ноль

SINT16 tempVal = pDate->month + upDown;
    if (tempVal < 0) {
        tempVal += (12+1);
    } 
    pDate->month % (12 + 1);

Это то, что я придумал - оно перекатывается через 12, а затем 0 или 1 0 12 Но я хочу избавиться от нуля. Любая помощь будет оценена :)


person Metio_1993    schedule 06.02.2018    source источник
comment
a % b — это число между 0 и b-1. Если бы вы хотели число между 1 и b, что бы вы сделали?   -  person molbdnilo    schedule 06.02.2018
comment
Если вы хотите пропустить ноль, условное выражение if отключается на единицу. Если вы это исправите, вам не придется неловко добавлять 12 + 1.   -  person DevSolar    schedule 06.02.2018
comment
Молбднило - можешь привести пример   -  person Metio_1993    schedule 06.02.2018
comment
@ Metio_1993 Если я дам вам число от 0 до 11, вы легко сможете превратить его в число от 1 до 12. Как вы можете это сделать?   -  person molbdnilo    schedule 06.02.2018
comment
@Metio_1993 Metio_1993 И если m не является отрицательным, m % 12 - это число от 0 до 11, так что ... (Вы были почти там.)   -  person molbdnilo    schedule 06.02.2018


Ответы (4)


Вопрос очень непонятный, но я попробую

SINT16 tempVal = pDate->month + upDown;
if (tempVal < 0) {
    /* if you are at negative 1 - assuming upDown is either (1,-1) */
    tempVal += (12); //just add the cycle value
} 

//pDate->month % (12 + 1);
pDate->month = (pDate->month % 12) + 1;//modulo by the cycle and then shift output

чтобы быть ясным по модулю 12 будут выведены значения (0 - 11), поэтому +1 не следует включать в функцию по модулю

person Omer Dagan    schedule 06.02.2018

если tempVal становится равным нулю, то примите месяц равным 12, в противном случае увеличьте его на 1:

SINT16 tempVal = pDate->month + upDown;
    if (tempVal == 0) {
        pDate->month = 12;
    }//if month becomes more than 12,ie 13
    else if(tempVal %12 == 1)
    {
       pData->month = 1;
    }
    else
    {
        pDate->month = tempVal;
    }
person Paresh Dhandhukiya    schedule 06.02.2018

Тщательно выбирая сравнения, вы можете упростить использование '%'. Вместо того, чтобы проверять, является ли month = 12 или month < 0, проверьте, вызывает ли приращение month > 12 или month < 1. Это те точки, где требуется бросок на 1 или 12.

Например, в общей функции для увеличения/уменьшения месяца на некоторое значение chg вы просто добавляете chg к текущему месяцу, а затем применяете тест, исправляя month = month % 12, где month > 12, или устанавливая month = month + 12, где month < 1, например:

int monthchg (int *m, int chg)
{
    *m += chg;

    if (*m > 12)        /* if month > 12, roll to month % 12 */
        *m = *m % 12;
    else if (*m < 1)    /* if month < 1, add 12 to month */
        *m += 12;

    return *m;
}

Краткий пример, который переводит клавиатуру в неканонический или необработанный режим и принимает +/- вводов для изменения месяца или q для выхода, может быть следующим:

#include <stdio.h>
#include <termios.h>

typedef struct {
    struct termios old;     /* orig keyboard settings   */
    struct termios new;
} kbmode;

kbmode *setkbmode (kbmode *k);
kbmode *restorekbmode (kbmode *k);

int monthchg (int *m, int chg)
{
    *m += chg;

    if (*m > 12)        /* if month > 12, roll to month % 12 */
        *m = *m % 12;
    else if (*m < 1)    /* if month < 1, add 12 to month */
        *m += 12;

    return *m;
}

int main (void) {

    kbmode kb = { .old = {0} };
    int dir, month = 6;

    setkbmode (&kb);        /* set kbd in raw-unbufered mode */

    printf ("enter +/- to inc/decrement month ('q' to quit)\n");
    for (;;) {
        printf ("\n  month : %2d : ", month);
        fflush (stdout);
        dir = getchar();

        if (dir == '+')
            monthchg (&month, 1);
        else if (dir == '-')
            monthchg (&month, -1);
        else if (dir == 'q')
            break;
        else
            puts ("invalid input - try again.");
    }
    putchar ('\n');

    restorekbmode (&kb);    /* restore original kbd settings */

    return 0;
}

/* set keyboard in raw-unbufered mode */
kbmode *setkbmode (kbmode *k)
{
    if (tcgetattr (0, &(k->old))) { /* save orig settings   */
        fprintf (stderr, "setkbmode() error: tcgetattr failed.\n");
        return NULL;
    }   /* copy old to new */
    k->new = k->old;

    k->new.c_lflag &= ~(ICANON);  /* new kbd flags */
    k->new.c_cc[VTIME] = 0;
    k->new.c_cc[VMIN] = 1;
    if (tcsetattr (0, TCSANOW, &(k->new))) {
        fprintf (stderr, "setkbmode() error: tcgetattr failed.\n");
        return NULL;
    }

    return k;
}

kbmode *restorekbmode (kbmode *k)
{
    /* reset original keyboard  */
    if (tcsetattr (0, TCSANOW, &(k->old))) {
        fprintf (stderr, "restorekbmode() error: tcsetattr failed.\n");
        return NULL;
    }

    return k;
}

Пример использования/вывода

$ ./bin/month_roll
enter +/- to inc/decrement month ('q' to quit)

  month :  6 : -
  month :  5 : -
  month :  4 : -
  month :  3 : -
  month :  2 : -
  month :  1 : -
  month : 12 : -
  month : 11 : -
  month : 10 : +
  month : 11 : +
  month : 12 : +
  month :  1 : +
  month :  2 : -
  month :  1 : -
  month : 12 : -
  month : 11 : -
  month : 10 : +
  month : 11 : +
  month : 12 : +
  month :  1 : +
  month :  2 : +
  month :  3 : q

Просмотрите все и дайте мне знать, если у вас есть дополнительные вопросы.

person David C. Rankin    schedule 06.02.2018

Мое предложение состояло бы в том, чтобы сохранить ваш счетчик месяцев в формате [0, 11] внутри кода, используя модуль (12) для переноса. Это просто и облегчает понимание кода. Затем напишите функцию для сопоставления этого внутреннего представления [0, 11] с тем, что пользователь хотел бы видеть, например [1, 12], всякий раз, когда вы печатаете или каким-либо образом отображаете значение для пользователя.

int16_t display_month(int16_t month)
{
    return month + 1;
}

В этом случае очень просто вернуть месяц + 1, но в более общем случае сопоставления количества N с чем-то, что не соответствует [0, N-1], я бы использовал массив для хранения этого сопоставления. Таким образом, отображение действительно может быть чем угодно, оно не должно быть упорядоченным и событие не должно быть целым числом.

int16_t display_month(int16_t month)
{
    static int16_t index_to_month_map[] = {1,2,3,4,5,6,7,8,9,10,11,12}; 
    return index_to_month_map[month];
}
person noizebox    schedule 06.02.2018