calc month length

ZX80, ZX 81, ZX Spectrum, TS2068 and other clones
Post Reply
cborn
Well known member
Posts: 267
Joined: Tue Oct 06, 2020 7:45 pm

calc month length

Post by cborn »

hi
Dom rewrote my simple clock
https://z88dk.org/forum/viewtopic.php?p=19905#p19905

and now i have a bit to big routine that actualy should work in a single line
it calculates the length of a month in days. just a simple calc.
it DOES give a compile warning about atol ??

Code: Select all


// gcc monthdays.c -o monthdays -lm   2> monthdays.log 

// modulo MONTH of 28+1,30 or 31 days,data table or calc?
//                 |01  02           03  04  05  06  07  |08  09  10  11  12 |
//                 |jan feb+ly       mch apr may jun jul |aug sep oct nov dec|
// odd=1-7    b4=0 |31, 28+leapyear, 31, 30, 31, 30, 31, |31, 30, 31, 30,  31|
// even=8-12  b4=1 |odd=30+1 feb=30-2+leapyear           |even=30+1          |
// odd = (month % 2) * (month>7)
// monthlen = 30 +odd -2*(month=2) +leapyear*(month=

// this routine should be only a SINGLE line with 2 or max 4 variables, month, monthlen, leapyear, odd


#include <stdio.h>

int main (int argc, char *argv[])
{
 int leapyear, odd, month, monthlen ;

 month = atol(argv[1]) ;
 leapyear  = atol(argv[2]) ;

 printf ("month %d\n",month);

 odd = month % 2;
 printf("odd %d\n");
 if (month > 7) odd=!(month % 2) ;
 printf("odd %d\n");

 monthlen = 30 ;
 monthlen = monthlen + odd ;
 monthlen = monthlen - 2*( month == 2) ;
 monthlen = monthlen + leapyear*( month == 2) ;

 printf( "month %d = %d days in LP=%d being odd %d \n", month, monthlen, leapyear, odd);

 return monthlen;
}
User avatar
dom
Well known member
Posts: 2072
Joined: Sun Jul 15, 2007 10:01 pm

Re: calc month length

Post by dom »

atol() is in <stdlib.h> so you need to include it
cborn
Well known member
Posts: 267
Joined: Tue Oct 06, 2020 7:45 pm

Re: calc month length

Post by cborn »

Yes, i just realised
#include <stdlib.h> // atol()

i have to check reversed what a command actualy whats
i checked
https://www.tutorialspoint.com/c_standa ... n_atol.htm
and at the left site off the screen you can see in which LIB it is organised

so here is the same file but complete

Code: Select all


// gcc monthdays.c -o monthdays -lm   2> monthdays.log 

// modulo MONTH of 28+1,30 or 31 days,data table or calc?
//                 |01  02           03  04  05  06  07  |08  09  10  11  12 |
//                 |jan feb+ly       mch apr may jun jul |aug sep oct nov dec|
// odd=1-7    b4=0 |31, 28+leapyear, 31, 30, 31, 30, 31, |31, 30, 31, 30,  31|
// even=8-12  b4=1 |odd=30+1 feb=30-2+leapyear           |even=30+1          |
// odd = (month % 2) 
// if (month>7) odd = !odd ;
// monthlen = 30 +odd -2*(month=2) +leapyear*(month=

// this routine should be only a SINGLE line with 2 or max 4 variables, month, monthlen, leapyear, odd


#include <stdio.h>
#include <stdlib.h>  // atol()

int main (int argc, char *argv[])
{
 int leapyear, odd, month, monthlen ;

 month = atol(argv[1]) ;
 leapyear  = atol(argv[2]) ;

 printf ("month %d\n",month);

 odd = month % 2;
 printf("odd %d\n");
 if (month > 7) odd=!(month % 2) ;
 printf("odd %d\n");

 monthlen = 30 ;
 monthlen = monthlen + odd ;
 monthlen = monthlen - 2*( month == 2) ;
 monthlen = monthlen + leapyear*( month == 2) ;

 printf( "month %d = %d days in LP=%d being odd %d \n", month, monthlen, leapyear, odd);

 return monthlen;
}
cborn
Well known member
Posts: 267
Joined: Tue Oct 06, 2020 7:45 pm

Re: calc month length

Post by cborn »

i would like to get it on a single line, but i guess it wont
meanwhile the value off 'odd' is always extra large, although when USED its only 1 or 0.

so its still the same, but a bit shorter again, probably i should turn it into a void ??
for now the last modify, as my home work, its "poinless"

Code: Select all


// gcc monthdays.c -o monthdays -lm   2> monthdays.log 

// modulo MONTH of 28+1,30 or 31 days,data table or calc?
//                 |01  02           03  04  05  06  07  |08  09  10  11  12 |
//                 |jan feb+ly       mch apr may jun jul |aug sep oct nov dec|
// odd=1-7    b4=0 |31, 28+leapyear, 31, 30, 31, 30, 31, |31, 30, 31, 30,  31|
// even=8-12  b4=1 |odd=30+1 feb=30-2+leapyear           |even=30+1          |
// odd = (month % 2) 
// if (month>7) odd = !odd ;
// monthlen = 30 + odd -( (2-leapyear) * (month==2) )

// can this routine be only a SINGLE line ?


#include <stdio.h>
#include <stdlib.h>  // atol()

int main (int argc, char *argv[])
{
 int odd, monthlen ;

 odd = atol(argv[1]) % 2 ;
 if (atol(argv[1]) > 7) odd = !odd ;
 printf("odd %d   is not 0 or 1 ??\n");

 monthlen = 30 + odd  - (( 2 - atol(argv[2]) ) * ( atol(argv[1]) == 2) ) ;

 printf( "month %d = %d days while leapyear=%d\n", atol(argv[1]), monthlen, atol(argv[2]));

 return monthlen;
}
cborn
Well known member
Posts: 267
Joined: Tue Oct 06, 2020 7:45 pm

Re: calc month length

Post by cborn »

Code: Select all

#include <stdio.h>
int monthlength(int month, int isleapyear)
{
 int odd;
 odd=month%2;
 if (month>7) odd=!odd;
 return 30+odd-((2-isleapyear)*(month ==2));
}

int main (){
printf ("%d\n",monthlength(2,0));
printf ("%d\n",monthlength(2,1));
}
if i know how to create 'odd' in a single formula then the whole routine can be a return value !
cborn
Well known member
Posts: 267
Joined: Tue Oct 06, 2020 7:45 pm

Re: calc month length

Post by cborn »

faster then my mind thinks
here is the single line solution
any comment is welcome

Code: Select all


// gcc monthlength.c -o monthlength -lm   2> monthlength.log 

// modulo MONTH of 28+1,30 or 31 days,data table or calc?
//                 |01  02           03  04  05  06  07  |08  09  10  11  12 |
//                 |jan feb+ly       mch apr may jun jul |aug sep oct nov dec|
// odd=1-7    b4=0 |31, 28+leapyear, 31, 30, 31, 30, 31, |31, 30, 31, 30,  31|
// even=8-12  b4=1 |odd=30+1 feb=30-2+leapyear           |even=30+1          |

// odd = (month % 2) 
// if (month>7) odd = !odd ;
// monthlength = 30 + odd -( (2-leapyear) * (month==2) )

// can this routine be only a SINGLE line ?


#include <stdio.h>
int monthlength(int month, int isleapyear)
{
 return 30+ ( month%2 && (month<=7) ) + ( !(month%2) && (month>7) ) -((2-isleapyear)*(month ==2)) ;
}

int main (){
printf ("%d\n",monthlength(2,0));
printf ("%d\n",monthlength(2,1));
}
i think i feal satisfied !
cborn
Well known member
Posts: 267
Joined: Tue Oct 06, 2020 7:45 pm

Re: calc month length

Post by cborn »

after a nice disccusion on WOS ( https://worldofspectrum.org/forums/disc ... nt_1000358 )
i finaly came up with this, from which Paradigm mentions its not very strong C
what is the common thoughets about a double NOT? like !!(this) ??

Code: Select all


// gcc monthlength.c -o monthlength -lm   2> monthlength.log 

// modulo MONTH of 28+1,30 or 31 days,data table or calc?
//                 |01  02           03  04  05  06  07  |08  09  10  11  12 |
//                 |jan feb+ly       mch apr may jun jul |aug sep oct nov dec|
// odd=1-7    b4=0 |31, 28+leapyear, 31, 30, 31, 30, 31, |31, 30, 31, 30,  31|
// even=8-12  b4=1 |odd=30+1 feb=30-2+leapyear           |even=30+1          |

// odd = (month % 2) 
// if (month>7) odd = !odd ;
// monthlength = 30 + odd -( (2-leapyear) * (month==2) )

// https://en.wikipedia.org/wiki/Knuckle_mnemonic
// https://worldofspectrum.org/forums/discussion/60707/length-of-month-calculation#latest
// with some nice suggestions about months, weeks and days!! thanks!
// eg year % 4 && !year % 400

#include <stdio.h>
int monthlength(int month, int year)
{
 return 30+((month<=7)?(month%2):(!(month%2)))-((2-((!(year%4)&&!!(year%100))||!(year%400)))*(month==2));
}

int main (){
int x ;
for (x=1299 ; x<=2100 ; x++ ) printf ("%d  Feb=%d\n",x,monthlength(2,x));
}

cborn
Well known member
Posts: 267
Joined: Tue Oct 06, 2020 7:45 pm

Re: calc month length

Post by cborn »

now i use 'short if/then/else' and FEW brackets all in 1 line.

Code: Select all


// gcc monthlength.c -o monthlength -lm   2> monthlength.log 
//  by Chris Born for public domain
// modulo MONTH of 28+1,30 or 31 days,data table or calc?
//                 |01  02           03  04  05  06  07  |08  09  10  11  12 |
//                 |jan feb+ly       mch apr may jun jul |aug sep oct nov dec|
// odd=1-7    b4=0 |31, 28+leapyear, 31, 30, 31, 30, 31, |31, 30, 31, 30,  31|
// even=8-12  b4=1 |odd=30+1 feb=30-2+leapyear           |even=30+1          |

// odd = (month % 2) 
// if (month>7) odd = !odd ;
// monthlength = 30 + odd -( (2-leapyear) * (month==2) )

// https://en.wikipedia.org/wiki/Knuckle_mnemonic
// https://worldofspectrum.org/forums/discussion/60707/length-of-month-calculation#latest
// with some nice suggestions about months, weeks and days!! thanks!
// eg year % 4 && !year % 400

#include <stdio.h>
int monthlength(int month, int year)
{
 return 30 +(month<=7?month%2:!(month%2)) -(month==2?2-((!(year%4)&&(year%100))||!(year%400)):-0);
}

int main (){
int x ,y=4;

for (x=1 ; x<=12 ; x++ ) printf ("year %d month %d\n",y,monthlength(x,y));
printf("\n");
for (x=1999 ; x<=2101 ; x++ ) printf ("%d  Feb=%d\n",x,monthlength(2,x));
}
Stefan
Member
Posts: 19
Joined: Fri Nov 29, 2013 10:21 pm

Re: calc month length

Post by Stefan »

What are you trying to achieve with a one-liner?

Unless you are writing source code on your target platform I would at least make it a bit more friendly on the eyes:

Code: Select all

    return
        30
        + ( month % 2 && ( month <= 7 ) )
        + ( !( month % 2 ) && ( month > 7 ) )
        - ( ( 2 - isleapyear ) * ( month == 2 ) ) ;
Additionally have you looked at the size of your binary? When I compile it for SAM Coupé (zcc +sam month.c -o month.bin -create-app), with some extra printing code, it weighs in at 6559 bytes. If I change the one liner to a less pleasing, but simpler switch / case statement:

Code: Select all

    switch ( month ) {
        case 2: return 28 + isleapyear;
        case 4: return 30;
        case 6: return 30;
        case 9: return 30;
        case 11: return 30;
        default: return 31;
    }
My binary then compiles to 6421 bytes which is 138 bytes shorter.
cborn
Well known member
Posts: 267
Joined: Tue Oct 06, 2020 7:45 pm

Re: calc month length

Post by cborn »

Thanks for your comment ans case example. part off the oneliner is to tease my brain and learn better C.
I was not concerned about the size off the outcome, although the routine is a bit related to the zxtime() from my sysviewer attempt. thats a 20k routine and has no use with that size. in asm i did some with an BCD realtime clock and perhaps make it into a calender.
the 6.5k from your result is for a standalone aproach, but its shows that a calculating can be longer then a decision rule.
you keep isleapyear as separate variable, probably thats better aswell like for the length of a leapyer, 365+leapyear is 365 or 366.
so the case is now, i got it working and now i have a better solution aswell
thank you
Post Reply