File: bday_cover.ll

package info (click to toggle)
lifelines 3.0.50-2
  • links: PTS
  • area: main
  • in suites: etch-m68k
  • size: 11,140 kB
  • ctags: 6,517
  • sloc: ansic: 57,468; xml: 8,014; sh: 4,255; makefile: 848; yacc: 601; perl: 170; sed: 16
file content (211 lines) | stat: -rw-r--r-- 5,819 bytes parent folder | download | duplicates (5)
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
/*
 * @progname    bday_cover.ll
 * @version     1 of 1994-11-02
 * @author      Andrew Deacon
 * @category
 * @output      Text
 * @description

A novelty report that lists on which days of the year people were born
and how many people share the same birthday. All valid birthdays
are considered. A valid birthday is one where the extracted birthday,
performed using extractdate(), has a month in the range 1-12 and a day
within that month.

This program works only with LifeLines.

The output is not sorted. The following are examples of
how to sort the output using UNIX sort:
# sort by frequency
sort +2n +0M bday.out
sort +2nr +0M bday.out
# sort by month
sort -M bday.out

*/

        global(julian)
        global(daysinmonth)

proc main ()
{
        table(day_counts)
        list(day_list)

        /* Formats/modes for date functions */
        monthformat(3) dayformat(1) dateformat(1)
        set(julian, 0) /* change to use Julian dates */

        /* Initialize counters */
        set(totaldays, 0) set(totalmonths, 0) set(totalbirths, 0)

        /* Iterate over whole database */
        forindi (indi, num) {

           /* if birthday recorded for individual */
           if (bth, birth(indi)) {

              /* Extract birthday for individual */
              extractdate(bth, birthday, birthmonth, birthyear)
              call get_days_in_month(birthday, birthmonth, birthyear)

              /* if valid birthday */
              if (and(gt(birthday, 0), le(birthday, daysinmonth))) {

                 /* Extract the month name and day */
                 set(bday, concat(substring(stddate(birth(indi)),1,6)," "))

                 /* if existing birthday found - just increment */
                 if(nmatch, lookup(day_counts, bday)) {
                    set(nmatch, add(nmatch, 1))
                 }
                 /* else new birthday - insert */
                 else {
                    set(totaldays, add(totaldays,1))
                    enqueue(day_list, bday)
                    set(nmatch, 1)
                 }
                 insert(day_counts, bday, nmatch)
                 set(totalbirths, add(totalbirths,1))

                 /* Extract the month name */
                 set(bmon, concat(substring(stddate(birth(indi)),1,4),"**"))

                 /* if existing birth month found - just increment */
                 if(nmatch, lookup(day_counts, bmon)) {
                     set(nmatch, add(nmatch, 1))
                 }
                 /* else new birth month - insert */
                 else {
                    set(totalmonths, add(totalmonths,1))
                    enqueue(day_list, bmon)
                    set(nmatch, 1)
                 }
                 insert(day_counts, bmon, nmatch)
              }
           }
        }

        /* Write report to file - use Unix sort to sort output! */
        "Distribution of birth days\n\n"
        "Month & day       Frequency\n\n"
        forlist(day_list, bday, num) {
                bday
                set(nmatch, lookup(day_counts, bday))
                col(sub(25, strlen(d(nmatch))))
                d(nmatch) "\n"
        }
        "Total birthdays in database: " d(totalbirths) "\n"
        "Total days (out of 366)    : " d(totaldays)   "\n"
        "Total months (out of 12)   : " d(totalmonths) "\n"
}

proc get_days_in_month(birthday, birthmonth, birthyear)
{
        /* code from a routine in "dates" by Jim Eggert */
        /* procedure sets global variable daysinmonth */
        set(daysinmonth, 31)
        if (or(le(birthmonth, 0), gt(birthmonth, 12)))
           { set(daysinmonth, 0) }
        elsif (or(or(eq(birthmonth, 9), eq(birthmonth, 4)),
               or(eq(birthmonth, 6), eq(birthmonth, 11))))
           { set(daysinmonth, 30) }
        elsif (eq(birthmonth, 2)) {
               if (and(eq(mod(birthyear, 4), 0),
                   or(julian, or(ne(mod(birthyear, 100), 0),
                                eq(mod(birthyear, 400), 0)))))
                 { set(daysinmonth, 29) }
               else
                 { set(daysinmonth, 28) }
        }
        else
           { set(daysinmonth, 31) }
}

/*

Sample output:

sorted by sort +2nr +0M sample.output and then edited

Distribution of birthdays

Total birthdays in database: 374
Total days (out of 366)    : 236
Total months (out of 12)   : 12

Month & day       Frequency

AUG 12                 6
SEP 12                 5
FEB 10                 4
MAR 03                 4
APR 12                 4
JUN 17                 4
JAN 06                 3
JAN 18                 3
JAN 29                 3
........
*/

/*
Below is a simple C program hack to check if your values
are similar to those generated randomly by the program.
Extract the program from these comment to compile and execute.
Change the RSEED to do different tests; change the ITERATIONS
to vary accuracy. Can also change the NUM_DAYS_REQUIRED
to the value obtained for your database and check if the people
required is similar.

#define RSEED 1576
#define NUM_DAYS 365
#define NUM_DAYS_REQUIRED NUM_DAYS
#define ITERATIONS 2000

#define FALSE 0
#define TRUE 1

static int days[NUM_DAYS];
static int num_got;
static int running_total;


int get_day() {
  return rand() % NUM_DAYS;
}

do_it() {
  int i;
  int j;
  int r;

  for (i = 0; i < NUM_DAYS; i++) {
    days[i] = FALSE;
  }
  num_got = 0;
  i = 0;

  while (num_got < NUM_DAYS_REQUIRED) {
    i++;
    r = get_day();
    if (!days[r]) {
      days[r] = TRUE;
      num_got++;
    }
  }
  printf("Required %d people to cover %d days.\n",i, NUM_DAYS_REQUIRED);
  running_total = running_total + i;
}

main() {
  int i;

  running_total = 0;
  srand(RSEED);
  for (i = 0; i < ITERATIONS; i++) {
    do_it();
  }
  printf("Average was %d.\n",(int)(running_total/ITERATIONS));
}

*/