Working as a freelancer this is a constant problem to me. If I get it badly wrong I loose money.
The problem with estimating for programming is precisely that which several people have identified here - it's the unknowns and the gotchas that can blow and estimate off into never-never land.
So increasingly I what I use is a two-fold approach
A. If the problem is in a known domain on software I am totally familiar with I do a straightforward mental breakdown and give a quote. Often with clients they'll ask for a ballpark upfront when discussing the project and with these I'm usually happy to agree - I ere on the side of caution, but this is just experience building on previous projects.
B. If the problem is an unknown domain. In these case I'll try an identify what are the crux issues upfront and I will code a test case around them to 'scope' the problem. Sometimes one can persuade the client to pay for this as a 'feasibility' study but even if you can't putting in the time unpaid and scoping the problem is cheaper than quoting the client X then finding it needs nX time to solve.
Identifying which problems fall into A or B, and identifying what are the crux items in B, is down to experience, but I think the general rule is universally applicable: always isolate the crux issues up front and deal with these first. Once they are know then more conventional techniques can be used with some confidence.