6

I am trying to solve Project Euler Problem 19.

I am not here to ask for the answer to the problem, but I noticed that every time my program runs, its output is different.

Please can someone explain why for me

"""
    Author: Luke Spademan
    Calculates answer to project euler problem id19
    https://projecteuler.net/problem=19
"""


def calculate():
    ans = 0
    months = {
        "jan": 31,
        "feb": 28,
        "mar": 31,
        "apr": 30,
        "may": 31,
        "jun": 30,
        "jul": 31,
        "aug": 31,
        "sep": 30,
        "oct": 31,
        "nov": 30,
        "dec": 31,
    }
    i = 1
    for year in range(1901, 2001):
        for month in months:
            months["feb"] = 28
            if year % 4 == 0 and not (year % 100 == 0 and year % 400 != 0):
                months["feb"] = 29
            if i % 7 == 0:
                ans += 1
            i += months[month]
    return ans

if __name__ == "__main__":
    answer = calculate()
    print(answer)
11
  • 1
    Running it with Python 2 produces same output every time, running it with Python 3 doesn't... Strange Commented Sep 4, 2017 at 9:49
  • 1
    Is that to do with a bug in python3, or my badly written code? Commented Sep 4, 2017 at 9:50
  • I get 172 with python3 all the time, cannot reproduce your error. Commented Sep 4, 2017 at 9:54
  • what version. I am running python 3.4.3 Commented Sep 4, 2017 at 9:55
  • my version is the same, 3.4.3 Commented Sep 4, 2017 at 9:56

2 Answers 2

6

The problem is that the result of the computation depends on the order in which months is iterated. As of Python 3.3, string hashing is randomized by default, meaning that this order will not be deterministic (until Python 3.6). You can read about how to make this program run deterministically here, although I think that your intention is to iterate months in a predefined order always, in which case it should probably be a list or an OrderedDict.

Sign up to request clarification or add additional context in comments.

3 Comments

It might be worth noting that Python 3.6 introduced a new dictionary implementation, which preserves order like an OrderedDict does. That behavior is considered an implementation detail for now (outside of a few specific cases like **kwargs), but it may become the official standard behavior in some future release.
confirmed that python3.6 gives the same answer everytime. Thankyou.
Note that it's not the only problem with OP's code.
0

With datetime

Before you get lost in implementation details about dicts and OrderedDicts, you could use datetime to know what the answer should be:

>>> from datetime import date
>>> sum(1 for month in range(1,13) for year in range(1901, 2001) if date(year, month, 1).weekday() == 6)
171

With list of tuples

Note that even with Python 3.6 or Python2 + OrderedDict, your code returns 172.

Your sunday test is written as i % 7 == 0. It means that the 1st day in your loop (1st of january 1901), which is a tuesday, should be initialized with i = 2.

To avoid any problem with unsorted dicts, you could simply use a list of tuples :

def calculate():
    ans = 0
    months = [('jan', 31), ('feb', 28), ('mar', 31), ('apr', 30), ('may', 31), ('jun', 30), ('jul', 31), ('aug', 31), ('sep', 30), ('oct', 31), ('nov', 30), ('dec', 31)]
    i = 2
    for year in range(1901, 2001):
        for month_name, days in months:
            if month_name == "feb":
              if year % 4 == 0 and not (year % 100 == 0 and year % 400 != 0):
                  days = 29
              else:
                  days = 28
            if i % 7 == 0:
                ans += 1
            i += days
    return ans

if __name__ == "__main__":
    answer = calculate()
    print(answer)

This code returns 171 with any Python version.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.