On 2:59 PM, Dave Angel wrote:
 On 9/29/2010 9:17 PM, Carter Danforth wrote:
On Wed, Sep 29, 2010 at 1:53 PM, Dave Angel<da...@ieee.org>  wrote:

  On 9/28/2010 5:11 PM, Carter Danforth wrote:

Thanks for the replies, Dave and Joel. The reason I'm not just using the time or datetime modules for a random date is because it's restricted to 1970-2038; I'm pulling dates from 1600-3099. Thanks a lot for the pointer about the leap years, Dave, as well the class instances; just updated it
and
it's all working now, and also included the rest of the code too w/ answer
verification and time tracking.

I want to start using this program to test myself for speed calculation using Zeller's formula, it's pretty cool for determining the days of dates
-
http://mathforum.org/dr/math/faq/faq.calendar.html

Because of the way variables C and D are split up from the year in the
formula, I split up the year for self.c and self.y.

------------------------

import random, time, datetime, calendar

class Date:
     def __init__(self):
         self.c = random.randint(16,30)
         self.y = random.randint(0,99)
         self.month = random.randint(1,12)
         self.year = self.c*100 + self.y

         apr = [4,6,9,11]
         feb = [2]
         notleap = [1700, 1800, 1900, 3000]

         if self.month in feb:
             if self.year%4 == 0:
                 if self.year in notleap:
                     self.k = random.randint(1,28)
                 else:
                     self.k = random.randint(1,29)
             else:
                 self.k = random.randint(1,28)
         elif self.month in apr:
             self.k = random.randint(1,30)
         else:
             self.k = random.randint(1,31)

         if self.month in [1,2]:
             d = self.y - 1
             m = self.month + 10
         else:
             d = self.y
             m = self.month - 2

         z = self.k + (13*m-1)/5 + d + d/4 + self.c/4 - 2*self.c

         if z<   0:
             r = (abs(z)/7)*7 + z + 7
         else:
             r = z%7

dict = { 0: 'Sunday', 1: 'Monday', 2: 'Tuesday', 3: 'Wednesday',
4:
'Thursday', 5: 'Friday', 6: 'Saturday' }
         self.day = dict[r]

t1m = time.localtime().tm_min
t1s = time.localtime().tm_sec
t1 = t1m + t1s/100.0
n = 0
x = 0

while n<   10:
     newdate = Date()

     print '\n',calendar.month_name[newdate.month], newdate.k,',',
newdate.year,'=',
     answer = raw_input()
     if answer.capitalize() == newdate.day:
         pass
     else:
         x += 1
     n += 1

t2m = time.localtime().tm_min
t2s = time.localtime().tm_sec
t2 = t2m + t2s/100.0
td = t2 - t1

print '\n',x,'out of 10 wrong\nAvg time/question:',td/10,'\nTotal
time:',td

<snip>

You top-posted again. Put your comments after the part you're quoting,
not before.

You still have a problem in the code, and I still think it's in the
2*self.c, though I don't have time to debug it.

Look up the day for 1/1/2099, and for 1/1/2100 and it comes out the same. That's not correct. No adjacent years start on the same day, it's always
either one day or two.

You have too much in one function (method), which makes it hard to debug it. Factor it into separate functions, and then test each independently. And using k for day and d for year make no sense to me, though perhaps it
does in some other language.

DaveA


Hey Dave, you probably left c and y alone when comparing the years. If the date's 1/1/2099, then self.c = 20 and self.y=99. If you try doing it again while changing those values, for 1/1/2099, the day comes out to be Thursday,
and for 1/1/2100 you'll get Wednesday.

Glad you pointed out the 2100 date though, there actually was a problem in it, but it's not the 2*self.c; I had to account for d = y - 1 when y = 00
(zeller subtracts months by 2, so it needs to be the previous yr for
jan/feb).

Below is the updated code, I put in a few comments to make it read easier.

----------------------

import random, time, datetime, calendar

class Date:
     def __init__(self):
         self.c = random.randint(16,30) # first two digits in a year
         self.y = random.randint(0,99)  # last two digits in a year
         self.month = random.randint(1,12)
         self.year = self.c*100 + self.y

         apr = [4,6,9,11]
         feb = [2]
notleap = [1700, 1800, 1900, 2100, 2200, 2300, 2500, 2600, 2700,
2900, 3000]

         if self.month in feb:          # assigns days, given the month
             if self.year%4 == 0:
                 if self.year in notleap:
                     self.k = random.randint(1,28)
                 else:
                     self.k = random.randint(1,29)
             else:
                 self.k = random.randint(1,28)
         elif self.month in apr:
             self.k = random.randint(1,30)
         else:
             self.k = random.randint(1,31)

         if self.month in [1,2]:        # months in zeller's rule are
subtracted by 2
             if self.y == 0:            # need to acct for jan/feb year
change
                 d = 99
                 m = self.month + 10
             else:
                 d = self.y - 1
                 m = self.month + 10
         else:
             d = self.y
             m = self.month - 2

         z = self.k + (13*m-1)/5 + d + d/4 + self.c/4 - 2*self.c  # -->
Zeller's formula

if z< 0: # the remainder of z/7 determines the
day of the week
             r = (abs(z)/7)*7 + z + 7   # need to account for negative z
values by adding 7 to remainder
         else:
             r = z%7

         week =
('Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday')
         self.day = week[r]

t1m = time.localtime().tm_min
t1s = time.localtime().tm_sec
t1 = t1m + t1s/100.0
n = 0
x = 0

while n<  10:
     newdate = Date()
     print '\n  ',calendar.month_name[newdate.month], str(newdate.k) +
',',newdate.year,'=',
     answer = raw_input()
     if answer.capitalize() == newdate.day:
         pass
     else:
         x += 1
     n += 1

t2m = time.localtime().tm_min
t2s = time.localtime().tm_sec
t2 = t2m + t2s/100.0
td = t2 - t1

print '\n',x,'out of 10 wrong\nAvg time/question:',td/10,'\nTotal time:',td

In order to check it out, I refactored the zeller portion into a separate function. Since there was no reason to make it a class member, I had to do a lot of editing. And since I couldn't understand the one-letter symbols, I changed them as well.

Your code is much more verbose than needed. If you just used 4 digit years, that last bug wouldn't have happened.

I think you have another bug, the logic for z<0 is incorrect, but also unnecessary. For some negative values, it'll produce a 7, which would give you a subscript error in your week[r] expression. But Python does the right thing with remainders of negative values, so all you need is the %7.

Consider using 306/10 for the month, and 1461/4 for the year, and then -year/100, and + year/400. Then you get actual number of days, Make that a function, and when you call it here, you use modulo 7 for day of week. But you can then test it independently.

How about:

def getDay2(year, month, day):
    if month < 3:
        year -= 1
        month += 12
    z = day + (month-4)*306/10 + year*1461/4 - year/100 + year/400
    return z- 275

Or of course:

def getDay3(year, month, day):
    mydate = datetime.date(year, month, day)
    return mydate.toordinal()

which gives identical results for all dates in that range.

And of course if you write one more function:

def getDate(days):
    mydate = datetime.date.fromordinal(days)
    return mydate.year, mydate.month, mydate.day

then you can make your random date much simpler as well:

year, month, day = getDate(random.randint(584023, 1095727))

assuming you want to fix the other bug: date range from 1600 through 3000. Your present code goes to 3099.

The body of your method then looks something like (untested)

self.year, self.month, self.day = getDate(random.randint(584023, 1095727))
    r = getDay2(self.year, self.month, self.day)

week = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]
  self.dayname = week[r]

Incidentally, there's another problem in your code -- when comparing the day string, you uppercase one of them, but not the other.



DaveA


Sorry, I mentioned %7, but forgot to include it in my last sample. It's still untested, but closer.

self.year, self.month, self.day = getDate(random.randint(584023, 1095727))
r = getDay2(self.year, self.month, self.day)
week = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]
self.dayname = week[r%7]

DaveA

_______________________________________________
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor

Reply via email to