闰年 - 仅使用 C 中的算术运算符
leap year - by only using arithmetical operators in C
我有一个我见过的最奇怪的练习:我必须通过在控制台中扫描年份来找到闰年,并控制它是否是闰年。
我只能使用+ - / * %
作为算术运算符;我不允许使用任何其他运算符或函数。
这是我目前的情况:
int year = 0;
bool b = false;
printf ("Type in a year: ");
int helpVar = 1000;
for (int i = 0; i < 4; i++) {
year += (getchar() - '0') * helpVar;
helpVar = helpVar / 10;
}
b = (((year % 4) + (year % 100) + (year % 400)) + 1) % 2;
所以我不明白我在这里做错了什么。到目前为止它有效,唯一让我害怕的是“1900”年。它不应该是闰年,但根据我的代码似乎是闰年。
我在这里错过了什么?
根据上面的post,aleap year
的定义是:对于年份n
n
应该是4的倍数,可以表示为n % 4 == 0
n
是 400
的倍数或 n
不是 100
的倍数
问题是您不应该将所有这三个条件都写成 加法 操作。你应该把它们写成逻辑表达式。
在您的代码中:
b = (((year % 4) + (year % 100) + (year % 400)) + 1) % 2;
有3个条件,year % 4
,year % 100
和year % 400
,求值后有两种方法使b = true:
- 三个条件都不成立
- 只有一种情况是错误的
好吧,让我们说清楚
闰年定义:
n
是4的倍数而不是100的倍数
n
是 400 的倍数
所以你的代码可以是这样的:
int year;
if (year % 400) {
printf("Fine it's a leap year\n");
} else if (year % 100 == 0) {
printf("Oh no it's not a leap year\n");
} else if (yaer % 4 == 0) {
printf("It's a leap year\n");
} else {
printf("Not a leap year\n");
}
这是一种可能性(也许不是最短的——显然只适用于公历):
b = (((year-1)%4)+1)/4 - (((year-1)%100)+1)/100 + (((year-1)%400)+1)/400;
这个想法是 ((year-1) % n) + 1
等于 n
仅当 year
是 n
的倍数(对于正数 year
),并且小于n
否则。因此,如果将其除以 n
,当且仅当 (year % n == 0)
.
时,您会得到 1
如果 year%4==0
不成立,year%100==0
就不可能成立,因此您可以将其相互减去,但在末尾添加 year%400==0
项。
问题是您的 %
运算是在 整数 算术中完成的,因此,它们的结果很可能是 0
以外的值或1
。但是,如果您将每个结果都转换为 bool
类型(假设在 <stdbool.h>
header 中定义),那么您的公式将起作用:
b = (((bool)(year % 4) + (bool)(year % 100) + (bool)(year % 400)) + 1) % 2;
我对您的代码所做的唯一修改是在每个 %
操作的结果上添加 (bool)
转换。
编辑:正如评论中所指出的,上述解决方案'breaks the rules' 通过使用转换运算符。以下修改也有效(以类似的方式),但它在每个 %
结果上使用 !
运算符(两次);这也违反了规则,但对后代来说可能是件好事:
b = ((!!(year % 4) + !!(year % 100) + !!(year % 400)) + 1) % 2;
仅使用 隐式 到 bool
类型转换(因此不使用强制转换运算符)的此解决方案的修改似乎符合规则。这可以使用 temporary/intermediate 变量来保存每个 %
操作的结果:
bool four = year % 4, hundred = year % 100, fourhund = year % 400;
b = (four + hundred + fourhund + 1) % 2;
或者,您可以 pre-declare 三个中间 bool
变量,然后进行隐式类型转换 'inline',如下所示:
bool m4, m100, m400; // You could also move this to where you declare "b"
b = (((m4 = year % 4) + (m100 = year % 100) + (m400 = year % 400)) + 1) % 2;
我有一个我见过的最奇怪的练习:我必须通过在控制台中扫描年份来找到闰年,并控制它是否是闰年。
我只能使用+ - / * %
作为算术运算符;我不允许使用任何其他运算符或函数。
这是我目前的情况:
int year = 0;
bool b = false;
printf ("Type in a year: ");
int helpVar = 1000;
for (int i = 0; i < 4; i++) {
year += (getchar() - '0') * helpVar;
helpVar = helpVar / 10;
}
b = (((year % 4) + (year % 100) + (year % 400)) + 1) % 2;
所以我不明白我在这里做错了什么。到目前为止它有效,唯一让我害怕的是“1900”年。它不应该是闰年,但根据我的代码似乎是闰年。
我在这里错过了什么?
根据上面的post,aleap year
的定义是:对于年份n
n
应该是4的倍数,可以表示为n % 4 == 0
n
是400
的倍数或n
不是100
的倍数
问题是您不应该将所有这三个条件都写成 加法 操作。你应该把它们写成逻辑表达式。
在您的代码中:
b = (((year % 4) + (year % 100) + (year % 400)) + 1) % 2;
有3个条件,year % 4
,year % 100
和year % 400
,求值后有两种方法使b = true:
- 三个条件都不成立
- 只有一种情况是错误的
好吧,让我们说清楚
闰年定义:
n
是4的倍数而不是100的倍数n
是 400 的倍数
所以你的代码可以是这样的:
int year;
if (year % 400) {
printf("Fine it's a leap year\n");
} else if (year % 100 == 0) {
printf("Oh no it's not a leap year\n");
} else if (yaer % 4 == 0) {
printf("It's a leap year\n");
} else {
printf("Not a leap year\n");
}
这是一种可能性(也许不是最短的——显然只适用于公历):
b = (((year-1)%4)+1)/4 - (((year-1)%100)+1)/100 + (((year-1)%400)+1)/400;
这个想法是 ((year-1) % n) + 1
等于 n
仅当 year
是 n
的倍数(对于正数 year
),并且小于n
否则。因此,如果将其除以 n
,当且仅当 (year % n == 0)
.
1
如果 year%4==0
不成立,year%100==0
就不可能成立,因此您可以将其相互减去,但在末尾添加 year%400==0
项。
问题是您的 %
运算是在 整数 算术中完成的,因此,它们的结果很可能是 0
以外的值或1
。但是,如果您将每个结果都转换为 bool
类型(假设在 <stdbool.h>
header 中定义),那么您的公式将起作用:
b = (((bool)(year % 4) + (bool)(year % 100) + (bool)(year % 400)) + 1) % 2;
我对您的代码所做的唯一修改是在每个 %
操作的结果上添加 (bool)
转换。
编辑:正如评论中所指出的,上述解决方案'breaks the rules' 通过使用转换运算符。以下修改也有效(以类似的方式),但它在每个 %
结果上使用 !
运算符(两次);这也违反了规则,但对后代来说可能是件好事:
b = ((!!(year % 4) + !!(year % 100) + !!(year % 400)) + 1) % 2;
仅使用 隐式 到 bool
类型转换(因此不使用强制转换运算符)的此解决方案的修改似乎符合规则。这可以使用 temporary/intermediate 变量来保存每个 %
操作的结果:
bool four = year % 4, hundred = year % 100, fourhund = year % 400;
b = (four + hundred + fourhund + 1) % 2;
或者,您可以 pre-declare 三个中间 bool
变量,然后进行隐式类型转换 'inline',如下所示:
bool m4, m100, m400; // You could also move this to where you declare "b"
b = (((m4 = year % 4) + (m100 = year % 100) + (m400 = year % 400)) + 1) % 2;