|
|
|
|
|
by jlees
5493 days ago
|
|
The boundary between recreational mathematics and computer science is flimsy at best; while Project Euler may not make you the world's best programmer, it'll get you well entrenched in some of the fundamental brain tricks in computer science. That's how I got interested in the whole field - Informatics Olympiad papers and mathematical problems unified the "10 PRINT 'HELLO'" world with the algorithmic one. I think the latter is surprisingly neglected these days, especially among self-taught people (not to say you can't be a great self-taught programmer, but you're less likely to have come at it all from the mathematical world). |
|
I happen to believe that taste in crafting of program structure and selection of appropriate abstractions is more important than algorithmic acuity for most modern programming. Computational geometry, graph theoretical manipulations, dynamic programming and so on certainly have their uses, but they are usually a small core of something and not reimplemented often. Maintainable programs are a bigger issue IMO; and an excess of focus on the finer details of computational algorithms doesn't necessarily solve that issue.
I rather think it can hamper the goal. Really efficient algorithms often "break the rules", exploiting commonalities or attributes that cross abstraction boundaries. Take an ultra-simple example: finding the index of a (possibly missing) element in an unsorted array with a linear search. The fastest in-order sequential algorithm is to add the element being searched for to the end of the array, and then iterate through the array and halt when the element is found. This reduces the amount of work that needs to be done over a more simple search because it removes the need for a termination condition test (index in array less than length of array) on the search loop. But it also breaks other things; it won't work in the presence of threads, and it's surprising that a search operation is not a read-only operation. Adding may need a memory reallocation; if the array is large and the growth algorithm is geometric (which it should be), then it could very surprisingly cause an OOM. Sure, you can get around this by pre-allocating the required slot, and detecting multiple threads etc., but now you've made things more complicated and harder to maintain in the search for the most efficient algorithm. The goal of efficiency can cause more assumptions to be made or pre-conditions required, and for these assumptions / pre-conditions to leak across abstraction boundaries, ultimately making maintenance changes have multiplicative rather than additive complexity costs.
So I think it's fine to target big-O algorithmic costs when it makes sense and doesn't contort the software architecture too much, but applying an excess of problem insight can work against better architecture. Premature optimization, as tautologically as ever, is premature.
(I write as someone self-taught who competed in IOI etc. The problems sets were fun, but I wasn't under any illusions that I was learning a whole lot. Using recursion and branch pruning to solve combinatorial search problems is a distraction when you're better off looking at the bigger picture, dare I say it, the business picture.)