翻转计数器跳零
Roll over counter skipping zero
也许是一个简单的问题,但我无法理解它。
我正在做某种月份计数器,想法是用户可以按 - 或 + 并仍然达到所需的月份:
例如我有:
今天是二月所以像这样
用户按 -
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
但我想摆脱零。
任何帮助将不胜感激:)
如果 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;
}
问题很不清楚,我试试看
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 不应包含在模函数中
通过仔细选择比较,您可以简化 '%'
的使用。不是检查 month = 12
或 month < 0
,而是检查增量是否导致 month > 12
或 month < 1
。这些是需要滚动到 1
或 12
的点。
例如,在按某个值 chg
递增/递减月份的通用函数中,您只需将 chg
添加到当前月份,然后应用测试,使用 [=22] 进行更正=] where month > 12
或通过设置 month = month + 12
where 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;
}
例子Use/Output
$ ./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
检查一下,如果您还有其他问题,请告诉我。
我的建议是在代码内部以 [0, 11] 格式保留您的月份计数器,使用 modulo(12) 环绕。这很简单,并且易于理解代码。
然后编写一个函数,将内部表示 [0, 11] 映射到用户希望看到的内容,即 [1, 12],无论何时打印或以某种方式向用户显示值。
int16_t display_month(int16_t month)
{
return month + 1;
}
在这种情况下,return 月 + 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];
}
也许是一个简单的问题,但我无法理解它。
我正在做某种月份计数器,想法是用户可以按 - 或 + 并仍然达到所需的月份: 例如我有: 今天是二月所以像这样 用户按 - 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 但我想摆脱零。 任何帮助将不胜感激:)
如果 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;
}
问题很不清楚,我试试看
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 不应包含在模函数中
通过仔细选择比较,您可以简化 '%'
的使用。不是检查 month = 12
或 month < 0
,而是检查增量是否导致 month > 12
或 month < 1
。这些是需要滚动到 1
或 12
的点。
例如,在按某个值 chg
递增/递减月份的通用函数中,您只需将 chg
添加到当前月份,然后应用测试,使用 [=22] 进行更正=] where month > 12
或通过设置 month = month + 12
where 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;
}
例子Use/Output
$ ./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
检查一下,如果您还有其他问题,请告诉我。
我的建议是在代码内部以 [0, 11] 格式保留您的月份计数器,使用 modulo(12) 环绕。这很简单,并且易于理解代码。 然后编写一个函数,将内部表示 [0, 11] 映射到用户希望看到的内容,即 [1, 12],无论何时打印或以某种方式向用户显示值。
int16_t display_month(int16_t month)
{
return month + 1;
}
在这种情况下,return 月 + 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];
}