C+的日历程序+;这个班有一个计日错误 我正在制作一个C++程序,它通过计算1753年1月1日的一天的天数来确定一年中的一天的月份。然后,它将天数除以7,以确定用于计算月的第一天从哪一天开始的“偏移量”(例如:由于1753年1月1日是星期一,因此偏移量为2表示月的第一天是星期三)。当我注意到一个非常奇怪的bug时,我完成了我的代码并运行了几次测试。对于2000年,抵消比它应该的高一倍(2月从周三开始,而不是周二,等等)。这个问题在任何其他闰年或以“00”结尾的年份中都不存在。这是我唯一一次失败的测试,而就我的一生而言,我似乎都不知道问题出在哪里
代码如下:C+的日历程序+;这个班有一个计日错误 我正在制作一个C++程序,它通过计算1753年1月1日的一天的天数来确定一年中的一天的月份。然后,它将天数除以7,以确定用于计算月的第一天从哪一天开始的“偏移量”(例如:由于1753年1月1日是星期一,因此偏移量为2表示月的第一天是星期三)。当我注意到一个非常奇怪的bug时,我完成了我的代码并运行了几次测试。对于2000年,抵消比它应该的高一倍(2月从周三开始,而不是周二,等等)。这个问题在任何其他闰年或以“00”结尾的年份中都不存在。这是我唯一一次失败的测试,而就我的一生而言,我似乎都不知道问题出在哪里,c++,C++,代码如下: //********************************************************************** #include <iostream> #include <iomanip> using namespace std; int getYear(); int getMonth(); int computeNumDays(int month, int year); int computeOffset(int mont
//**********************************************************************
#include <iostream>
#include <iomanip>
using namespace std;
int getYear();
int getMonth();
int computeNumDays(int month, int year);
int computeOffset(int month, int year);
bool isLeapYear(int year);
void displayHeading(int month, int year);
void displayTable(int offset, int numDays);
/********************
* MAIN
*********************/
int main()
{
int month = getMonth();
int year = getYear();
int offset = computeOffset(month, year);
int numDays = computeNumDays(month, year);
displayHeading(month, year);
displayTable(offset, numDays);
return 0;
}
/********************
*GETMONTH
*Prompts the user for a month number
*********************/
int getMonth()
{
int month;
//Month number must be between 1 and 12
cout << "Enter a month number: ";
cin >> month;
//Displays an error message if the month is under 1 or over 12
while (month < 1 || month > 12)
{
cout << "Month must be between 1 and 12.\n";
cout << "Enter a month number: ";
cin >> month;
}
return month;
}
/********************
*GETYEAR
* prompts the user for a year
*********************/
int getYear()
{
int year;
cout << "Enter year: ";
cin >> year;
//Displays an error message if the year is less than 1753
while (year < 1753)
{
cout << "Year must be 1753 or later.\n";
cout << "Enter year: ";
cin >> year;
}
cout << "\n";
return year;
}
/********************
*COMPUTENUMDAYS
* For computing the number of days in a month, so we know where to count to when filling in
* the calendar
*********************/
int computeNumDays(int month, int year)
{
int numDays;
if (month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12)
return numDays = 31;
else if (month == 4 || month == 6 || month == 9 || month == 11)
return numDays = 30;
else if (month == 2 && (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))
return numDays = 29;
else if (month == 2)
return numDays = 28;
}
/*********************
*COMPUTEOFFSET
*********************/
int computeOffset(int month, int year)
{
int totalYearDays = 0;
int totalMonthDays = 0;
//This counts up all the days between the January 1st of 1753 to January 1st of the users input
//year. Leap years are accounted for with the IF statements and the isLeapYear function
for (int yearCount = 1753; yearCount < year; yearCount++)
{
if (isLeapYear(yearCount))
totalYearDays += 366;
else
totalYearDays += 365;
}
//The days of the month of the user input year are added up here. If the user inputs February(2),
//then it counts the days of each month in between and adds them up.
for (int monthCount = 0; monthCount < month; monthCount++)
{
if (monthCount == 1 || monthCount == 3 || monthCount == 5)
totalMonthDays += 31;
else if (monthCount == 7 || monthCount == 8 || monthCount == 10 || monthCount == 12)
totalMonthDays += 31;
else if (monthCount == 4 || monthCount == 6 || monthCount == 9 || monthCount == 11)
totalMonthDays += 30;
//if the user input year is a leap year, then an extra day to February is added
else if (monthCount == 2 && (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))
totalMonthDays += 29;
else if (monthCount == 2)
totalMonthDays += 28;
}
int offset = (totalYearDays + totalMonthDays) % 7;
return offset;
}
/******************************************
* ISLEAPYEAR
******************************************************/
bool isLeapYear(int yearCount)
{
//Equation for determining if a year is a leap year or not
if ((yearCount % 4 == 0 && yearCount % 100 != 0) || (yearCount % 400 == 0))
return true;
else
return false;
}
/*************************************************
*DISPLAYHEADING
* This is where the Month Name and Year are shown
**************************************************/
void displayHeading(int month, int year)
{
if (month == 1)
cout << "January, " << year << endl;
else if (month == 2)
cout << "February, " << year << endl;
else if (month == 3)
cout << "March, " << year << endl;
else if (month == 4)
cout << "April, " << year << endl;
else if (month == 5)
cout << "May, " << year << endl;
else if (month == 6)
cout << "June, " << year << endl;
else if (month == 7)
cout << "July, " << year << endl;
else if (month == 8)
cout << "August, " << year << endl;
else if (month == 9)
cout << "September, " << year << endl;
else if (month == 10)
cout << "October, " << year << endl;
else if (month == 11)
cout << "November, " << year << endl;
else if (month == 12)
cout << "December, " << year << endl;
return;
}
/********************
*DISPLAYTABLE
*********************/
void displayTable(int offset, int numDays)
{
//days of the week are displayed here
cout << setw(4) << "Su" << setw(4) << "Mo" << setw(4) << "Tu"
<< setw(4) << "We" << setw(4) << "Th" << setw(4) << "Fr" << setw(4)
<< "Sa" << setw(2) << endl;
//WeekBreak counter will be used to add new lines for each week
int weekBreak = 1;
//This IF statement determines the number of days before the first of the month occurs,
// as well as sets the weekBreak counter
if (offset != 6 && offset >= 0)
do
{
cout << setw(4) << " ";
offset--;
weekBreak++;
} while (offset != -1);
//The counter loop here begins putting in the dates, all the way from the first to
//the max number of days in the month
for (int date = 1; date <= numDays; date++)
{
cout << " " << setw(2) << date;
weekBreak++; //weekBreak prevents us from putting more than
//7 dates in a single week
if (weekBreak == 8)
{
cout << "\n"; //once a week hits 7 dates(or 8 spaces), it moves on to a new week
weekBreak = 1;
}
}
//this puts an end to the calander, regardless if weekBreak limit is reached
if (weekBreak >= 2 && weekBreak <= 7)
cout << "\n";
}
//**********************************************************************
#包括
#包括
使用名称空间std;
int getYear();
int getMonth();
整数计算日(整数月,整数年);
整数计算偏移量(整数月,整数年);
布尔群岛年(国际年);
无效显示标题(整数月,整数年);
void displayTable(int offset,int numDays);
/********************
*主要
*********************/
int main()
{
int month=getMonth();
int year=getYear();
int offset=计算偏移量(月、年);
int numDays=计算天数(月、年);
显示标题(月、年);
显示表(偏移量,numDays);
返回0;
}
/********************
*GETMONTH
*提示用户输入月份号
*********************/
int getMonth()
{
整月;
//月数必须介于1和12之间
月份;
//如果月份小于1或大于12,则显示错误消息
而(月<1 | |月>12)
{
月份;
}
返回月份;
}
/********************
*假期
*提示用户一年
*********************/
整年
{
国际年;
年份;
//如果年份小于1753,则显示错误消息
而(年份<1753年)
{
过去一年;
}
cout为了调试代码,我编写了以下main
函数:
int main()
{
for (int year = 1753; year <= 2021; year++)
{
for (int month = 1; month <= 12; month++)
{
int offset = computeOffset(month, year);
int numDays = computeNumDays(month, year);
std::chrono::year_month_day date(std::chrono::year(year), std::chrono::month(month), std::chrono::day(1));
std::chrono::weekday day{ std::chrono::sys_days(date) };
int expectedOffset = ((day - std::chrono::Monday).count() + 7) % 7;
if (expectedOffset != offset)
{
std::cout << year << "/" << month << " expected " << expectedOffset << " actual " << offset << "\n";
}
}
}
return 0;
}
和计算偏移量
:
else if (month == 2 && isLeapYear(year))
return numDays = 29;
else if (monthCount == 2 && isLeapYear(year))
totalMonthDays += 29;
修复了这个bug
该错误的原因实际上是两个错误的组合:
在computeOffset
monthCount
中,从0
开始,而不是1
当year%400==0
为真时,表达式monthCount==2&&(year%4==0&&year%100!=0)|(year%400==0)
将始终为true
这会导致totalMonthDays
的值比它在%7
之后可以被400整除的年份多29,这会导致computeOffset
的结果比它应该的值高1
通过消除重复,您的代码可以大大简化:
int computeNumDays(int month, int year)
{
switch (month)
{
case 1:
case 3:
case 5:
case 7:
case 8:
case 10:
case 12:
return 31;
case 4:
case 6:
case 9:
case 11:
return 30;
case 2:
return isLeapYear(year) ? 29 : 28;
default:
throw std::invalid_argument("invalid month");
}
}
int computeOffset(int month, int year)
{
int totalYearDays = 0;
int totalMonthDays = 0;
//This counts up all the days between the January 1st of 1753 to January 1st of the users input
//year. Leap years are accounted for with the IF statements and the isLeapYear function
for (int yearCount = 1753; yearCount < year; yearCount++)
{
if (isLeapYear(yearCount))
totalYearDays += 366;
else
totalYearDays += 365;
}
//The days of the month of the user input year are added up here. If the user inputs February(2),
//then it counts the days of each month in between and adds them up.
for (int monthCount = 1; monthCount < month; monthCount++)
{
totalMonthDays += computeNumDays(monthCount, year);
}
int offset = (totalYearDays + totalMonthDays) % 7;
return offset;
}
bool isLeapYear(int yearCount)
{
//Equation for determining if a year is a leap year or not
if ((yearCount % 4 == 0 && yearCount % 100 != 0) || (yearCount % 400 == 0))
return true;
else
return false;
}
int计算天数(int月,int年)
{
开关(月)
{
案例1:
案例3:
案例5:
案例7:
案例8:
案例10:
案例12:
返回31;
案例4:
案例6:
案例9:
案例11:
返回30;
案例2:
返回年份?29:28;
违约:
抛出std::无效的_参数(“无效月份”);
}
}
整数计算偏移量(整数月,整数年)
{
int totalYearDays=0;
int totalMonthDays=0;
//这将统计1753年1月1日到用户输入的1月1日之间的所有天数
//年份。闰年使用IF语句和isLeapYear函数进行计算
对于(int yearCount=1753;yearCount
我建议您开始阅读它所提供的内容。建议:备份您所拥有的内容并删除所有用户输入。用您知道的导致您正在查找的错误的硬编码值替换它。这减少了实验的周期时间,并使每个人都使用相同的数据集,希望使用相同的错误。Doe您的代码考虑到可被100整除的年份不是闰年,但可被400整除的年份是闰年吗?我不喜欢if else if
ladders。使用字符串数组:char*month\u name[]={“无”、“一月”、“二月”、“三月”、“十二月”};std::cout+1用于使用C++20 chrono编写调试代码。Fwiw,这里是C++20 chrono(在C++20 date.h之前)打印日历:。基于计时的代码的一大优点是没有实现computeOffset
的循环。这个功能可以在print\u of u calendar\u month
,case 2
,string(static\u cast((wd firstdow).count()*3',
中找到。更简单地说,就是子表达式(wd firstdow).count()
。计算从firstdow
(星期日)到每月第一天的天数。