I am trying to create a date identifier using only if statements and a switch statement that can determine whether an inputted date is valid, what season the date is in and finally whether it is a leap year. I tried to get the component parts working independently first and got two of them working then tried them all together but I still can't get my switch statement working. I want my switch statement to show the season by checking both the day and month to see what season we are in but I'm not sure how to do that. Here is my code:
/* Switch statement to determine season for day and month */
// Using it with a "m" on it's own works, how do I get it working for specific days?
switch (m)
{
case 12:
case 1:
case 2:
if ((m == 12 && d >=21) || (m == 1) || (m == 2) || (m == 3 && m < 21))
printf("The season is Winter.\n");
break;
case 3:
case 4:
case 5:
if ((m == 3 && d >= 21) || (m == 4) || (m == 5) || (m == 6 && d < 21))
printf("The season is Spring.\n");
break;
case 6:
case 7:
case 8:
if ((m == 6 && d >= 21) || (m == 7) || (m == 8) | (m == 9 && d < 21))
printf("The season is Summer.\n");
break;
case 9:
case 10:
case 11:
if ((m == 9 && d >= 21) || (m == 10) || (m == 11) || (m == 12 && d < 21))
printf("The season is Autumn.\n");
default:
break;
}
}
I tried getting the code working for each part independently, but I'm still unsure about my switch statement. How can I get it working for days as well as months? Is there a way to do it still with a switch statement?
Example Output:
20/06/2022 = Spring
21/06/2022 = Summer
CodePudding user response:
You example will fail for March 1 (and other dates) since there is no case for 3 listed in the Winter case. You don't need a switch statement at all:
if ((m == 12 && d >=21) || (m == 1) || (m == 2) || (m == 3 && d < 21))
printf("The season is Winter.\n");
else if ((m == 3 && d >= 21) || (m == 4) || (m == 5) || (m == 6 && d < 21))
printf("The season is Spring.\n");
else if ((m == 6 && d >= 21) || (m == 7) || (m == 8) | (m == 9 && d < 21))
printf("The season is Summer.\n");
else
printf("The season is Autumn.\n");
CodePudding user response:
If you must use a switch
, then you have to put the boundary months (March, June, September, December) into their own cases:
const char *season = NULL;
switch (m)
{
case 1:
case 2:
season = "Winter";
break;
case 3:
season = (d < 21) ? "Winter" : "Spring";
break;
case 4:
case 5:
season = "Spring";
break;
case 6:
season = (d < 21) ? "Spring" : "Summer";
break;
case 7:
case 8:
season = "Summer";
break;
case 9:
season = (d < 21) ? "Summer" : "Autumn";
case 10:
case 11:
season = "Autumn";
break;
case 12:
season = (d < 21) ? "Autumn" : "Winter";
break;
default:
assert("month out of control" == NULL);
season = "Unknown - invalid month";
break;
}
printf("The season is %s.\n", season);
CodePudding user response:
"Is there a way to do it still with a switch statement?
This question indicates a flawed perspective. Algorithms should be written to clearly and cleanly achieve the objective of the task; not written to conform to a favourite scheme. As shown in other answers, switch()
is either cumbersome or unnecessary to solve this problem.
It's worth noting/learning that "branching" can be expensive in terms of processing time. While a ladder of if/else conditionals may be easy for a human to read and understand, finding a superior algorithm that does not involve branching will likely process much faster.
If you want to calculate the name of the season instead of using a lot of magic numbers in conditionals, then this seems to work.
void season( uint16_t m, uint16_t d ) {
char *seasons[] = { "Winter", "Spring", "Summer", "Autumn", "Winter" };
char *p = seasons[ ((m-1) / 3) (!(m%3)*( d >= 22 )) ];
printf( "mon %d day %d = %s\n", m, d, p );
}
int main() {
season( 1, 1 );
season( 1, 22 );
season( 2, 22 );
season( 3, 21 );
season( 3, 22 );
season( 9, 21 );
season( 9, 22 );
season( 12, 21 );
season( 12, 22 );
return 0;
}
mon 1 day 1 = Winter
mon 1 day 22 = Winter
mon 2 day 22 = Winter
mon 3 day 21 = Winter
mon 3 day 22 = Spring
mon 9 day 21 = Summer
mon 9 day 22 = Autumn
mon 12 day 21 = Autumn
mon 12 day 22 = Winter
And, with only "month and day", the only indication of "leap year" would be if you had the pair "02/29". Not sure what you wanted there...
EDIT:
Not to forget those who live south of the equator, here is the trivial modification to the above function that takes a 3rd parameter (true for the southern hemisphere.)
void season( bool SthHemi, uint16_t m, uint16_t d ) {
char *seasons[] = { "Winter", "Spring", "Summer", "Autumn", "Winter", "Spring", "Summer", };
char *p = seasons[ (SthHemi*2) ((m-1) / 3) (!(m%3)*( d >= 22 )) ];
printf( "mon %d day %d = %s\n", m, d, p );
}
EDIT2:
Not really happy with the extra instances of the names of the seasons, here is an improved calculation that determines which string to use.
char *season( int SthHemi, uint16_t m, uint16_t d ) {
char *seasons[] = { "Winter", "Spring", "Summer", "Autumn" };
return seasons[ (((m (SthHemi*6)-1) / 3) (!(m%3)*( d >= 22 )))%4 ];
}
SthHemi
- being 0 (north) or 1 (south) - is multiplied by 6 as the hemispheres' seasons are 6 months out of phase. Adding this to the month index (1-12), subtracting 1, then dividing by 3 gives either 0,1,2,3 or 2,3,4,5 towards the index of the string to use. Now, if the month modulo 3 is 0 (ie: Mar, Jun, Sep, or Dec), use !0 (ie: 1) to multiply the truth value that the day-of-month is >= 22. This operation may add 1 to the index value calculated so far for the final days of those 'transitional' months. Finally, use modulo 4 to "wrap" larger index values into the range of 0-3 and return the appropriate string from the array of strings that are season names. Simple!