【问题标题】:Roll over counter skipping zero翻转计数器跳过零
【发布时间】:2018-02-06 08:46:29
【问题描述】:

也许是一个简单的问题,但我无法理解它。

我正在做某种月份计数器,其想法是用户可以按 - 或 + 并仍然达到所需的月份: 例如我有: 今天是二月所以是这样的 用户按下 - 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 但我想摆脱零。 任何帮助将不胜感激:)

【问题讨论】:

  • SINT16 -> int16_t
  • a % b 是介于 0b-1 之间的数字。如果你想要一个介于1b 之间的数字,你会怎么做?
  • 如果你想跳过零,if 条件减一。如果你更正了,你就不必尴尬地添加12 + 1
  • molbdnilo - 你能举个例子吗
  • @Metio_1993 如果我给你一个 0 到 11 之间的数字,你可以很容易地把它变成 1 到 12 之间的数字。你怎么做到的?

标签: c counter monthcalendar


【解决方案1】:

这个问题很不清楚,但我会试试

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 不应包含在模函数中

【讨论】:

    【解决方案2】:

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

    【讨论】:

      【解决方案3】:

      通过仔细选择比较,您可以简化'%' 的使用。不是检查month = 12month &lt; 0,而是检查增量是否导致month &gt; 12month &lt; 1。这些是需要滚动到112 的点。

      例如,在将月份增加/减少某个值chg 的通用函数中,您只需将chg 添加到当前月份,然后应用测试,使用month = month % 12 更正month &gt; 12 或通过设置month = month + 12 where month &lt; 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
      

      查看一下,如果您还有其他问题,请告诉我。

      【讨论】:

        【解决方案4】:

        我的建议是在代码内部将月份计数器保持为 [0, 11] 格式,使用 modulo(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];
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-03-14
          • 1970-01-01
          • 2022-07-04
          • 1970-01-01
          • 2022-12-02
          • 1970-01-01
          相关资源
          最近更新 更多