Real Ultimate Programming

The Home for People Who Like to Flip Out and Write Code

Project Euler: Problem 16

I’ve just finished solving Problem 16. It was a fairly straightforward problem, and at first I couldn’t decide how I wanted to solve it, so I decided to do it both ways and compare them. Here’s the script with both versions of the solution:

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
    import math

    def pure_numeric_sum_of_digits(num):
        """
        Finds the sum of the digits in num (presumed to be base-10).
    
        This version of the method operates purely on numbers.
    
        >>> pure_numeric_sum_of_digits(2 ** 15)
        26
        """
        running_total = 0
        for n in xrange(int(math.log10(num)) + 1):
            running_total += num % 10
            num //= 10
        return running_total

    def string_based_sum_of_digits(num):
        """
        Finds the sum of the digits in num (presumed to be base-10).
    
        This version of the method works by using a string representation
        of num and converting individual characters to numbers so we can
        operate on it as a sequence.
    
        >>> string_based_sum_of_digits(2 ** 15)
        26
        """
        sum([int(digit) for digit in str(num)])

    def problem_16():
        """Solves Problem 16 at Project Euler."""
        return string_based_sum_of_digits(2 ** 1000)

    if __name__ == '__main__':
        print problem_16()

Clearly, the string-based solution is more compact, but it has to be slower, right? strings are slower than ints and all that. Thanks to the optimization efforts of the Python implementers, the string-based solution is actually ~167% faster on my machine (I used cProfile on a 10000-iteration loop to make these measurements).

Back to flipping out…

Notes on Acts-as-taggable-on

If you’re using acts-as-taggable-on, you may have noticed the documentation is a bit… sparse. The following are some of the more helpful resources I’ve found.

  • The README from Acts as Taggable on Steroids (the inspiration for acts-as-taggable-on)
  • crunchytoast.com has a nice documentation effort

Finally, I ran into errors with trying to build a tag cloud when there were no tags to count. My solution was to embed

1
    @tags = Post.tag_counts || []

(or similar) into whichever method on the controller was responsible for the page to contain the tag cloud so that the default is an empty list instead of nil.

Back to flipping out…

Sneak Attack: Reversion

Reversion has to be one of the more clever applications of object serialization I’ve come across lately.

Back to flipping out…

Project Euler: Problem 15

This one took me a while, largely because I didn’t understand what they meant by backtracking. I was thinking of backtracking to a particular point, so I kept trying to use acyclic graphs, sometimes called forests. That’s not really what they meant, though. In the context of Problem 15, no backtracking just means you can’t go up and you can’t go left. After working a 3x3 version of the problem, I thought the values looked a little familiar; I was right. It’s a counting problem we covered in combinatorics oh so many years ago: Permutations with Repeated Elements. There are 40 steps to any given path (we have to go 20 steps down and 20 steps right). Since the definition of backtracking makes any given move down indistinguishable from any other move down, and any given move right indistinguishable from any other move right, the answer is 40!/(20!20!).

Back to flipping out…

Improving Browser Support for HTTP Authentication

One of the classic problems with HTTP Authentication has been the way browsers implement it: there’s no easy way to “log out” of a site. Once you’ve provided authentication tokens for a site, the browser keeps sending it. This decision has put a sharp dent in the adoption of standards-based authentication schemes. It doesn’t have to be this way. Bug 300002 is an enhancement request for Firefox that would add a UI element for telling the browser to stop. So far, this request has languished in undeserved obscurity; let’s put an end to that. Please vote up Bug 300002. If Firefox were to remedy this usability problem with HTTP authentication, maybe other browser makers would follow suit, and standards-based authentication would once again be seen as a viable option.

Back to flipping out…

Project Euler: Problem 14

Problem 14 was a fairly straightforward problem to solve, but I liked it a lot. One reason I liked it is that I enjoy playing with mathematical sequences, but also because it marked my first foray into TDD in Python. I’d heard about doctest, and I really like the concept, so I decided to use it when solving this problem. Here’s the code I used to find the solution:

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
    """Solves Problem 14 from Project Euler."""

    def _gen_sequence(seed, cur_sequence = None):
        """Generates a sequence following the rules from Problem 14.

        >>> _gen_sequence(13)
        [13, 40, 20, 10, 5, 16, 8, 4, 2, 1]"""
        if not cur_sequence:
            cur_sequence = []
        cur_sequence.append(seed)
        if seed == 1:
            return cur_sequence
        elif seed % 2:
            return _gen_sequence(3 * seed + 1, cur_sequence)
        else:
            return _gen_sequence(seed / 2, cur_sequence)

    def problem_14(upper_bound):
        """Finds the seed (< upper_bound and > 500000) for the longest sequence.

        >>> problem_14(502873)
        502137
        """
        cur_answer = 0, 0  # Track the length too, just out of curiosity.
        for seed in reversed(xrange(500001, upper_bound, 2)):
            cur_length = len(_gen_sequence(seed))
            if cur_length > cur_answer[1]:
                cur_answer = seed, cur_length
        return cur_answer[0]

    if __name__ == '__main__':
        print problem_14(1000000)

You can execute these tests (assuming Python 2.6) from the command-line with python -m doctest -v problem14.py. The output will resemble:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Trying:
        _gen_sequence(13)
    Expecting:
        [13, 40, 20, 10, 5, 16, 8, 4, 2, 1]
    ok
    Trying:
        problem_14(502873)
    Expecting:
        502137
    ok
    1 items had no tests:
        problem14
    2 items passed all tests:
       1 tests in problem14._gen_sequence
       1 tests in problem14.problem_14
    2 tests in 3 items.
    2 passed and 0 failed.
    Test passed.

Not only does doctest make it easy to do TDD, it reminds me somewhat of literate programming. It’s obviously not the same, but I think it encourages the sort of documentation that Knuth would approve. I know it definitely made me think more about documenting these simple functions.

Back to flipping out…

JavaScript Idioms Revisited

In an earlier post about JavaScript idioms, I talked about a common idiom for copying an array:

1
2
3
4
    var myArray = [];
    for (var i = 0; i < source.length; i++) {
        myArray[i] = source[i];
    }

In a comment, Jesse offers the following alternative:

1
    var args = Array.prototype.slice.apply(arguments);

To my eye, this is clearly preferable, and I hope more people use it in the future. Thanks for pointing it out, Jesse.

Also: here’s a good list of JavaScript idioms.

Back to flipping out…