Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking for code must demonstrate a minimal understanding of the problem being solved. Include attempted solutions, why they didn't work, and the expected results. See also: Stack Overflow question checklist
Closed 9 years ago.
Improve this question
if (month > 0 && month <= 12)
if (day > 0 && day <= checkDays(month, year))
if (year >= 1752 || year <= 9999)
if((month != 12 && day != 31 && year != 9999))
return true;
else return false;
else return false;
else return false;
else return false;
I have the values month = 12, days = 31, and year = 2008 and the data validation is failing at the last part, but I cannot figure out why.
Your first year condition uses OR when you wanted AND; your second year condition is exactly inverted from what I suspect you wanted.
You also have an order-of-operations bug: you can't check the day until after you validate the month and the year (assuming what checkDays does is provide the maximum day number for a particular (month, year) pair; if so, you should rename it days_in_month).
Finally, code like this is generally much easier to read if written as a series of if-fail-return-false conditions without any nesting. Like so:
// Year range supported is [1752, 9999].
// (Gregorian calendar introduced in 1752 in Great Britain.)
if (year < 1752 || year > 9999)
return false;
// Valid month numbers in [1, 12].
if (month < 1 || month > 12)
return false;
// Valid day numbers in [1, n] where n depends on month and year.
if (day < 1 || day > checkDays(month, year))
return false;
// 9999-12-31 is invalid (used as a sentinel value?)
if (year == 9999 && month == 12 && day == 31)
return false;
return true;
By the way, the Long Now people would like a word regarding your upper year limit.
I find it's nearly always easier to write these things with the "find the false things and return". So:
if (month < 1 || month > 12) return false;
if (day < 1 || day > 31) return false;
if (year < 1752 || year > 9999) return false;
if (month == 12 && day == 31 && year == 9999) return false;
// If we get here, everything is fine, so return true.
return true;
Of course, you should probably check the day based on which month it is:
int daysInMonth[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
if (month < 1 || month > 12) return false; // Must do this before checking day!
int daysThisMonth = daysInMonth[month];
// Check for leapyear.
if (month == 2 && year % 4 == 0 && (year % 100 != 0 || year % 400 == 0))
{
daysThisMonth = 29;
}
if (month != 2 && day < 1 || day > daysThisMonth) return false;
...
A bit of speculation, since I don't quite know what your function is supposed to do, but here goes.
month != 12 && day != 31 && year != 9999 only returns true if the month is not 12 and the day is not 31 and the year is not 9999.
So for your input, it's:
month != 12 && day != 31 && year != 9999
=> false && false && true
=> false
Don't you maybe want:
month != 12 || day != 31 || year != 9999
Which will return true if either the month is not 12 or the day is not 31 or the year is not 9999.
An equivalent, but possibly more understandable way of writing it:
!(month == 12 && day == 31 && year == 9999)
So that's "if the month is 12 and the day 31 and the year 9999, return false".
Related
I'm doing a practice exercise. It asks me to create a calendar of the month, year which is the current user time. I have looked up some code on the Internet, it works well, but I can't understand it clearly. Especially the line year -= month < 3. Can someone explain it, please?
//return the daycode of the first day of month.
int firstDayOfMonth(int month, int year) {
int dow = 0;
int day = 1;
int t[] = { 0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4 };
year -= month < 3; // I cannot understand this.
cout<<"This is year "<<year<<endl;
dow = ( year + year/4 - year/100 + year/400 + t[month-1] + day) % 7;
return dow;
}
int main()
{
int a;
cout<<firstDayOfMonth(2,2018)<<endl;
return 0;
}
In C++, boolean values can be implicitly converted to integers, with false becoming 0 and true becoming 1. (See bool to int conversion.)
So year -= month < 3; is equivalent to:
if (month < 3) {
year -= 1; // true -> 1
} else {
year -= 0; // false -> 0
}
which can be simplified to:
if (month < 3) {
--year;
}
The motivation is that January and February (months 1 and 2) come before any leap day, while the other months come after any leap day, so it's convenient to treat January and February as being at the end of the previous year, and let the leap day be added to the calculation for the entire March-to-February year.
This code is obviously not optimized for readability.
What that means is:
if the condition (month < 3) is true, then decrement by 1. if the condition (month < 3) is false, then decrement by 0 (year stays the same)
The value of 1 & 0 represent false & true of the month & number comparison.
I'm having trouble deciphering this bit of code. I've encountered a return statement as complicated as this, so can someone break it down for me? (This code was from a problem in which I had to differentiate between a leap year and a non-leap year). Thanks!
return ((year % 4) || (!(year % 100) && ((year+300) % 400))) ? 28 : 29;
It's just a conditional expression, condition ? true_value : false_value.
It gets clearer if you separate out the condition:
bool not_leap_year = (year % 4) || (!(year % 100) && ((year+300) % 400));
return not_leap_year ? 28 : 29;
It's more common to compute the negation of the condition though, as the rules for when there is a leap year are better known than the rules for when there isn't (so there's less chance of bugs).
bool leap_year = year % 4 == 0 && (year % 100 != 0 || year % 400 == 0);
return leap_year ? 29 : 28;
((year % 4) || (!(year % 100) && ((year+300) % 400))) ? 28 : 29;
This is the ternary operator ? with a relatively complex boolean expression. You could achieve the same with an if expression:
if ( (year % 4) // year not dividable by 4
or
(
not (year % 100) // year dividable by 100
and
((year+300) % 400))) // year + 300 not dividable by 400
{
return 28;
}
else
{
return 29;
}
One can make that a bit more readable using a helper function:
bool dividableBy(unsigned value, unsigned divisor) {
return value % divisor == 0;
}
//...
if ((not dividableBy(year, 4)) or
(dividableBy(year, 100) and
(not dividableBy(year+300, 400)))) {
return 28;
}
else {
return 29;
}
I'm having an issue with this code,I do not understand how the function works. I need to validate the input from the user, to see if their date that they placed is valid. And if it isn't I set the error code. So in my read function I cin the date then validate the input and call mdays() however, for some reason I don't know how to check in my if statement in the read function if the date is validate or not.
int Date::mdays() const
{
int days[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, -1};
int mon = _mon >= 1 && _mon <= 12 ? _mon : 13;
mon--;
return days[mon] + int((mon == 1)*((_year % 4 == 0) &&
(_year % 100 != 0)) || (_year % 400 == 0));
}
The code is very clever, written by someone who wanted to demonstrate that they are smart. I hate clever code. (It's also quite slow, I hate code that tries to be clever and fails).
Remember the rules for leapyears:
Every fourth year is a leap year. Except that every 100th year is not a leap year. Except that every 400th year is a leap year.
Most months you can look up from a table, except that February has either 28 or 29 days. So to understand the code, what happens if the month is not February? And what happens if the month is February? mon will be equal to 1. What is the value of (mon == 1) in February? How would you express the rules for leap years?
And the function that you showed calculates the number of days in a month, it doesn't do any validation. Obviously you need to know that April has 30 days to know that April 31st is invalid.
You can change the signature of mdays(), return a boolean to indicate if the date is validate or not, and put an output argument to store the days if the date is validate
bool Date::mdays(int& month_days) const {
int days[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
if (_mon < 1 || _mon > 12) return false;
mon--;
month_days = days[mon] + int((mon == 1)*((_year % 4 == 0) && (_year % 100 != 0)) || (_year % 400 == 0));
return true;
}
If you can modify the Date class, you should be able to create new method utilizing return value of mdays() like this:
bool Date::validate_day_and_month() const {
int maxday = mdays();
if ( maxday < 0 ) { return false; } // mdays() = -1 if _month is bad
if ( _day <= 0 || _day > maxday ) { return false; }
return true;
}
Here, _day is the day part of the user date input.
What is the execution order and possible results of this statement: leap = year%4 == 0;
(The left part is assignment and the right assertion?)
Which is excerpt from the following algorithm used to calculate day of the week of any date in Gregorian calendar:
static char daytab[2][13] =
{
{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
{0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
};
for (year = 1; year <= y; year++)
{
leap = year%4 == 0;
if (year%100 == 0 && year%400 != 0)
leap = 0;
for (month = 1; month <= m; month++)
{
d += daytab[leap][month - 1];
daystotal = 365*(year - 1) + (int)floor((year-1)/4)
- (int)floor((year - 1)/100) + (int)floor((year - 1)/400) + d;
}
}
Look here operator precendence. year % 4 will be evaluated, than result will be compared to 0 and then result will be assigned to leap variable.
year % 4 == 0 is equivalent to (year % 4) == 0, which takes the remainder after dividing year by 4, then compares that to 0 and produces a Boolean result--true or false. You don't show a declaration/definition of leap, so we can only guess at its type. If it's a bool, that result will be assigned directly to it. Based on the later code:
if (year%100 == 0 && year%400 != 0)
leap = 0;
It appears that leap is probably some other arithmetic type (probably int). This is quite common, especially in code that was originally written in C90, which has no Boolean type.
In this case, the bool will be converted before the assignment. When being converted to arithmetic types, false converts to 0 and true converts to 1 (going in the other direction, 0 converts to false, and any other value converts to true).
So, the code has basically the same effect as something like:
if ((year % 4) == 0)
leap = 1;
else
leap = 0;
...or:
leap = ((year % 4) == 0) ? 1 : 0;
If I were writing it, I think I'd probably write the code more like this:
if ((year % 4 == 0) && ((year % 100 != 0) || (year % 400 == 0) )
leap = 1;
else
leap = 0;
...or (more likely) just:
leap = ((year % 4 == 0) && ((year % 100 != 0) || (year % 400 == 0));
At least to me, this more directly states the conditions of "what is a leap year" in the Gregorian calendar1. I suppose you could view the original code as a historical artifact through: it first computes whether it's a leap year under the rules of the older Julian calendar, then separately adds on the rules that were added in the Gregorian calendar. If somebody really wanted to reflect that history, however, they should probably include a comment explaining that that's why the code is written as it is. As it stands right now, rather than just computing the correct value, it starts by computing a value that may be incorrect, then checks for more conditions, and patches the value up afterward.
1. Which are, of course, something like: A year is a leap year if it is divisible by 4, and either not divisible by 100, or also divisible by 400. So, for example, 2000 was a leap year (divisible by 4 and also divisible by 400) but 1900 was not (divisible 4, but also divisible by 100 and not divisible by 400).
I'm trying to write a program that calculates a rental bill. I have most of the program written, but I have to write a function that takes the user input of days rented and the starting rental date to determine the return date. The only requirement is that the function is to be a loop that calls another function (that determines the number of days in the month). The problem I keep running into is that the other function (which is to determine the days in each month) doesn't change depending on the month. So if I put in 1/1/2013, it has the correct number of days for the month and then when the counter changes to Feb, it continues with 31 days. Does anyone know a formula that will satisfy the requirements?
Start with a hard-coded array with the number of days in each month.
Compensate for February's leap day and you should be good.
int daysInMonth(int month, int year)
{
// Check for leap year
bool isLeapYear;
if (year % 400 == 0)
isLeapYear = true;
else if (year % 4 == 0 && year % 100 != 0)
isLeapYear = true;
else
isLeapYear = false;
int numDaysInMonth[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
if (isLeapYear)
numDaysInMonth[1]++;
return numDaysInMonth[month - 1];
}
Why not considering using Boost.Date_Time ?
int isLeap(int year)
{
return (year > 0) && !(year % 4) && ((year % 100) || !(year % 400));
}
int calcDays(int month, int year)
{
static const int daysInMonth[2][13] = {
{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
{ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } };
if (month >= 1 && month <= 12) {
return daysInMonth[isLeap(year)][month - 1];
}
return -1;
}
this will give you the days of the month