1

我有这个疯狂的作业,我必须创建一个表达式来验证关于儒略历和公历以及许多其他东西的日期......

问题是它必须全部在一个表达式中,所以我不能使用任何;

是否有在表达式中定义变量的选项?就像是

d < 31 && (bool leapyear = y % 4 == 0) || (leapyear ? d % 2 : 3) ....

我可以在哪里定义和初始化一个或多个变量,并在一个表达式中使用它们而不使用任何;

编辑:明确地说,它必须是一个单行表达式。没有功能..

我现在这样做的方式是编写宏并扩展它们,所以我最终得到了这样的东西

#define isJulian(d, m, y) (y < 1751 || (y == 1752 && (m < 9) || (m == 9 && d <= 2)))
#define isJulianLoopYear(y) (y % 4 == 0)
#define isGregorian(d, m, y) (y > 1573 || (y == 1752 && (m > 9) || (m == 9 && d > 13)))
#define isGregorianLoopYear(y) ((y % 4 == 0) || (y % 400 = 0))
// etc etc ....

看起来这是解决问题的唯一合适方法

编辑:这是原始问题

假设我们有变量d my包含日、月和年。任务是编写一个表达式来决定日期是否有效。如果日期有效,则值应为真(非零值),如果日期无效,则应为假(零)。

这是一个表达式示例(正确的表达式看起来像这样):

d + 4 == y ^ 85 ? ~m : d * (y-2)

这些是错误答案的示例(不是表达式):

if ( log ( d ) == 1752 ) m = 1;

或者:

for ( i = 0; i < 32; i ++ ) m = m / 2;

仅提交仅包含一个表达式的文件,而不;在末尾。不要提交命令或整个程序。

  • 2.9.1752 之前是儒略历,之后是公历
  • 在儒略历中,闰年每年可被 4 整除。
  • 在公历中每年都是闰年,可以被 4 整除,但不能被 100 整除。可以被 400 整除的年份是另一个例外,是闰年。
  • 1800, 1801, 1802, 1803, 1805, 1806, ....,1899, 1900, 1901, ... ,2100, ..., 2200 不是循环年份。
  • 1896, 1904, 1908, ..., 1996, 2000, 2004, ..., 2396,..., 2396, 2400 是循环年
  • 1752 年 9 月是另一个例外,当 2.9.1752 之后是 14.9.1752 时,因此日期 3.9.1752、4.9.1752、...、13.9.1752 无效。
4

9 回答 9

6
((m >0)&&(m<13)&&(d>0)&&(d<32)&&(y!=0)&&(((d==31)&&
((m==1)||(m==3)||(m==5)||(m==7)||(m==8)||(m==10)||(m==12)))
||((d<31)&&((m!=2)||(d<29)))||((d==29)&&(m==2)&&((y<=1752)?((y%4)==0):
((((y%4)==0)&&((y%100)!=0))
||((y%400)==0)))))&&(((y==1752)&&(m==9))?((d<3)||(d>13)):true))
于 2009-10-03T04:32:39.583 回答
5

<evil> 如果您可以重用现有的,为什么要定义一个新的?errno是一个完美的临时变量。 </evil>

于 2009-10-05T10:43:19.740 回答
4

我认为作业的目的是要求您在不使用变量的情况下执行此操作,而您尝试做的事情可能会违背其目的。

于 2009-10-02T22:59:28.800 回答
3

在标准 C++ 中,这是不可能的。G++ 有一个称为语句表达式的扩展,可以做到这一点。

于 2009-10-02T22:52:32.100 回答
2

我不相信你可以,但即使你可以,它也只能在括号内定义它们(在你的例子中),并且不能在它们之外使用。

于 2009-10-02T22:52:50.693 回答
1

第一:不要。它可能很可爱,但即使有一个允许它的扩展,代码高尔夫也是一种危险的游戏,它几乎总是会导致比它解决的更多的悲伤。

好的,回到作业定义的“真实”问题。你能做额外的功能吗?如果是这样,不要在变量中捕获它是否是闰年,而是创建一个返回正确值的函数 isLeapYear(int year)。

是的,这意味着您将不止一次地计算它。如果这最终成为一个性能问题,我会感到非常惊讶......而且首先担心这个问题还为时过早。

如果您不允许编写函数作为这样做的一部分,我会感到非常惊讶。这似乎是这样一个练习的一半。

……

好的,这里是您需要做什么的快速概述。

首先,基本验证 - 月、日、年都是可能的值 - 月 0-11(假设从 0 开始),天 0-30,非负年(假设这是一个约束)。

一旦你过去了,我可能会检查 1752 特殊情况。

如果这不相关,则可以非常简单地处理“常规”月份。

这给我们留下了闰年的情况,可以分解为两个表达式 - 某事是否是闰年(将根据公历/朱利安另外分解),以及该日期是否有效。

因此,在最高级别,您的表达式看起来像这样:

areWithinRange(d,m,y) && pass1752SpecialCases(d,m,y) && pass30DayMonths(d,m,y) && pass31DayMonths(d,m,y) && passFebruaryChecks(d,m,y)

如果我们假设我们只在主动检测到规则违规时从子表达式中返回 false(6 月的 31 天对于 30DayMonth 规则返回 false,但 2 月的 30 天是无关紧要的,因此通过 true),那么我们几乎可以说那个层次的逻辑是正确的。

此时,我将为各个部分编写单独的函数(作为纯表达式,单个 return ... 语句)。一旦你得到了这些,你可以用扩展版本替换顶级表达式中的方法调用。只要确保你用括号括起来(这是一个词吗?)充分。

我还将制作一个使用该表达式并具有许多有效和无效输入的测试工具程序,并验证您是否在做正确的事情。您可以通过执行以下操作将其编写在一个函数中,以便在最终上交时轻松剪切和粘贴:

bool isValidDate(int d, int m, int y)
{
    return
        // your expression here
}

由于表达式将单独一行,因此很容易剪切和粘贴。

您可能会找到其他方法来简化您的逻辑 - 例如,除了 1752 特殊情况外,1 到 28 之间的天数始终有效。

于 2009-10-03T01:20:45.737 回答
1

您的解决方案(我不会完全为您提供)可能会遵循以下原则:

isJulian ? isJulianLeapyear : isGregorianLeapyear

为了使其更具体,它可能是这样的:

isJulian ? (year % 4) == 0 : ((year % 4) == 0 || (year % 400) == 0) 

你只需要确保你的算法是正确的。我不是日历专家,所以我不会知道。

于 2009-10-03T02:45:20.160 回答
0

考虑到这是家庭作业,我认为最好的建议是得出自己的解决方案的方法。

如果我要处理这个任务,我会从打破规则开始。

  1. 我会写一个给定变量 d、m 和 y 的 c++ 函数,返回一个关于日期有效性的布尔结果。我会根据需要使用尽可能多的非递归辅助函数,并且可以随意使用 if、else if 和 else,但不要大声循环。

  2. 然后我会内联所有辅助函数

  3. 我会将所有 if、else if 和 else 语句减少到 ? : 符号

如果我成功地限制了变量的使用,我也许可以将所有这些简化为一个没有变量的函数——它的主体将包含我寻求的单个表达式。

祝你好运。

于 2009-10-03T03:00:11.080 回答
0

您显然必须以某种方式传递日期。除此之外,您真正要做的就是链接&&||(假设我们将日期作为tm结构获取):

#include <ctime>
bool validate(tm date)
{
     return (
             // sanity check that all values are positive
             date.tm_mday >= 1 && date.tm_mon >= 0 && date.tm_year >= 0
             // check for valid days
             && ((date.tm_mon == 0 && date.tm_mday <= 31)
              || (date.tm_mon == 1 && date.tm_mday <= (date.tm_year % 4 ? 28 : 29))
              || (date.tm_mon == 2 && date.tm_mday <= 31)
             // yadda yadda for the other months
              || (date.tm_mon == 11 && date.tm_mday <= 31))
             );
}

date.tm_year % 4 ? 28 : 29实际上不需要括号,但为了便于阅读,我将它们包括在内。


更新

查看评论,您还需要类似的规则来验证公历中不存在的日期。

更新二

由于您处理的是过去的日期,因此您需要实施更正确的闰年测试。但是,我通常处理未来的日期,这个错误的闰年测试将在 2012、2016、2020、2024、2028、2032、2036、2040、2044、2048、2052、2056、2060、2064、 2068, 2072, 2076, 2080, 2084, 2088, 2092, 和 2096。我会预测,在这次测试失败之前,2100 台基于硅的计算机将被遗忘。我严重怀疑我们是否会在当时使用的量子计算机上使用 C++。此外,我不会成为被指派修复错误的程序员。

于 2009-10-03T00:25:17.837 回答