Using Switch Statements with Dates and Seasons - c

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

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");

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);

"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!

Related

How do you write multiple conditions on if statements

if (num1 == (1,2,3,4,5,6,7,8,9)){
*some command*
}
does this sequence work, if not can you guide me masters. I'm a beginner
Try this:
if(num1 >= 1 && num1 <= 9) {
// Some code
}
&& operator will make sure num1 should be between 1 to 9 including it (i.e. 1, 9). It will execute some code only if both the conditions are true.
If the numbers you're testing for are in a continuous range, you can bound the value with greater than and less than (or equals):
For example, if you're testing if an int n is one of 1, 2, 3, 4, 5, 6, 7, 8, 9, you can do this:
if(n >= 1 && n <= 9)
{
// Code
}
If, however, the numbers are not a continuous range you have no choice but to explicitly test every value. So, if you were checking if n was one of 13, 57, -3, 11, -66, 100, you could have to write it out completely (or use a switch statement or lookup table):
if(13 == n || 57 == n || -3 == n || 11 == n || -66 == n || 100 == n)
{
// Code
}
Alternatively (only for integral types):
switch (n)
{
case 13:
case 57:
case -3:
case 11:
case -66:
case 100:
// Code
break;
}
You may want to write a helper method in the latter case to make it more clear what you're testing for. e.g.:
if(IsAcceptableValueForTask(n))
Where IsAcceptableValueForTask returns an int representing the truth (1|0) of 13 == n || 57 == n || -3 == n || 11 == n || -66 == n || 100 == n
You can use
if (num1 == 1 || num1 == 2 || num1 == 3 || num1 == 4 || num1 == 5 || num1 == 6 || num1 == 7 || num1 == 8 || num1 == 9 ){
//code
}
If you want to check between a range of numbers you can use
if(num1 >= 1 && num1 <= 9) {
//code
}
You can also use switch statement for more convenience if the numbers are random and there are many conditions

Search for `count' distinct odd numbers that are smaller than `bound' and add up to `sum'

I am working on a problem that finds 'count' odd numbers below the int value 'bound' and adds up to an int value sum. It is suggested that I use recursion to solve.
I have completed the recursion and have made it solve 7 / 8 cases in mimir. There is one case that is showing a fail but I cannot figure out what is wrong even when stepping through with gdb.
Problem case:
Input: 10 54 108
EDIT:
So it turns out that my code is correct and is finding the correct answer for this case ( AKA - No solution exists ) but my problem is that I only have 3 sec of run time to find this solution and currently my code takes longer than that.
Not looking for a straight answer necessarily, more of a point in the right direction. Trying to learn from this :)
https://ibb.co/4138WBw
int odd_sum(int count, int bound, int sum)
{
if (bound % 2 == 0)
return odd_sum(count, bound -1, sum);
else if ( sum == 0 && count == 0 && bound >= -1)
return 1;
else if ( sum - bound < 0)
return odd_sum(count, bound - 2, sum);
else if (count == 0 && sum != 0)
return 0;
else if (bound < 1 && sum != 0)
return 0;
else
{
int value = (odd_sum(count - 1, bound - 2, sum - bound));
if ( value )
{
return printf("%d ", bound);
}
else
return (odd_sum(count - 1, bound - 2, sum - bound));
}
/* Do not change the main() function */
int main(void)
{
int value;
int c, b, s;
printf("Please enter 3 positive integers: count, bound, and sum:\n");
if (scanf("%d%d%d", &c, &b, &s) != 3) {
printf("Please enter 3 integers.\n");
return 1;
}
if (c <= 0 || b <= 0 || s <= 0) {
printf("Integers must be positive.\n");
return 1;
}
value = odd_sum(c, b, s);
if (value)
printf("\n");
else
printf("There are no solutions.\n");
return 0;
}
The final result needs to look like this for the two cases, ( pass or fail )
$./odd_sum
Please enter 3 positive integers: count, bound, and sum:
10 20 100
1 3 5 7 9 11 13 15 17 19
$./odd_sum
Please enter 3 positive integers: count, bound, and sum:
10 18 100
There are no solutions.
$./odd_sum
Please enter 3 positive integers: count, bound, and sum:
12 30 200
5 7 9 11 13 15 17 19 23 25 27 29
Thank you guys in advance
This code seems to return the correct result for input, (10, 54, 108): 1 3 5 7 9 11 13 15 17 27
int odd_sum(int count, int bound, int sum){
if (count == 0 && sum == 0)
return 1;
if (count == 0 || bound <= 0)
return 0;
if (bound % 2 == 0)
return odd_sum(count, bound - 1, sum);
if (odd_sum(count - 1, bound - 2, sum - bound))
return printf("%d ", bound);
else
return odd_sum(count, bound - 2, sum);
return 0;
}

code logic: Friday the Thirteenth (USACO)

I am a newbie to coding and I am trying to code for the "Friday the Thirteenth" problem posted in USACO, which requires us to compute the frequency that the 13th of each month lands on Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, and Saturday over a given period of N years. The time period to test will be from January 1, 1900 to December 31, 1900+N-1 for a given number of years, N. N is positive and will not exceed 400.
It was given that Jan 1, 1900 was on a Monday. We are not supposed to use any in-built functions.
I tried to solve this problem with a different approach (which I think isn't the best approach). My code (in C) is given below:
#include<stdio.h>
int daysInMonth (int month, int year)
{
/*
30 should be returned if the months are Apr, June, Sept and Nov.
31 should be returned in all other cases.
29 should be returned if the month is Feb and the year is a leap year
*/
if (month == 1) //Feb
{
if (year % 4 == 0 || (year % 100 != 0 && year % 400 == 0)) //leap year
return 29;
else
return 28;
}
switch (month)
{
case 3:
case 5:
case 8:
case 10: return 30;
default: return 31;
}
}
void main ()
{
int month, year, n, i, noOfDays, start = 0, result[] = { 0, 0, 0, 0, 0, 0, 0 }, day = 0, daycheck = 1;
scanf ("%d", &n);
for (year = 1900; year <= 1900 + n - 1; ++year)
{
for (month = 0; month < 12; ++month)
{
if (month == 0 && year == 1900) // to identify the first 13th and the day it falls on
{
while (daycheck != 13)
{
++daycheck;
day = (day + 1) % 7;
}
++result[day];
}
else
{
if (month == 0) //If January, add the noOfDays of the prev. month i.e. December
noOfDays = 31;
else
noOfDays = daysInMonth (month - 1, year);
day += (noOfDays - 28); // Adding a multiple of 7 (here, 28) does not change the day
day %= 7;
++result[day];
}
}
}
for (i = 0; i < 7; ++i)
printf("%d ", result[(i + 5) % 7]); //Sat, Sun, Mon, Tue, Wed, Thu, Fri
}
For an input of 20, the expected output is 36 33 34 33 35 35 34.
However, my output turns out to be 35 35 33 35 32 35 35.
Even though my answer is within the range of the expected output, there's something wrong with my logic that makes it erroneous.
I would appreciate if someone could point out the error. I would also be happy if you could suggest a better way to approach this problem. I am a student of Computer Science and am yet to learn about algorithms in detail.
Your leap year condition is wrong.
Change the Leap year condition as follows.
int daysInMonth (int month, int year)
{
if (month == 1) //Feb
{
if (( year%400 == 0)|| (( year%4 == 0 ) &&( year%100 != 0)))
return 29;
else
return 28;
}

Printing a Julian Calendar in C using month and year input?

I'm trying to output a calendar in C and I think I've got the format down, but I'm having trouble with:
Validating user input (I've commented out the potential solution, but it hasn't compiled correctly yet. It always prints the "invalid year/month selected" and the break statement doesn't work.)
Starting the calendar days on the correct day of the week (May of 2018 starts on Tuesday, not on Sunday)
My current output:
Enter month: 5
Enter year: 2018
Su M Tu W Th F Sa
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
My desired output:
Enter month: 5
Enter year: 2018
Su M Tu W Th F Sa
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31
Here's my program:
#include <stdio.h>
#include <stdlib.h>
/* #defines */
#define BEGIN 1900
#define DAYS_IN_WEEK 7
/* function prototypes */
void getMonthYear(int *month, int *year);
int toJulian(int month, int day, int year);
int daysInMonth(int month, int year);
int leapYear(int year);
long yearsToDays(int year);
void printCalendar(int startDay, int numDays);
void printHeader();
/* Calendar.c: Prints monthly calendar. Lab 4 / Week 9 */
void main(void)
{
int month, year;
int startDay; // what day is first day of month. 1/1/1900 was Monday, so...
// day 1 is Mon, day 2 is Tue, ... , day 0 is Sun
getMonthYear(&month, &year);
startDay = (toJulian(month, 1, year) + yearsToDays(year)) % DAYS_IN_WEEK;
printCalendar(startDay, daysInMonth(month, year));
}
void getMonthYear(int *month, int *year) {
printf("Enter month: ");
scanf("%d", month);
/*if (month < 1 || month > 12) {
printf("Invalid month selected");
//break;
}*/
printf("Enter year: ");
scanf("%d", year);
/* if (year < BEGIN) {
printf("Invalid year selected");
//break;
}*/
printf("\n");
}
int toJulian(int month, int day, int year) {
int count;
for(count = 1; count < month; ++count) {
day += daysInMonth(month, year);
}
return day;
}
int daysInMonth(int month, int year) {
int numDays;
switch (month) {
case 1: numDays = 31;
break;
case 2: numDays = 28;
break;
case 3: numDays = 31;
break;
case 4: numDays = 30;
break;
case 5: numDays = 31;
break;
case 6: numDays = 30;
break;
case 7: numDays = 31;
break;
case 8: numDays = 31;
break;
case 9: numDays = 30;
break;
case 10: numDays = 31;
break;
case 11: numDays = 30;
break;
case 12: numDays = 31;
break;
}
return numDays;
}
int leapYear(int year) {
if (year % 400 == 0 && (year % 100 != 0 || year % 400 == 0)) {
return 1;
}
else {
return 0;
}
}
long yearsToDays(int year) {
int count;
long days;
for (count = BEGIN; count < year; ++count) {
days = 365 + leapYear(year);
}
return days;
}
void printCalendar(int startDay, int numDays) {
int dayid;
printHeader();
// Shifts position for the first date... sort of
for ( dayid = 0; dayid < startDay; dayid++ ) {
printf(" ");
}
// Supposedly prints all the dates for one month
for ( dayid = 1; dayid <= numDays; dayid++ ) {
printf("%3d", dayid );
// If the day is not before Saturday, start next line on Sun
if ( ( dayid + startDay ) % DAYS_IN_WEEK > 0 ) {
printf(" ");
}
else {
printf("\n" );
}
}
}
void printHeader() {
printf(" Su M Tu W Th F Sa\n");
}
break is used for exiting loops or switch statements. It can only be used inside a loop inside the current function scope.
So even if getMonthYear() were called inside a loop in main() (which it isn't), a break inside it will not exit that loop.
As it is, you have no loop at all, neither in getMonthYear(), nor in the calling sequence leading to it, so the break would be a no-op.
You have to ask yourself "what do I actually want to do when they make an invalid entry?"
One possibility would be to return the validity from getMonthYear()
bool valid_input = 0;
while (!valid_input) {
valid_input = getMonthYear(&month, &year);
}
To deal with the problem of getting the day correct, you probably need to do a little more debugging yourself: put print statements in all the places where there are calculations, print out the intermediate results, and find out where you have an error that way.
You have errors in the following functions:
toJulian
int toJulian(int month, int day, int year) {
int count;
for(count = 1; count < month; ++count) {
day += daysInMonth(month, year);
}
return day;
}
You are using the month in every call. You need to use count.
You don't need the input argument day. You can have a local variable that is initialized to 0 before the loop starts.
The updated version:
int toJulian(int month, int year) {
int count;
int days = 0;
for(count = 1; count < month; ++count) {
days += daysInMonth(count, year);
}
return days;
}
leapYear.
int leapYear(int year) {
if (year % 400 == 0 && (year % 100 != 0 || year % 400 == 0)) {
return 1;
}
else {
return 0;
}
}
The logic in the if statement is not correct. It needs to be:
(year % 400 == 0 || (year % 100 != 0 && year % 4 == 0))
You can make the function to be more readable and less error prone by using:
int leapYear(int year) {
int ret = 0;
if ( year % 4 != 0 )
{
ret = 0;
}
else
{
if ( year % 100 != 0 )
{
ret = 1;
}
else
{
ret = (year % 400 == 0);
}
}
return ret;
}
yearsToDays
long yearsToDays(int year) {
int count;
long days;
for (count = BEGIN; count < year; ++count) {
days = 365 + leapYear(year);
}
return days;
}
You have not initialized days.
You are not accumulating the number of days. You are just assigning a value. The last returned value gets returned instead of the accumulated number of days.
You are using year in the loop instead of count in the argument to leapYear.
Here's the updated version:
long yearsToDays(int year) {
int count;
long days = 0;
for (count = BEGIN; count < year; ++count) {
days += 365;
days += leapYear(count);
}
return days;
}
printCalendar
void printCalendar(int startDay, int numDays) {
int dayid;
printHeader();
// Shifts position for the first date... sort of
for ( dayid = 0; dayid < startDay; dayid++ ) {
printf(" ");
}
// Supposedly prints all the dates for one month
for ( dayid = 1; dayid <= numDays; dayid++ ) {
printf("%3d", dayid );
// If the day is not before Saturday, start next line on Sun
if ( ( dayid + startDay ) % DAYS_IN_WEEK > 0 ) {
printf(" ");
}
else {
printf("\n" );
}
}
}
You are using up four spaces when printing the days of the month - "%3d" and " ". You need to write four spaces for each day up to startDay in the first for loop. Otherwise, the first row of output won't be properly aligned.
You need to use:
for ( dayid = 0; dayid < startDay; dayid++ ) {
printf(" ");
}
main
The line
startDay = (toJulian(month, 1, year) + yearsToDays(year)) % DAYS_IN_WEEK;
should be
startDay = (1 + toJulian(month, year) + yearsToDays(year)) % DAYS_IN_WEEK;
to account for (1) the fact that 1900-Jan-01 falls on a Monday and (2) change to the interface of toJulian.

Given a sorted array, output all triplets <a,b,c> such that a-b = c

Given a sorted array, output all triplets such that a-b = c.
The code I tried so far is as below; but there are following test cases-
-12 = -7 - 5
-12 = 3 - 15
-7 = -4 - 3
-7 = 3 - 10
-7 = 9 - 16
-4 = 5 - 9
3 = -4 - -7
5 = -7 - -12
5 = 15 - 10
10 = 3 - -7
10 = 15 - 5
15 = 3 - (-12)
16 = 9 - (-7)
while my program prints only-
-12 = -7 - 5
-7 = -4 - 3
-12 = 3 - 15
-7 = 3 - 10
-4 = 5 - 9
-7 = 9 - 16
5 = 15 - 10
means only the abs difference! Any suggestion ll be great help!
void binder(int*a, int n) {
int i;
for (i = 0; i < n; i++) {
int current = a[i];
int left = 0;
int right = n-1;
while (left < right) {
if ( left == i ) {
left++;
continue;
}
if (right == i) {
right--;
continue;
}
if (a[left] + a[right] < current) {
left++;
} else if (a[left] + a[right] > current) {
right--;
} else {
printf("\n %d = %d - %d",a[left],current, a[right]);
left++;
right--;
}
}
}
}
int main() {
int a[] = {-12, -7, -4, 0, 3, 5, 9, 10, 15, 16};
binder(a, 10);
return 0;
}
It seems as though the test case is also missing a triplet:
9 = 5 - (-4)
Try changing your printing from:
printf("\n %d = %d - %d",a[left],current, a[right]);
to:
printf("\n %d = %d - %d",a[left],current, a[right]);
printf("\n %d = %d - %d",a[right],current, a[left]);
This solution is O(n^3), but it should work.
void binder(int*a, int n)
{
for(int left = 0; left < n; left++)
{
for(int right = 0; right < n; right++)
{
for(int result = 0; result < n; result++)
{
if(left != right && left != result && result != right && a[left] - a[right] == a[result])
printf("\n %d = %d - %d", a[result], a[left], a[right]);
}
}
}
}
How about something like this:
HashTable table;
for b = 0 to n-1:
for c = 0 to n-1:
table[b + c] = <b, c>
end for
end for
for a = 0 to n-1:
if table[a] exists and (<b, c> in table[a] where b != a and c != a) then:
output <a, b, c>
end if
end for
So, if we consider "a=b+c", for each (b, c) pair of values, we place that in a hash table, associating it with the (b, c) pair [O(n^2)].
Then, we go through the array again and if a value appears in the hash table, and the associated pairs are for different indices, then we've found a new entry (rearranging the terms back into "a-b=c"). This step is O(n), resulting in a O(n^2) solution overall.
I think we can see this question as a variation on the "find pairs of values in an array that sum up to S, for a fixed S" problem.
If they are sorted, (and as Hanning pointed out, a-b=c is the same as a=b+c) you can start with the smallest b and c, and add them, and this should lead to the smallest a. Now while increasing b or c, a can only get bigger too, so you should have never to look back.
If you make a table of b's and c's and their sum (which should be one of the a's):
c\ b:-12 3 4 5 7 10 15 16
-12: -24, -19, -9, -7, -3, -2, 3, 4
-7: -9, -4, 6, 8, 12, 13, 18,
3: -8, -3, 7, 9, 13, 14, 19,
5: -7, -2, 8, 10, 14, 15,
9: -5, 0, 10, 12, 16,
10: -2, 3, 13, 15,
15: 3, 8, 18,
16: 4, 9, 19,
you see, that I omited the values on the lower right, because the previous value (from left) already exceeded the maximum a (15), so a higher value can't match.
Of course, for such a small number of equations, you waste much more time thinking about optimization, than you gain from omitting superfluous calculations. For much bigger sets of values, it might be useful, to optimize.
you have missed one more iteration/loop in your code. since you are using brute force strategy so analysis say that it will take O(n^3) space and you code's time complexity seems O(n^2).
here is the case which will help you to understand.
you check for :
a = b-c
and you skip the check for :
c = b-a

Resources