Speak and Shout

Tuesday, March 29, 2005

Maximum code, minimum space

While solving the 3n+1 problem on the ACM-ICPC problem set archive, I used this piece of C-style boilerplate code every programmer will recognize.

long max_value = 0;
long val = 0;
for (long i=1, i < 1000000; i++)
{
    val = some_func(i);
    if (val > max_value)
        max_value = val;
}
return max_value;

Here, some_func is a function that returns a single value which I'm trying to optimize. For each value returned from the function, I'm comparing it with the maximum value I've seen so far and keeping the higher of the two.

This boilerplate code -- while simple to write and understand -- bugs me. For one thing, the only thing I'm interested in is the maximum value, but I have to assign the return value of the function to a temporary variable too. Then, there's the fact that there's three lines of code in the loop to express the concept "give me the maximum value from all the iterations of this function".

Actually, thinking through that last statement gave me an idea. How about instead:

long max_value = 0;
for (int i=1; i < 1000000; i++)
    max_value = max(some_func(i), max_value);

return max_value;

Much better. The extra variable is gone, and the body of the loop is reduced to a single line. It seems this is about as good as you can do with C/C++. I paid a little for this brevity ... over the million iterations, I lost about 100 ms with the one-line max function. That's in the noise for typical applications.

My favorite language, Python, is known for brevity. I wondered if I could do better than the C version.

My first attempt draws on one of my favorite language features, the list comprehension.
return max([some_func(x) for x in range(1, 1000000)])

This manages to combine the return statement, the loop, the function call, and the maximization logic into one line! Its only disadvantage is that two large lists are being generated -- one is by the range statement and the other is by the list comprehension.

Enter Python 2.4's generator expressions. The syntax is a little different than the list comprehension, but the idea is exactly the same. However, a generator expression builds only one list instead of two and wastes less memory.
return max(some_func(x) for x in range(1, 1000000))

Actually, it looks cleaner than the list comprehension anyway. Go, Python!

2 Comments:

  • Actually, I think your original C/C++ code example is wrong. Setting val = 0 and max_value = 0 means that as soon as it hits the for loop it will fail because i will be set to 1 which is greater than val. So the for loop code will never get executed. Or am I the one not thinking clearly today?

    By Blogger ScW, At 11:44 AM  

  • Fixed. Thanks for the catch.

    By Blogger Brandon Corfman, At 12:28 PM  

Post a Comment



<$I18N$LinksToThisPost>:

Create a Link

<< Home