Kirjautuminen

Haku

Tehtävät

Keskustelu: Koodit: PL/I: Ongelman ratkaisua bittimerkkijonojen avulla

jalski [23.02.2012 01:36:04]

#

Bittimerkkijonojen avulla voidaan helposti ja erittäin nopeasti selvittää vaikka kaikki vuoden 2012 perjantai 13. päivät.

LYHYT TOIMINTA KUVAUS:

friday bittimerkkijono:

karkausvuodessa on 366 päivää ja jokaista päivää vastaa yksi bitti. Viikossa on seitsemän päivää ja kalenterista voidaan katsoa, että ensimmäinen perjantai on kuudes päivä. Näitä seitsemän bitin sarjoja mahtuu karkausvuoteen 52 ja kaksi bittiä tarvitsee vielä lisätä, jotta saadaan 366 bittiä täyteen.

thirteenth bittimerkkijono:

Sisältää kaikkien karkausvuodessa olevien kuukausien 13. päivät.


Vuoden perjantai 13. päivät saadaan siis yksinkertaisesti näiden bittijoukkojen leikkauspisteistä AND-operaatiolla.

*PROCESS MARGINS(1, 120);

 f13th: proc options (main);
   dcl jan1st fixed bin (31);
   dcl date char (8);
   dcl result bit (366);
   dcl friday bit (366) init (((52)'0000010'b || '00'b));
   dcl thirteenth bit (366)
                  init (((12)'0'b || '1'b || (30)'0'b
                        || '1'b ||  (28)'0'b || '1'b || (30)'0'b
                        || '1'b ||  (29)'0'b || '1'b || (30)'0'b
                        || '1'b ||  (29)'0'b || '1'b || (30)'0'b
                        || '1'b ||  (30)'0'b || '1'b || (29)'0'b
                        || '1'b ||  (30)'0'b || '1'b || (29)'0'b
                        || '1'b ||  (18)'0'b));

   dcl (days, daystodate, substr, length, search) builtin;

   jan1st = days('01012012', 'DDMMYYYY');

   put list ('Friday, the 13th dates in 2012:');
   put skip;

   result = friday & thirteenth;
   call friday13th(1);


   friday13th: proc (i) recursive;
     dcl i fixed bin;

	 dcl j fixed bin;

	 j = search(result, '1'b, i);
	 if j ^= 0 then do;
	   date = daystodate(jan1st + j - 1, 'DDMMYYYY');
	   put skip list (substr(date, 1, 2) || '.' || substr(date, 3, 2) || '.' || substr(date, 5, 4));
	   call friday13th(j+1);
	 end;
   end friday13th;

 end f13th;

Ajettaessa ohjelma saadaan tulokseksi:

Friday, the 13th dates in 2012:

13.01.2012
13.04.2012
13.07.2012

Perinteisempi ja yksinkertaisempi (tylsempi) tapa selvittää nuo vuoden 2012 perjantai 13. päivät voisi olla:

*PROCESS MARGINS(1, 120) pp(macro);
%replace FRIDAY by 6;

 f13th: proc options (main);
   dcl wd fixed bin (31);
   dcl i fixed bin;

   dcl 1 date,
	     2 dd   pic '99' init ('13'),
		 2 mm   pic '99' init ('01'),
		 2 yyyy pic '9999' init ('2012');

   dcl (days, weekday, string) builtin;

   put list ('Friday, the 13th dates in 2012:');
   put skip;

   do i = 1 to 12;
     wd = weekday(days(string(date), 'DDMMYYYY'));
	 if wd = FRIDAY then
	   put skip list(date.dd || '.' || date.mm || '.' || date.yyyy);
	 date.mm += 1;
   end;

 end f13th;

Bittimerkkijonoja apuna käyttäen onnistuu myös kalenteri viikkonumeron ratkaiseminenkin helposti:

*PROCESS MARGINS(1, 140);

 test: proc options (main);
   dcl 1 date_type based,
         2 day   pic'99',
         2 month pic'99',
         2 year  pic'9999';

   dcl d like date_type;

   /* fill date structure */
   d.day   = '01';
   d.month = '01';
   d.year =  '2012';

   /* test our proggy */
   put skip list (trim(week(d)));

 /**************************************************************************************************************************************/
   (STRINGRANGE, SUBSCRIPTRANGE):
   week: proc (day) returns (fixed bin (31));
     dcl day like date_type;

     dcl (from, to) like date_type;
     dcl (days_from, days_to) fixed bin (31);
     dcl total_days fixed bin (31);
     dcl week_index fixed bin (31);
     dcl weeknro fixed bin (31);
     dcl result bit (*) aligned controlled;
     dcl weeks (7) bit (7) aligned nonasgn init ('0100000'b, '0010000'b, '0001000'b, '0000100'b, '0000100'b, '0000010'b, '0000001'b);
     dcl masks (7) bit (7) aligned nonasgn init ('0111100'b, '1111000'b, '1110001'b, '1100011'b, '1000111'b, '0001111'b, '0011110'b);
     dcl bool bit (1);

     dcl (days, weekday, tally, substr, lbound, hbound, copy, omitted) builtin;

     /* we start from first of january, naturally */
     from.day   = '01';
     from.month = '01';
     from.year  = day.year;

     to = day;

     days_from = days(string(from), 'DDMMYYYY');
     days_to   = days(string(to), 'DDMMYYYY');

     /* calculate required length for the bit string */
     total_days = days_to - days_from + 1;
     if total_days <= 0 then return (0);

     /* allocate bit string, holding date range */
     allocate result bit (total_days);

     /* fill bit string with correct rotation of the week pattern */
     week_index = weekday(days_from);
     result = copy(weeks(week_index), total_days / 7) || substr(weeks(week_index), 1, mod(total_days, 7));

     /* find the number of weeks starting on monday */
     weeknro = tally(result, '1'b);

     /* free allocated storage */
     free result;

     /* first week can be partial and if it includes thursday, then add it to the result */
     bool = substr(masks(week_index), 1, 1);
     If bool then weeknro += 1;

     /* maybe first days of the year belong to week numbering of the previous year? */
     if weeknro <= 0 then
       do;
         from.year -= 1;
         to = from;
         to.day   = '31';
         to.month = '12';

         days_from = days(string(from), 'DDMMYYYY');
         days_to   = days(string(to), 'DDMMYYYY');

         total_days = days_to - days_from + 1;
         if total_days <= 0 then return (0);

         allocate result bit (total_days);

         week_index = weekday(days_from);
         result = copy(weeks(week_index), total_days / 7) || substr(weeks(week_index), 1, mod(total_days, 7));

         weeknro = tally(result, '1'b);
         free result;
       end;
     return (weeknro);
   end week;
 /**************************************************************************************************************************************/
 end test;

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta