The Dirty Little Secrets of Real-World Math
In my “Real-World Math” article that posted to StickyMinds on July 14, I didn’t have room to explore some of the dark secrets underlying the article. First, discussing mathematical topics with my peers and editors often gave me feelings of inadequacy. I mentioned probability theory, and one person starts to talk about how he regularly uses combinatorics to analyze test inputs. The terms he used sounded vaguely familiar, but it would have taken a lot of study for me to really grok what he was doing. When he related a story about bivariate data, I knew I was really on shaky ground. When I posed a question on the Toolsmith Guild about using logarithms to speed up the search for the boundary between a pass and a failure in a test, people started talking about root finding algorithms, slopes, and convergence, and I feared that I didn’t have the foundation for having an intelligent conversation.
Still, I pressed on, determined to write about only things that I understand reasonably well. The finished result, though, doesn’t show how the sausage was made.
It’s all story problems
Remember how annoying it was to do “story problems” in math class, where you weren’t spoon-fed the numbers you needed to plug in to a formula? Well, bad news - most real-world math challenges are story problems, and the relatively simple algebra example in my Real World Math article was one of them. I didn’t describe the difficulty I had in setting up the problem, starting with defining the variables. Is “D” the number of developers before or after some of them become testers? Do I need one variable for before and another for after? “T” is the number of testers, which is 0 right now, but may be non-zero later. I had a few false starts before I decided that it would work best for all variables to reflect the state of things after some of the developers had become testers.
I first set up the equations like this:
T = D / 4
T + D = 200
And solved for D like this:
T + D = 200
D / 4 + D = 200
D(1/4 + 1) = 200
D = 200 / 1.25
D = 160
This is somewhat more complex than the final version I settled on for the article, though it’s just as valid. It seemed a bit more straightforward to represent the first formula as “D = T * 4″, and I solved for T in the calculations instead. I was able to avoid the ugly “1.25″ in the new version.
I imagine that textbook authors go through this same process, and while it’s nice that the published version looks elegant and easy to understand, I think people can get very frustrated when their own calculations look uglier and more belabored than the polished examples in the books. Real-world math is uglier than the textbooks, and my own article, imply that it is.
Bad test code
While writing about the modulo function, I found a bug in my test code. I was keeping a count of the total number of virtual users that had been started, like this:
wlGlobals.userCount++
wlLocals.userNum = wlGlobals.userCount % wlGlobals.totalUsers
This code has a race condition, because it’s multi-threaded. Thread 1 could execute “wlGlobals.userCount++”, then get interrupted so thread 2 can run, which then also executes “wlGlobals.userCount++”, and when we eventually switch back to thread 1, it ends up using the same userCount value as thread 2. I explored ways to do locking to try to make the code thread-safe, but then found the built-in “ClientNum” variable, so I didn’t need to keep my own count after all.
I often find bugs in my test code when trying to explain it to other people. I should do that more often.
How does a logarithm work?
In the article, I write about my disk stress test that chooses a chunk size using this formula: “int exp(rand(log($filesize)))”. I admitted that I still don’t feel like I understand logarithms well enough to understand why this works, so I ran some experiments that showed that it does accomplish what I wanted. I knew I wanted a formula that used a logarithm function, and I used a good deal of intuition to cobble together the formula. Maybe my subconscious understands it, but I still have a nagging sense that I don’t understand what’s going on. I understand the basic concept. I can even draw the rough shape of it on a graph. But I still don’t feel I understand why generating a random number after taking the logarithm then immediately reversing the logarithm actually works. Maybe this is why we’re supposed to show our work when we do our math homework. In this case guessed the answer without doing the work at all.
While trying to study logarithms with Google’s help, I saw that the derivative of the logarithm function is the inverse function (1/x), and a graph of the inverse function looks just like I want the distribution of my test values to be. But I wasn’t about to try to bring calculus into the conversation. That would just ramp up my feelings of inadequacy even further.
I even resorted to slide rules. Having heard that slide rules use a logarithmic scale, I asked my father-in-law to get out his slide rule and show me how it works. He gingerly handed me his prized slide rule, which his own father had used. And I dropped it. Shattered the cursor beyond repair. Anyway, long story short, with eBay’s help I found a replacement cursor, and several slide rules I could keep for myself. But I still haven’t gotten that lesson, and the online tutorials I found have shown me that these things aren’t as simple as I had hoped. So while previous generations may have a deep understanding of what makes a logarithm tick, they have years of experience that my digital calculators have deprived me of.
Oh, one more thing. The first version of the disk stress algorithm that I used actually first calculated the position of the file to start writing from using a random number on a linear scale, then used the logarithmic scale to calculate the chunk size. The range of the chunk size in that case was from 1 to the end of the file from that starting position, making the average chunk size perhaps half as big as it is with the formula I described in the article. I decided it would be more straightforward to first calculate the chunk size, up to the full length of the file, then calculate a random starting position using a range of possible positions where the chunk wouldn’t run off the end of the fixed file size. So again, after having to explain my code, I found a way to improve it.
Popularizing math
I think we need more authors to help popularize mathematical concepts. Like Ivars Peterson did in Islands of Truth: A Mathematical Mystery Cruise. But Peterson talks about four dimensional geometry and fractals, not more practical applications that people are likely to use regularly. I even had a hard time getting into George Polya’s classic book How to Solve It, often on recommended reading lists for computer professionals.
Is math just inherently too difficult to write about in a way that people understand? For my StickyMinds article, we even had to seek outside help to proofread the math. But I don’t think it’s impossible to make math approachable. What do you think?
July 16th, 2008 at 1:25 pm
Math problems are fun and you are so right that knowing basic manipulations comes in handy in everyday life and at work; story problems being the most common type of math in real life. In a related suggestion, I think everyone should take at least one course in mathematical or formal logic. I use those skills every day as well, and feel bad for those around me who seem deprived in this area. I enjoyed your column on StickyMinds and especially enjoyed this companion-piece on your thinking behind the column.
July 17th, 2008 at 7:54 am
Hi, Robert. Yes, we use logic all over the place, even when writing programs that we think uses no math. Did you know you use math when you tie your shoes? “Knot theory” is another branch of math.
July 19th, 2008 at 10:36 am
Hi Danny. I enjoyed your StickyMinds piece on real-world math. The part about modulo-n arithmetic reminded me about its place in combinatorial testing. I gave a talk in May at StarEast on pairwise testing and tried to introduce a little bit of math. (See slide 8 in the presentation below.) There’s a really neat way to build orthogonal arrays from modulo-n addition and multiplication tables if n is a prime number. But it seems to me the real challenge here is training (as Robert and you have pointed out). There isn’t enough time in school to learn about the subtleties of pairwise testing with constraints, or how finite fields relate to test design. So forums like StickyMinds are really important to improve the state of the art.
Pairwise Testing Comes of Age http://www.testcover.com/pub/background/stareast2008.ppt