[Tutor] generating independent random numbers
Dave Angel
davea at ieee.org
Thu Sep 30 06:38:31 CEST 2010
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<davea at 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
More information about the Tutor
mailing list