Tuesday, May 24, 2011

Razor sharp humor

The radio show Okham's Razor, starring Robyn Williams has a show on humor, from a grammar point of view. It's good, but not very funny. Download it now and listen to it, or read the transcript. I'll wait.

Everyone knows that jokes that are explained are universally not funny. One assumes that people who study humor, called 'jokeologists', are singularly unfunny people. Comedians study humor. Most people will claim that they can't remember jokes. Jokes are generally nonsense - who could remember that? It seems that most people can't tell jokes very well. That may be because they don't practice. A good comedian can tell jokes and make it look easy because they practice telling jokes until the jokes are old and tired. They're literally not funny any more. And that gets us back to how jokeologists are people that are not funny, at least to themselves. But don't feel bad for the poor comedian. The jokes were funny for them once. And they get a rush when the audience is amused.

Groucho used elephants because elephants are inherently funny. He could have use a cow, if cows weren't so cuddly. Groundhogs are funny, but they also might fit in Groucho's pajamas. And shirts aren't nearly as funny as pajamas. Groucho even breaks the rule about explaining his joke, and gets away with it. That's genius. Anyone else trying that would be considered conceited. Content is important. This is the main problem with the humor constructed by ten year olds. It should be noted that your average ten year old knows how to properly use ten thousand rules of grammar. Where a ten year old's attempts at humor go wrong is generally in content, not grammar.

Many of my friends who are mathematicians are some of the funniest people around. Perhaps their jokes are funny because the rules their humor break have no ambiguity to exploit, and when broken shake the foundations of the Universe. Perhaps these jokes are funny because there's a sense that it took more work to create them. Mark Twain said that it takes about two weeks to come up with a really good extemporaneous comment.

The problems with teaching grammar are related to the problems of teaching math(s). 1) The plethora of definitions. 2) The applications that might provide context aren't elucidated. 3) The use of arbitrary rules that are difficult to cope with (where extra work is needed to avoid having a preposition at the very end). 4) The use of vocabulary that is specialized to the point of obfuscation. Math(s) teaching goes further with this obfuscation bit by using symbols that are apparently invented on the spot, often using glyphs pulled from other languages, without explanation. Symbols introduce indirection, which is an irritant to the non-specialist. For the mathematician, if one knows how to go from New York to Detroit, and one knows how to go from Detroit to Boston, then one knows how to go from New York to Boston. The rest of us will get out a map and figure out how to go from New York to Boston directly, since that's likely to be less than a tenth of the distance, as it was even when gas (petrol) was cheaper. Neither math(s) nor grammar make much sense or appear to have much use (power to achieve any likely goals). It's too bad, since both math and grammar are among the most powerful tools ever invented.

When the ten year old says, "My friend and me went to the store", i don't correct it by stating "My friend and I". I explain that 'Me went to the store' doesn't sound as good as 'I went to the store'. I have no idea what the formal rule is. Ten year olds don't get the rule right mainly because they don't think about the whole sentence before it comes out of their mouth. I want to teach the child to think a bit before they speak. It would solve so many other issues.

Just as with the doctor, a ten year old is only a little patient. Computers have infinite patience. If computers could be taught grammar, and were fed a dictionary, could they produce huge amounts of humor? Perhaps IBM's Watson could take up this new avocation.

My favorite one liner is this: A Zen master went to his hot dog vendor and said, "Make me one with everything"'.

I heard it again in the movie "The Bicentennial Man", starring of all people, Robin Williams. There aren't any jokes near it. I'd heard it before, and laughed right away. Some thirty seconds later, someone else in the theater laughed. Then a couple guys laughed at what must have been five minutes. When i tell it, not everyone gets it. I figured that they didn't know what Zen is or something. So i told it to a group of five of my Indian colleagues. They didn't laugh. I asked them about it. One said that "It's not a Zen Master. It's a Buddhist monk." Another said, "And they're vegetarian, so they wouldn't be eating hot dogs." And so on. In fact, i counted nearly as many errors in the joke as words in it. It's not that they didn't get it, it was just too broken for them to be funny. To me, that's what makes it funny. And listing the things wrong with it doesn't diminish it as a joke. Though, to be fair, i've practiced telling it quite a bit.

Forth For Enlightenment, part three of ten, Logic two

Last time, the four digit logic problem was introduced, with solution. This time, we'll develop a brute force solution for the HP-28, which we're thinking of as a Forth language engine.

We're looking for a four digit number. It must be greater than 2000. The digits of this number add to 14. The one hundred's digit is less than the one's digit. The ten's digit is three times the thousands digit. The number must be odd.

Since the number is four digits and greater than 2000, the number must be between 2001 and 9999. That suggests a loop. In Forth, the style is to use lots of little functions to get things done. So, in writing the top level function, we'll imagine that we have helper functions to solve smaller problems. The top level could be a loop that checks every digit. Call it 'TOP'. It effectively enforces the first two rules. The development plan was more or less top down design, bottom up implementation, though with some feedback leading to a little jumping around. It's presented as top down, that is callers first, however. For testing, it should be entered bottom up. The called functions can be tested first. If you don't recall the syntax for something, you can refer to my previous articles. Hewlett Packard has the full manual available as well, though not online or free.

By the way, using lots of little functions isn't how i learned to write C. I use C when performance is everything. When i learned C, subroutine calling always introduced a few instructions of overhead. The incentive is to only write subroutines when they'll be called more than once. But modern C compilers can perform function inlining automatically. And, statically declared functions can be inlined with the original function eliminated entirely. So the effect can be better readability and maintainability without the subroutine call performance penalties or extra code. However, there's still the issue of variable scope, parameter passing and return. So it's not something you can always do. By the way, when entering this routine, NEXT isn't the NEXT key on the machine. It's in the Program Branch menu on the 2nd level. This procedure ironically has you use the NEXT button to get to the 2nd level of the menu. Alternately, you can enter the 4 letters N E X T and a space.


« 2001 9999 FOR x x CHECK NEXT
» 'TOP' STO

So, the next thing to consider is CHECK, which enforces the last four rules. It takes a 4 digit number from the stack (and consumes it). How does it flag any correct answers? The stack is not a good place for this. We could store any answer we get in a variable called 'ANS'. If we assume that we don't know how many correct answers that there might be, 'ANS' could be a list which we can append to. So, TOP needs to initialize this list with an empy list before the loop that calls CHECK. We'll do that in a function called INIT. We might modify INIT later to add anything else that comes up. Also, TOP should recall the value of ANS. Here's the brand new INIT along with the new version of TOP.

« { } 'ANS' STO
» 'INIT' STO

« INIT 2001 9999 FOR x x CHECK NEXT ANS
» 'TOP' STO

Now CHECK needs to break the number into digits. I considered using an array for the digits, and index into the array. But there doesn't seem to be much advantage to that approach. A variable for each digit is OK. I went with 'THO', 'HUN', 'TEN' and 'ONE'. A function 'BRK' breaks the number into digits. The idea is to divide the number by 10 using the HP-28's MOD function - which gets the remainder. That's the low digit. Then divide the number by 10 and use FLOOR to get the integer part. This is repeated, so we'll write a GETDIG function to do that much. GETDIG takes the number to break and returns the new number to break and the digit obtained on the stack. BRK calls it 4 times, storing results.

« DUP 10 MOD 10 SWAP / FLOOR SWAP
» 'GETDIG' STO

« GETDIG 'ONE' STO
GETDIG 'TEN' STO
GETDIG 'HUN' STO
'THO' STO
» 'BRK' STO

This much is easily tested. Type 1234 and using the USER function key setter run 'BRK'. Four variables are created, ONE, TEN, HUN and THO, and pressing those buttons shows their digit values. Testing again with 5678 shows that each value changes appropriately.

The CHECK function has four rules to enforce. The order doesn't matter. If the number passes all four rules, then the 4 digit number is added to the list. The tests are in the functions IS14, ISHLO, IST3T and ISODD. These functions look at the digits stored by BRK and return true or false. They could be all tested and the results ANDed together, but it's probably faster to have nested IFs so that if any are false, it can stop checking. Using AND would eliminate all but one of the IFs. A new typography thing. The →LIST notation is for an HP28 built in function. The function name really starts with a right arrow. In development, i wrote a version that kept the current potential answer on the stack as an unnamed variable. It even worked. But storing it in a real variable called 'PANS' is easier and shorter than goofing around with the stack. It looks like this:


« DUP 'PANS' STO
BRK
IF IS14 THEN
IF ISHLO THEN
IF IST3T THEN
IF ISODD THEN
ANS PANS 1 →LIST + 'ANS' STO ; a solution
END
END
END
END
» 'CHECK' STO

If there is a solution, it is converted to a list and appended to the ANS list of solutions. This function can't be checked yet. All the called check functions must in place first.

The first rule function is IS14. It checks to see that the digits add to 14. It recalls each digit and adds. It doesn't perform the IF, it just does the compare. The compare returns 0 for false or 1 for true. So Booleans are just numbers.


« THO HUN + TEN + ONE + 14 ==
» 'IS14' STO

One can check this function using 1234 BRK IS14. It should report 0. Then 2165 BRK IS14 should report 1.

The next rule is ISHLO, which checks that the one hundred's digit is less than the one's digit.


« HUN ONE <
» 'ISHLO' STO

2165 BRK ISHLO should report 1. 4321 BRK ISHLO should report 0.

The next rule is IST3T, which checks that the ten's digit is three times the thousands digit. I'm using * instead of X for multiply because that's what you get on an HP-28 when you press the X button when you are creating a function. The letter X could be a variable or function.


« THO 3 * TEN ==
» 'IST3T' STO

4321 BRK IST3T should report 0. 2165 BRK IST3T should report 1.

The last rule is ISODD, which checks that the number must be odd. One imagines that such a function could be handy for other things, and therefore is a candidate for a library function. Then any mistakes you make in creating it could be reused. No, no. Really, libraries are a good thing.


« ONE 2 MOD 1 ==
» 'ISODD' STO

2165 BRK ISODD should report 1. 1234 BRK ISODD should report 0. Visually, it may not be totally clear what it's doing. We don't need to know anything other than the least significant digit. Recall the one's digit, divide it by 2 with the MOD function, and compare the result to 1.

The CHECK function can now be checked using INIT 1234 CHECK ANS. It should report { }. Then INIT 2165 CHECK ANS should report { 2165 }. Of course, if we didn't know a solution to the problem, you'd have to check that TOP yields an answer with TOP.

Running the full program by invoking TOP takes 49:22 (2962 seconds) to run on my HP-28C. It should be faster on an HP-28S, since the processor speed is higher. Optimization or speed was not a particularly big consideration with this program. A logic program like this would be run once. There are no parameters. It should always produce the same answer. But it should be noted that some of the tests report false more often than others, so should be evaluated first. For example, one expects that IS14 is true 1/14th of the time, while ISODD is true half of the time. In fact, ISODD could have been incorportated into TOP's FOR loop by using a STEP clause of 2 and count just the odd numbers. And of course, if speed were required, a modern machine could have been used and with an efficient compiler. One expects that a C version should consume less than a second. That's because 8000 just isn't a very large number. And in fact, even a decade old PC requires only a millisecond, and sometimes reports zero time.

One of the things that is attractive about this language is that the check functions are all really tiny. Indeed, having a compact language makes considerable sense for small machines. I had heard that Forth for the 1970's batch of microcomputers could achieve 1/3rd of the speed that typical programmers could achieve using assembly language. However, i doubt it. If i recall right, the inner loop for a Forth engine required 21 instructions on a z80. This is all overhead. But perhaps the figure was for a Forth system where many of the primitives were in assembly language, and therefore much of the code executed in a Forth system was, in fact, assembly language. Given that Forth is arguably easier to write, that's quite promising. The low memory foot print for Forth is also encouraging. Java has achieved 1/3rd the performance of C, but it started out at about 1/350 of C's speed. Java has only achieved this performance through considerable heroics. It took over ten years to happen. By available evidence, every opportunity to trade memory for speed has been used to achieve it. Java is incredibly memory hungry.

The CHECK function shows that even a little complexity can give rise to an increased programmer burden tracking how the stack is used. Tracking what's on the stack is one of the major challenges with writing and debugging Forth. One ends up drawing stack diagrams all the time. When i wrote this program, the only problem was that the first version of the CHECK function left an extra value on the stack. I didn't happen to notice it, so my first run of TOP ran out of memory due to the accumulating values on the stack every loop.

Even as short as ISODD is, it's not evident from the code what it might be doing to the novice. It's probably more evident to the seasoned Forth programmer. But this forms a barrier to entry, and makes procedural (or imperitive) languages easier in general. In fact, i find that documenting my Forth code to the level of this article is what i need to have a clue even a year later. That's distressing.

Is the application of logic, or the crafting of a program faster if the goal is getting the answer? I'd have to say that the logic was marginally quicker for me. It's not as complicated. It took nearly twice as much text to describe the program as it did the mathematical logic. I don't attempt to solve this sort of logic problem very often. While i'm not currently an HP-28 RPL or Forth guru, i do write programs all the time. I'm much quicker at it than i was towards the start of my programming career. Although the debug cycle was short, the run time was pretty long. I don't count it, as i was able to do other things while it ran. Uhm, i added 440 1 BEEP at the end of TOP to alert me when it was finished with a 1 second long musical A note.

Monday, May 23, 2011

Forth for Enlightenment, part two of ten, Logic problem

Here's a logic problem that i came across while helping a 5th grade student with math. My interest in it is to solve it in a brute force manner on the HP-28C. But before i do that, i'll go through the problem and logic solution. First, the problem.

We're looking for a 4 digit number. It must be greater than 2000. The digits of this number add to 14. The one hundred's digit is less than the one's digit. The ten's digit is three times the thousands digit. The number must be odd.

So, first, the logic solution. In these sorts of logic search problems, you'd like to use the clues to narrow down the search, if possible. We'll start with the first two rules. It's a 4 digit number that is greater than 2000. So, the number is in the range from 2001 to 9999. That's roughly 8,000 numbers to check.

It's not immediately clear that adding digits to 14 helps narrow the search at this point. You'd have to check all 8,000 numbers or something. And for the same reason, we'll skip the hundred's digit rule for now as well. But consider that the ten's digit is three times the thousands digit. Well, the thousand's digit has to be at least 2. Three times two is 6. If the thousand's digit is 3, then the ten's digit must be 9. If the thousand's digit is 4, then ten's digit is 12, which is not a digit. So the thousand's digit must be either 2 or 3. That narrows the search to the range 2069 to 3999. And the number must be 2?6? or 3?9?. Here, i'm using ? to mean any digit. That looks like 200 numbers to check.

Now the hundred's digit must be less than the one's digit. So, for 2?6? numbers, the hundred's digit must be in the range of 0 through 5. For 3?9? numbers, the hundred's digit must be 0 through 8. Let's use [0-5] and [0-8] as notation for single digit ranges. We have 2[0-5]6? and 2[0-8]9? as possibilities. Since the hundred's digit must less than the one's digit, it follows that the one's digit must be greater than the hundred's digit. Since the hundred's digit must be at least zero, the one's digit must be at least one. So the ranges are 2[0-5]6[1-9] and 3[0-8]9[1-9]. That's 54 + 72 numbers or 126 possibilities remaining.

Let's check the rule that the digits must add to 14. In the 3[0-8]9[1-9] case, the two known digits add to 12. So the only valid combination is 0, 2. But since the one's digit must be odd, even this combination must be eliminated. In the 2[0-5]6[1-9] case, two of the digits are known, and add to 8. So the other two digits must add to 6. Since the hundreds digit has to be smaller, the valid combinations are 0, 6, and 1, 5, and 2, 4. Since the one's digit must be odd, that leaves 1, 5. So the answer is 2165.

What does a 5th grade student do with this problem? They guess. It's a 4 digit number. It must be greater than 2000. So the first guessed digit is 2. It's 2???. The "digits add to 14" rule is ignored. The 10's digit is 3x the 1000's digit. So, the guess is 2?6?. There's no rule that the numbers must be unique, but they guess '1' for the hundred's digit all the same. They could have guessed zero, since it's a digit. But they don't know much about zero. So that's 216?. The number must be odd. The next guess is 2163, because 1 was already taken and this is the next odd number. Some 5th graders stop there. And it's not quite the right answer. But really smart 5th graders go back to the "adds to 14" rule, and notice they need 4 more, and so guess 2165. And, it's the right answer.

Is this problem reasonable to hand to a 5th grade student? IMO, no. There are several skills that could have been taught first. For example, one could teach the idea of doing the easy stuff first. But my real complaint is that this exercise teaches the 5th grader to guess at answers, and fairly randomly. Usually, at this age, the guesses are not checked for correctness, and wrong answers come out. So, one should also explicitly teach students to check their answers. This problem also requires quite a bit of estimation and mental juggling for anyone, much less a 5th grader. Sorting the rules by next easiest is another teachable skill. But the school that assigned this problem taught none of these skills. Finally, this is a logic problem with no obvious (or explained) real world analogy. There seems to be no use for knowing how to solve it. Most math can be applied. IMO, it's criminal to expose students to math without explaining what it it might be for.

Admittedly, it took me much longer to solve than it took a smart 5th grader. But that's because i took the time to understand more about the problem. For all i know, there might be more than one solution. I invented notation to help keep track of the possible solutions. I did go with easy constraints first. So, i skipped the "adds to 14" constraint until later. But i also ignored the odd number constraint. I could have invented a [2-9]??[13579] notation. But that's really three notation inventions all at once. And when I was finished, not only did i know that i had an answer, i also knew it was the only answer.

There's a fear of math issue for the 5th grader (and, one imagines, for most of us). If one makes a mistake, one gets the wrong answer. If one adds 2 + 2 and gets 5, it's not close. It's wrong. Fear of math is mostly the fear of failure. That is, you invest your time and effort, but if you get the wrong answer, it's entirely wasted. At least, that's the fear. It's worthwhile to teach the idea that the problems are a challenge. One way to get over the fear is that getting the right answer is rewarding in itself. Frankly, i get a little rush. I find it addictive. I try not to let it go to my head and make me proud and boastful. That's not the person i want to be. But i do want it to build up my self esteam or self confidence. That will make it easier to do the next problem. But along with the fear of failure and wasted investment in time that comes from poor self confidence, there's also the fear that there may be no solution. As an adult working real world problems, i've come across problems that don't appear to have real solutions. Or if real solutions exist, there doesn't seem to be a way to get at them with logic. The 5th grade student should be assured that a solution exists. Still, this problem is way too complex for most parents, let alone typical 5th grade students. How an untrained 5th grade student is supposed to solve it as a homework problem is beyond my reckoning.

I've consumed enough of your consideration on the logic of this problem. The next article will dive into an HP-28 solution.

Friday, May 20, 2011

Forth for Enlightenment, part one of ten, Factorial

My Scheme series introduced factorials in part one (the 2nd post). The factorial function is strictly numerical. The factorial of 5 is 5! = 5 * 4 * 3 * 2 * 1 = 120. The factorial of any number is the product of the integers from 1 up to that number. The numbers are multiplied together. A series using the HP-28 calculator ought to have this function early on. After all, the factorial function works with numbers. So do calculators. But doesn't the HP-28 have a built-in factorial function? Yes it does. And it's fast. And it can deal with fractions. I mean, the factorial of 5 is 5! = 5 * 4 * 3 * 2 * 1 = 120. But what is the factorial of 5.5? Well, there's a gamma function, and it yields 287.9 (with more decimal digits). The gamma function closely tracks the factorial function. For very large factorials, the gamma function can get you an answer that is good enough without doing all those multiplies. The HP-28 can represent numbers up to 10^500. So the FACT function is limited to input up to 253.

If you write your own factorial function, you'll find that it's not as fast as the internal function. The internal function is pretty much instant. It's not clear if they coded it in assembler, if ROM is faster than RAM (as it was with the Texas Instruments TI-59 calculator), or if they used some tricks. It might be a combination of these. One of the tricks it might do is store the answers to all factorials up to 253. Or, they could use less space and only store every tenth factorial. So, 10! is 3,628,800. If you need 11!, you start with 10! and multiply by 11. Then, factorials would be really fast.

I wasn't so much interested in speed as programming. The recursive version is first. It doesn't support the gamma function. Just the multiplication of integers is considered.


« DUP IF 1 ≠ THEN ; stop at 1. If not...
DUP ROT * ; multiply count into product
SWAP ; switch prod and count
1 - FA ; cnt = cnt - 1, call self
END
» 'FA' STO

Typography first. The 'FA' STO at the end isn't really part of the function. It's how you enter the function. 'FA' is the function's name.

The function expects two arguments. The number 1, and the factorial to be computed. So, this can be run with 1 5 FA. But it also returns two items on the stack. And the answer, 120, is buried. It returns the answer and the number 1 on the stack. So, get the answer by running DROP. This isn't really clear to an end user, so there should be a wrapper function, which i call 'FAC'.


« 1 SWAP FA DROP
» 'FAC' STO

This FAC fucntion takes one argument, and returns the answer. So 5 FAC returns 120. FA, and therefore FAC, can compute factorials for numbers up to 253 properly. That's from the limitation of numbers, not from running out of memory for stack data.

But let's get back to FA again. In it, the HP-28 function ROT is used which rotates entries on the stack. It's pretty clever. But it's not clear what it should be good for. It works for this program. ROT comes from ROTate. Let's examine how it works. If a, b, and c are on the stack before ROT, then b, c and a are on the stack afterwords. Here it is in table form.





LevelBefore ROTAfter ROT
3ab
2bc
1ca

Now, FA takes two arguments on the stack, which are 1 and the factorial number to compute. It turns out that the 1 is needed as a running product. The count is multiplied by the current product on each loop down. The current count is at the top of the stack. In the first line, the count is copied, so that there are two of them. The IF consumes one count in the compare to 1. In the line with the count, we want to multiply the count into the product, but we need to remember the count also. So the count is duplicated, and then ROT does it's magic. Finally, we have the multiply. The next line does a SWAP to restore the product and count to where they started. Here's a stack diagram for operations starting in line 2. The stack shows what's on the stack after each operator.





LevelStartDUPROT*SWAP1-
3 prodcount  prod 
2prodcountcountcountprodcountprod
1countcountprodprod * countcount1count - 1

Note that in the column with the multilply, prod * count is shown. After that, it's the new product, so just prod is shown. The stack diagram should get you through the operation of this function. Forth programmers use these often. But i wouldn't be surprised if after awhile, idioms involving ROT become second nature. I timed this function with the highest argument, 253. It took 20 seconds. The built in function comes back with the answer almost right away, even for 253.

This is an acedemic excersise, so a version that uses a loop instead of recursion was written next. I used a new name, FACTO. It takes the number to compute, and returns the answer. It's also shorter and simpler.


« 1 SWAP 1 SWAP
FOR x
x * ; multiply count into product
NEXT
» 'FACTO' STO

The first line with the SWAPs might be confusing. The FOR operator takes two arguments, the start number, and the ending number. The count is already on the stack, but needs to be in level 1. A 1 is needed on level 2 to serve as the start number. A 1 is needed on level 3 to serve as the running product. Here's a stack diagram.





Levelstart1SWAP1SWAPFOR
3   11 
2 count1count1 
1count1count1count1

The FOR loop's first iteration starts with 1 on the stack, which is the running product. The x in the FOR line is a local variable. It matches the x in the third line. This variable counts from 1 to count, stepping by one each loop. So x * multiplies the current running product by the current count number each loop. The NEXT function marks the end of the FOR loop. The local variable conveniently and automatically is removed when the loop is finished with all iterations. When each loop is finished, the current running product is the only thing on the stack. So when all loops are complete, the complete product is returned.

The start with the SWAPS can be made shorter, if perhaps more complicated. Consider this version:


« 1 1 ROT
FOR x
x * ; multiply count into product
NEXT
» 'FACTO' STO






Levelstart11ROTFOR
3  count1 
2 count11 
1count11count1

Clearly, it gets the stack to the same place and with 1 fewer command. It might be marginally faster, but it's only one command that is skipped, and only once. It is shorter, so it should take just a tiny bit less memory. While the HP-28C is memory starved, in reality one would use the built-in FACT function, which would take zero memory. It does show that the ROT function is often valuable.

This version of the factorial function is faster than the recursive version. It took 5.8 seconds. That's more than three times faster. It isn't anywhere near as fast as the built-in function, however. It also takes less memory, since it doesn't use more than three stack levels. It doesn't need a helper function.

Since recursion can always be converted to loops, one wonders why recursion is ever needed. And indeed, it isn't. But sometimes recursion is how the problem is presented. If that's the case, then often recursion is a good approach to take. But there are also algorithms that are easier with recursion. The Quick Sort algorithm comes to mind.

Thursday, May 19, 2011

Forth for Enlightenment, part zero of ten - count

Back in 2008, i posted a series of articles as an introduction to the scheme computer language, and basically functional programming in general. One of the quotes one hears from functional programming enthusiasts says that languages are either functional or disfunctional. From my perspective, C can be used as a functional language, even if that isn't the usual case. For that matter, assembler can be used as a structured language if just a little discipline is used, despite only directly supporting GOTO. And back in the 70's, with 8 bit processors such as the 8080, z80, 6502, 6809, or 1800 (all of which i consider to be 16 bit processors, since that's the address space), memory space was so tight that having little tiny functions made sense. Therefore, assembler programs often had a functional feel to them.

Anyway, the next language i wanted to visit, or in this case revist, is Forth. I could download a Forth system for Linux, but i happen to have something like Forth in a more portable form. I have an HP-28C calculator from Hewlett-Packard. I got it in late 1986, i think. When i saw the HP-28S, i wished i'd gotten that one instead. The HP-28C has 2 KB RAM. The HP-28S has 32 KB RAM. The speed increase of the HP-28S would have been irrelevant to me. This might be considered blasphemy. But i had access to much faster computers with C compilers if i needed to perform serious computations. Battery life is more important. Battery life on the HP-28C is excellent, by the way. But lots of RAM (16 times more) would have opened up the range of potential applications dramatically. For example, one of my benchmarks involves performing a matrix multiply using three 20x20 arrays. That's 1,200 cells, which won't fit in 2 KB of RAM. Numbers take at least 8 bytes of storage. So 1,200 cells takes at least 9,600 bytes. So, it will fit fine in 32 KB, but not even close in 2 KB.

Anyway, the HP-28C doesn't implement Forth exactly. HP called the language RPL. This stands for Reverse Polish Lisp, though it looks more like Forth than Lisp. Forth was already available. In fact, Rockwell sold a version of their 6502 computer chip with a Forth system in ROM on the chip. The way i heard it, Rockwell was working on a version of the 6502 that would include ROM on the chip. Engineers asked around for some code that could be tested, and one guy handed them some code. They manufactured a chip, and gave it to the guy with the code for testing. Does it work? Sure. What is it? It's a Forth system. So then they had a product with no documentation. They had an external 2 KB ROM that implemented a text editor and floppy disk system for development. All this to say, Forth is extremely bit-efficient.

So, the HP-28C is something like Forth. Close enough for what i wanted to do. My 25 year old calculator works fine. And, it's very portable, allowing me to doodle with it while waiting for various things to happen. One of the Wiki pages suggests that the battery door tends to break, and most of these devices are taped shut. My battery door is intact. I love the machine. The keys have very nice tactile feedback, and there's a "back up a character" key that lets you edit numbers. Further, you can undo operations to find out what you did. And I have the printer. All this makes me gravitate towards this machine when i need to do my taxes. There just aren't the fat-finger unreliability issues i often have with other machines. But while i programmed the device extensively in the late 80's, i really only retained fairly simple arithmetic skills until recently. By comparison, i have another device from the late 80's that has a BASIC like language. After a couple decades of disuse, i found i could program it without the manual. So, there's something about Lisp and Forth like languages that make them more difficult to read and write than strictly procedural languages. The barrier to entry is higher. Yet, there are many who would advocate that procedural languages should be relegated to only where optimization is required. My opinion is that this is idea is neither practical nor desirable.

In Forth (or RPL), one puts one or more objects (which can be any of several types, but numbers for now) onto the stack, and then one runs a function which consumes value(s), and leaves some result(s). A function can call other functions. I recall that one of the manuals warns against having a function call itself, or call a function that ends up calling itself - since that can result in an infinite loop. But that's exactly what i wanted to do first. Not an infinite loop, but have a function call itself. The way it could work properly is if there was some way of terminating the recursive call somehow. RPL has IF...THEN...ELSE...END conditionals. So the first thing i did was create a recursive counting function. It counts down to zero. Yes, this function alway returns zero, if it works. And usually, that wouldn't be very interesting. But what i wanted to know was approximately how deep recursion can work on this system. I should also point out that there are two stacks in Forth. There's a call stack where the return address of the caller goes, and there's a data stack. In C (and many other languages), the call stack and data stack are implemented with a single structure. It makes memory management easier - especially for local variables. It has some disadvantages as well, though these are managed easily.

Two issues in typography need to be mentioned first. The HP-28 has single characters for double less than and double greater than. I'll use the web characters '«' and '»'. These single characters start and end procedures. If a procedure is stored in a variable - that is, if it has a name, then it is a callable function. Like Lisp (and Scheme), you can have unnamed procedures. I don't find unnamed procedures very valuable on a hand held calculator. They have limited, but important use on bigger systems. The other typographical note is that the HP-28 has a single character that is an '=' with a '/' through it. It means not equal, and it is represented with '≠'. Finally, I show end of line comments starting with a semicolon ';'. I don't actually enter comments into the calculator. Amazingly, comments can be entered into programs. I'm not using the HP-28 convention. With that, here is the first program, which i called 'BCNT'.


« DUP IF 0 ≠ THEN ; If not zero...
1 - BCNT ; Subtract 1 and call self
END ; ends the IF. Returns 0
» 'BCNT' STO ; end of the procedure

Note that IF consumes the value on the stack. So this program starts with DUP. This makes a copy of the value on the top of the stack. Perhaps it retrieves the value, then pushes it twice. The next line puts the value '1' on the stack, and issues '-', which subtracts 1 from whatever was on the stack, and puts the result back on the stack. It then calls itself. The END is the end of the IF statement from the first line. And that's it. Except that the key to figuring out how it works is that if the value isn't zero, it subtracts one and calls itself. But what happens when it returns? Nothing. It hits the END, which ends the IF statement, but that doesn't actually do anything. It returns from the function, carrying with it whatever value was on the stack. But if it returned, it's always zero that's on the stack. It's worthwhile to trace what it does for a small value, like 3.

After typing in the program, i typed 'BCNT, the 'enter' key, and the STO key, which binds the program the the variable named 'BCNT'. Yes, that was a single quote, then the letters B C N & T. The 'enter' key closed the string with a single quote. You get used to it. To run it, type a number and the name of the function. The machine has a USER menu where the new function name appears under a function key. So, it's really enter a number an press a single key. I'm giving detailed instructions on how to enter programs because, after decades of disuse, i'd forgotten most of it. Should you have a functioning multiple decade old calculator to try this on, here it is.

After typing in the program, i typed 'BCNT, the 'enter' key, and the STO key, which binds the program the the variable named 'BCNT'. Yes, that was a single quote, then the letters B C N & T. The 'enter' key closed the string with a single quote. You get used to it. To run it, type a number and the name of the function. The machine has a USER menu where the new function name appears under a function key. So, it's really enter a number and press a single key. I'm giving detailed instructions on how to enter programs because, after decades of disuse, i'd forgotten most of it. Should you have a functioning multiple decade old calculator to try this on (i've seen it in two museums), here it is.

Anyway, with some trial and error, i discovered that this function could count down to zero from 317. There was nothing else in memory. The HP-28 is clearly not performing any tail recursion optimization. Otherwise it could count down from any integer it could represent, given enough time. I also timed this maximum depth count. And it counts at 18.2 per second. Calling and returning are fairly high overhead operations. A simple loop counts faster. That means that loops are faster than recursion. That's also true in C, lisp and scheme systems i've used. It's not a surprize.

This program adds 1000 to the current value on the stack, by adding 1 repeatedly. I uses a loop. It counts at 60.75 per second.


« 1 1000 START ; Peform 1000 loops
1 + ; add 1 to the stack.
NEXT ; end of the loop
» 'C' STO ; end of the procedure

I called it this version 'C'. Run it by typing any number and 'C' from the USER menu function key. So far, we have functions, recursive calls (which look like any other kind of call), conditional if, and loops. This is enough to write almost anything, given memory and time. More to come.

Tuesday, April 12, 2011

one point six million

Only really dramatic traffic deaths make the news. And fender benders never make the news. That's because they're so common. Until recently there were some 45,000 traffic deaths per year in the US. That works out to 3 per day per state. So, if they were news, you'd see them every day. Traffic deaths have gone down recently and dramatically, to only about 2 per day per state in the US. Accidents per year in the US total some 1.6 million. That's pushing 90 per day per state. With gas prices going up, maybe it's time to take a train. As with Astronomy Day, May 7th, 2011 is National Train Day. Passenger deaths on trains are news when they happen. You don't hear about them because they happen so seldom.

Tuesday, March 29, 2011

Top Ten, 20 of 10

We last left our hero in the top ten list of ways to be Screwed by "C". Today's entry is 64 Bit Madness.

No example is given, just a general warning about how integers are often signed by default, and therefore do not always behave as expected when moving from 32 bit architectures to 64 bit architectures. Since i learned C on the PDP-11, i'm predisastered. The PDP-11 is a 16 bit architecture and commonly used 16 bit integers. C's long type was 32 bits, but was not generally used for pointer arithmetic on this system. The Vax 11/780 was a commonly accessible 32 bit computer that was contemporarily available when i learned C. So, there was a considerable amount of code that i ported from the 32 bit VAX to the 16 bit PDP-11. I had fewer issues moving from 16 bits to 32 bits than from 32 bits to 16.

The sign extension problem was not much of an issue. If there was a sign issue on the 16 bit PDP-11, it generally showed up right away. That's because using more than 2^15 = 32,768 bytes was common on these machines. These machines often had between a quarter of a megabyte of physical RAM and as much as four megabytes.

On 32 bit machines, until very recently, it wasn't very common to have more than 2 GB of RAM, which is what you need to run into sign extension problems. However, it's already very common to have more than 4 GB of RAM on 64 bit computers. I already have one with 8 GB.






Computercharshortintlonglong long
PDP-11 16 bits8161632n/a
32 bits816323264
64 bits816326464
64 bits816646464

Denis Ritchie's C compiler was nearly always used the the PDD-11. And the int type was explicitly stated to be the most natural size for the machine. For most computers, this is the width of the CPU registers. And, for most machines, this is also the width of the program counter so that general registers could be used to compute addresses. The gcc compiler introduced the long long data type. It was a way to allow the int type to remain flexible while allowing access to a new longer integer type, whose time had come. It also had the feature of not breaking the language. No new keywords were introduced. Old compilers did not break on new code (though they usually did not produce what was desired). But when 64 bit computers came out, there were two standards, often for the same hardware. Depending on the compiler, the int data type may be 32 or 64 bits in length. So, there are some C compilers which decided that the int data type was not a redundant optimization type but rather had it's own type, and further, that data type is not the same size as pointers on that machine, as was historically the case.

So while porting C code from the PDP-11 to the 32 bit VAX was generally easy, it can be awkward to port code from one compiler to another on the same 64 bit machine. There are workarounds.

Could Dennis have planned better when he designed his language? While 64 bit integers weren't much in demand on the PDP-11, 64 bit architectures existed in hardware since 1961. That's much older than the C language. It wouldn't have hurt much to add 64 bit support for the PDP-11. Indeed, Unix was ported to the 1976 Cray-1 computer architecture eventually. That's well before the roughly 1969 vintage C language.

Monday, March 28, 2011

Top Ten, 19 of 10

We last left our hero some time ago in the top ten list of ways to be Screwed by "C". I happened to be looking at the old posts, and noticed that the author has added a couple. Today's entry is Accidental Integers. The first example is:


int a = 2 && 4 && 8; // what is the value of "a" ?

The issue here is that integers are also Booleans in the C language. So this expression is expected to use the constant "2" as a Boolean, which is clearly not false and therefore true, perform logical and with "4", which is also true, and perform a logical and with "8", which is also true. The answer is true, and the variable a is set to 1. On read, integer values that are zero are false, and anything else is true. But if the language has to pick a non zero value, it uses 1. Since this example has several constants in an expression, the compiler would evaluate these at compile time and simply assign the value of 1 to a. The second example is a little curious. It's supposed to be the same.

int value = a && b && fn(a->x,b->x);

In this example a and b are structure pointers, and fn is a function which returns an integer. The author wants to check to see that the structure pointers aren't NULL before calling the function, which in C is usually zero. NULL is typically a zero cast to (void *). If you check the boolean truth value as in this code example, you are expecting the value to be compared with zero. But also, the && and operator is a shortcut operator. If the left hand side of the operator is false, then the right hand operator is not evaluated. So, the idea in this code fragment is if pointer a isn't NULL then check if pointer b isn't NULL, and if it isn't, call function fx and set value to the truth value of the integer returned by fn. One suspects that the unexpected result is how the return value is assigned. So this is probably what the author wanted:

int value; /* return value from fn() */

if (a && b) {
value = fn(a->x, b->x);
}

Which is to say that the author didn't want the truth value of the function, but rather the integer value. From a stylistic point of view, i would not be tempted to compress this to

int value; if (a && b) value = fn(a->x, b->x);

or even


int value = (a && b) ? fn(a->x, b->x);

This last is particularly odd. It explicitly sets value only if a and b are both non zero. I can't think of any production code that uses the question mark operator without a colon. The question mark operator is not that commonly used as it is, but one could imagine it could be used to conditionally set a variable in this way. Perhaps in some real life example, the variable was initialized. But in this case, it's difficult to imagine how the return that is set to value is used. Since value was uninitialized, how could the code dependably know if it's the return of fn or some random value? Well, perhaps fn has some side effect, such as setting a global variable that the following code could check. It's a poor example, in my opinion.

The idea that NULL is zero is pervasive in C code. However, i've worked on a machine where the NULL pointer was not, in fact, zero. That's because this unusual 16 bit segmented architecture added byte addressability late in its development. So pointers point at 16 bit words. They added an address bit for the even/odd bytes, though for compatibility reasons, it's not the low bit in a pointer. And worse, the bit is set to "1" for the even numbered bytes. So address zero has a "1" set in it somewhere. The C compiler for this machine defined NULL correctly, but it isn't zero. Yes, there are other complications for C on this unique and special architecture. But we did get a Unix kernel to boot on it. So the above code fragment wouldn't work on this machine. You'd need to explicitly compare with NULL, which properly documents intent, and has no performance consequences. It might looks like this:


int value = ((a != NULL) && (b != NULL) ? fn(a->x, b->x);

It should also be noted that this topic is directly related to the second topic in this series. That is Accidental assignment/Accidental booleans. Use of "=" when you meant "==" is a pretty common error. And it's true that it wouldn't happen at all if a strict Boolean type existed in C and people actually used it, and if the C language did not allow integers to be used as Booleans. My own opinion is that in assembler language, which C compiles to, integers are used in exactly this way for Booleans. And, it was up to the programmer to document the meanings of variables. For code size and performance, integers and Booleans are routinely mixed. Therefore it is up to the programmer to document their variables. My own coding style is to do this near the declaration. Most C programmers do not explicitly declare local loop variables with comments where the use is common and obvious. But in my standards, each variable is declared on its own line so that it can be documented. After all, this makes no difference whatsoever to the compiled code.

Friday, March 25, 2011

Filters in Emacs

In the early 80's, i wrote a filter in C called 'onespc' (V7 Unix had 14 char filenames, i tended to omit vowels). 'onespc' by default would read stdin, compress groups of blank lines (with optional white space) to a single blank line, and write to stdout. I'd use it from the command line, sometimes in scripts that changed many files. I'd use it from Emacs on the whole buffer or regions. 'onespc' has a bunch of options to do similar things, like remove all blank lines.

Emacs was sluggish starting up until the 386/33 or 486/25. This may be ancient history, but it was more than a decade for me. I haven't come up with a good way to use Emacs to edit hundreds of files. My current plan is to learn elisp. That should fix everything. Lisp isn't easy to learn. But i've used Lisp and Sheme in the past.

In the late 80's, i wanted something easier in scripts than

for i in *.txt; do
 onespc $i > x
 mv x $i
done


It's not a good solution, since x might exist as a file. So, i wrote a version of 'into'. The syntax is

for i in *.txt; do
 onespc $i | into $i
done

So, 'into' copies stdin to a temp named file, which it determines does not exist in advance. On EOF, it renames it to the argument, deleting the existing file if it can.

I was about to publish all these utilities, but then someone publish the 'getopt' functions for command line. I liked my least ambigous command line parser better. I never liked the '--' standard. I stalled.

Who knows? Maybe Emacs has a simple file mapper. I'd like to be able to do this easily:

for i in `find . $HOME/some/other/place -type f -name \*.txt`; do
 onespc $i | into $i
done

But 'find' and my filter set (including all of the *ix filters, including 'sed' and 'perl') is a pretty powerful set of flexibility to allow.

Despite emacs's internal docs, 'info', 'man', and google, i can't always find docs for what i want to do just at this moment. One learns by putting in effort. One can always learn more.

Monday, March 14, 2011

No Child Left Untested

The news is that President Obama is to push an overhaul of the No Child Left Behind (NCLB) program. As a parent of school age children, i'd like to get rid of it.

From my perspective, what we need is evidence based education. The way that would work is that we would come up with ideas on how to educate better. The first step would be to implement them in small pilot programs. If the new idea works better than the standards, then it would be moved to a larger pilot. Really good programs would be expanded nation wide. Every change implemented at large scale would have costs and benefits understood beforehand. Was there ever a pilot before introduction of No Child Left Behind (NCLB)?

NCLB suggests that we can't test teachers to determine their competence at teaching. I can understand that. Testing is rarely a good test of competence. Managers in industry mostly can't tell competent employees from dead wood. So, the NCLB idea is to test students. But why do we then think that testing students determines their level of compentence? Didn't we just say that testing rarely is a good test of competence?

And, NCLB does not address course approach and content. For example, teaching astronomy with english together allows students to research history, make observations, etc., and write papers about these things - graded for content and form together. It's been shown more efficient. And why wouldn't it be. Students put in a little extra effort to make their papers better, but don't have to do as many. That's more efficient for the students. It's more efficient for the teachers. There's no additional teacher training cost. You use an English teacher and an Astronomy teacher. You just use them at the same time. Teachers alternate classroom time. Both teachers grade papers. This is just one of a zillion examples.

There are lots of cheap programs that have worked well in pilots that have not been fielded at large scales. It's so sad.

Thursday, March 10, 2011

Kepler

If you look at all the colors of the light given off by a star in fine detail, you'll see lines that are characteristic of atoms and molecules that make up the star. These lines can be compared with similar lines when the same atoms or molecules are heated in the lab back here on Earth. So, you can tell what objects are made of anywhere in the Universe. If an object is moving toward you, these lines move to higher frequencies - towards the blue end of the spectrum (at least in visible light). If the object moves away, these lines move to lower frequencies - towards the red end of the spectrum. It's similar to the way a fire truck's siren is higher pitched when it comes towards you, but falls to a lower pitch when it has passed by and moves away from you. Looking at the detail of the colors of light is called spectroscopy.

The first planet discovered around a star other than the Sun was announced in 1995. That's about 16 years ago. Since then, 528 such planets have been discovered (a number that changes almost daily). The method used at the time was the "wobble" method. Most of these discoveries were made using this technique. It's based on spectroscopy. The idea is that as a planet orbits it's star, it tugs on it's star with gravity. So the star wobbles. With spectroscopy, the movement of the star towards or away from us can be detected. It's not just if it's moving away or towards us, but how fast. So, if the planet is closer to us, it tugs the star towards us. If it's on the far side, it tugs it away. The planet has to go around it's star at least once, but more is better.

Now, it's easier to detect movements of a big star if the planet is big. And, it's easier to detect movements of a planet if the planet is closer to it's star. That's because planets closer to the star pull on the star with more force if it's closer. And, shorter, quicker orbits mean that you can get one or more full orbits quicker. So, most of the planets detected this way are large - as big as Jupiter, and close in to their parent star - sometimes closer than Mercury is to the Sun. And, it's easier if the star is smaller than the Sun. A planet can move a small star easier than a big one.

What we'd like find is Earth sized planets in orbit around stars like the Sun. That's because what we'd really like to know is if there are planets like ours. At the moment, the only place we know of for sure with life on it is the Earth. We'd like to know if there are other places with life. Do aliens exist? (If they're on their own worlds, they aren't aliens - they're natives).

There are other ways to discover planets around other stars. One might expect that a picture could be taken of a star at high resolution, and all the planets would show up. Unfortunately, stars shine through their own light, and planets shine mostly through reflected light. So, stars are something like a billion times brighter than planets. It's like looking for a firefly next to a search light, only harder. But it has been done. At least twice. This technique favors planets that are far from their host star, big, and it helps if they're very young, so they can shine in infrared light by virtue of being hot. You have to take at least two images to show that the planet moves with the star. Three images gives you more confidence, and can show the planet arc around in it's orbit.

Another way detect a planet around another star is to watch a star often, and look for a small drop in light as the planet comes in front of the star. You have to look very often to catch it in the act. You have to have pretty good sensitivity, like a part per 50,000. Both of these issues suggest that you need a telescope in space. In space, you can look at the same spot on the sky 24x7. You don't have to worry about poor weather. And, you don't have a boiling Earth atmosphere making changes to your star's brightness every few seconds. But there's another issue. Most planets won't happen to pass in front of their stars from our point of view. It's a geometry thing. If we're looking down on the pole of the star, then we'll never see any planets come in front. And the farther the planet is from it's star, the fewer stars will be aligned close enough to get one cross in front. So, if you want to detect planets this way, you have to look at lots of stars. This method, called the 'transit method', is used by the Kepler space craft. It's looking at the same patch of sky with a keen interest in about 150,000 stars.

And, the Kepler mission has 15 confirmed planet discoveries. In February of 2011, the team announced 1,235 planet candidates. Estimates are than perhaps 80% of these candidates will be confirmed as real planets. That suggests that perhaps 976 new planets will have been found. If confirmed, it more than doubles the current number of known planets. And, this preliminary data is from when the Kepler mission has more or less just gotten started, nothing like sixteen years. Since Kepler hasn't been looking very long, the data favors planets that orbit close to their stars. Bigger planets are easier to spot. But planets as small as the Earth and smaller are among the candidates. And yet, fifty four of the candidates orbit their star at a distance where liquid water might exist on the surface. These kinds of orbits are smaller for smaller stars. Five of these palnets are near the size of the Earth.

The Kepler mission is currently funded for an initial mission of 3 1/2 years. That's because the goal is to find Earth-like planets in orbit around Sun-like stars. We can tell if a star is Sun-like through spectroscopy. We can tell if a planet is Earth-sized by the amount of dimming. The spacecraft needs to detect three transit events to give us confidence that it's really a planet. Three orbits of a planet in an Earth-like orbit around a Sun-like star will take three years. You'll need a little extra to make sure you get three. The mission could easily be extended longer. The spacecraft doesn't run out of fuel at the 3 1/2 year mark. It's is hoped that the data from Kepler will lead to solid statistics on how common habitable planets are in the Universe. Or, at least, in our part of the galaxy.

What can we do with such statistics? We'll, in 1961, Frank Drake proposed a simple formula for estimating how many civilizations there might be in the galaxy. At the time, we didn't know much about what numbers to plug into the formula. The formula has terms like "the fraction of stars with planets". This is a number where Kepler data can help. Better numbers help give us a better estimate.

We also might be able to discover not only if there might be water, but if there actually is water on these planets. The Spitzer infrared space telescope was used to detect a variety of compounds in the atmospheres of a couple extrasolar planets. And while it is no longer capable of this feat, it demonstrates that it can be done. Transit data tells you when to look to pull it off.

The Kepler discovered planets will miss something we would really like. And that is that none of them will be very near to the Earth. If a planet discovered by Kepler has intelligent life on it, communication (by radio) would still take thousands of years, each way. It's tough to hold up much of a conversation with that sort of delay. We'd really like to find habitable planets that happen to be closer to us. But to do that, you have to look in almost every direction at once. And, we'll likely have to use direct imaging. That's going to require very large telescopes in space. In principal, it can be done. In practice, it will be expensive. But the results will definitely be exciting.

Wednesday, March 09, 2011

Truth That Hurts

Edsger W. Dijkstra
You're doing it wrong.
Edsger W. Dijkstra wrote a very short classic paper, How do we tell truths that might hurt? in 1975. In it, he lists a number of things that he imagined computer scientists of the day thought were true "without hesitation". They're great sound bites. That is, they have no context. They have no explanation. But they're delivered by someone (in this case Dijkstra) in authority. For the record, though Dijkstra was amazing, he said a number of things that are no longer true, and/or were overly general.

For example, at the time, languages such as machine language, FORTran or BASIC, one of the primary control structures available was the "GO TO" command. There was no real choice. You had to use it frequently. And it could be very difficult to follow the flow of a program when there were lots of them. You'd try to follow where things were going, but it was like following spaghetti noodles. By the 1980s, block structured languages were abundantly available. That included C, Pascal, and even Fortran, with the 1977 standard. Oddly, one of Dijkstra's favorite languages, Algol 60, was on it's way out. Anyway, in 1968, he wrote an article against the Go To.

In the 80's, i had managers totally go crazy seeing even a single "go to" in my code. Now, while a single "go to" could in principal be difficult to follow, when it is clearly used to exit a doubly nested loop, there's no such issue. The spaghetti argument can't be made. How much of a rat's nest can you make if you are limited to one loop? My argument wasn't that he was wrong. My argument was that by using absolute authoritarian statements, he caused as many problems in the industry as he solved. The C language has the break statement to exit a loop. But one must use "goto" to get out of two nested loops. One of the typically ways to get the same effect is to introduce a state variable. This has two problems. First, state variables can be just as hard to follow, or even worse than spaghetti "go to"'s. Second, checking a run time variable increases code size and slows execution.

The same managers who balked at a single "go to", would scold me for daring to use recursion to solve a problem. Really. Recursion looks strange when you see it for the first time, but it's very powerful. If you're a programmer and don't know it, then it's something you must learn. Get out of your comfortable space and do some growth. Dijkstra would have approved. I haven't yet spotted a reference where Dijkstra was a big Lisp fan, but he was into proving program correctness, and Lisp was and is the language to do that in. You can do lisp without recursion, but Lisp lends itself to recursion so much that many programs use it instead of using loops, and it's quite natural.

Anyway, back to the paper. It's pretty funny. But in his paper, How do we tell truths that might hurt? he never answers the question. It's a rant. If you tell people that they're doing things wrong, you'll ruffle feathers. After all, Galileo was a giant - developing the telescope, discovering all sorts of interesting things with it. But he suffered house arrest by the Vatican for his arrogance. Yet, it doesn't seem to occur to Dijkstra that there's only a little difference between "You're doing it wrong", and "there is a better way to do it". And yet the difference makes all the difference. There is plenty of evidence that the Vatican was already cool with a Sun centered solar system. It wasn't the facts so much as the way they were delivered.

I'm currently learning COBOL - a language i've been avoiding for decades. It's not that it's difficult. It's a little clunky. But it can certainly get the job done. And in the late 70's, everyone claimed that it was on it's way out. But forty years later, it's still going strong. So, what did people know back then? Anyway, the paper starts by calling COBOL a disease to either fight or ignore. Hysterical. But, let's see how the other sound bites hold up.

Programming is one of the most difficult branches of applied mathematics; the poorer mathematicians had better remain pure mathematicians. I agree that programming is difficult. I have an engineering degree. When you design a car, you reuse the same bolt design over and over. In programming, if you're doing the same thing again, you make it a subroutine and call it twice. Ideally, there's no repetition, no repeated parts. And each of those parts works with, reacts, and counter reacts, at least potentially, with every other part in the system. So the complexity goes up faster in programming. Now, only one in four students who start an engineering degree graduate. And, you have to be really sharp to get enrolled. Back in 1975, programmers came from the ranks of mathematicians. Today, it's its own discipline. It's not that mathematicians were poor programmers. Programming requires unique skills. And not everyone gets it. Not all programmers with a Computer Science degree today will meet Dijkra's standards. The standard of competence today is that the programs created work. Dijkstra also required elegance, which leads to mainainability, sometimes performance, in addition to a sort of art appreciation.

The easiest machine applications are the technical/scientific computations. This was likey true at the time. Computers are good at math. If you need to figure out how much the beam will bend under load, it's a pretty easy program to write. But these days, the simulations you need to do for a car crash aren't exactly easy. It's just that computers in 1975 weren't up to the task. I'd say that business applications are the easiest. That's not to say that they're trivial.

The tools we use have a profound (and devious!) influence on our thinking habits, and, therefore, on our thinking abilities. The language you learn, be it English or whatever, has cultural prejudices embedded. And, solving a problem in Lisp will almost always lead to a very different approach than solving it in C. Having done both, my initial guess, that one language would be better than the other at some tasks, has been validated. So with any two languages, each will have it's strengths. I wrote both solutions, using the available language features and styles. So it's not necessarily thinking habits. Habits can be broken. Prejudices can be fought. The process is the same. Think about everything. Don't take anything for granted. Anything less is lazy. So, Dijkstra is right, but not in any absolute sense. In particular, we should not all switch to Lisp, even if that is the language where it's easiest to "prove" the correctness of our programs.

FORTRAN --"the infantile disorder"--, by now nearly 20 years old, is hopelessly inadequate for whatever computer application you have in mind today: it is now too clumsy, too risky, and too expensive to use. FORTran, about 50 years old, has evolved. One of the quotes going around in the 80's was I don't know what language we'll be using in the year 2000, but it will be called FORTran. It's not my favorite language. Last i used it, it was difficult (but not strictly impossible) to write code that manipulated text symbolically. It was great for math computations, but not great at symbolic math. When i got to use C, which is pretty good at math, pretty good with text, and OK with symbols, i pretty much only used FORTran if i had to. But it's still in use today. It's just not as clumsy.

PL/I --"the fatal disease"-- belongs more to the problem set than to the solution set. PL/I was an IBM language. I wrote one of my very first programs in a subset of PL/I, called PL/C. I was maybe 12 or 13. It was block structured. It seemed OK. But i didn't stress the language, so i have no idea what Dijkstra might have been on about. It couldn't have been as bad at the time as BASIC, from Dijkstra's perspective. Last i heard, PL/I was in use at IBM internally only. It may have been abandoned by now.

It is practically impossible to teach good programming to students that have had a prior exposure to BASIC: as potential programmers they are mentally mutilated beyond hope of regeneration. Well, BASIC seemed to encourage GO TOs. All lines were numbered, and these numbers could be used as labels for GO TO. Numbered lines made editing easier. But BASIC had for loops. And these loops added some block structure. Another issue was that all variables had global scope. That limited the size of programs by making the complexity needlessly high. Later versions of BASIC fixed these issues by adding real block structure, local variables for subroutines, and even recursion.

The real problem with BASIC wasn't that it damaged anyone. It was that the tools it provided were good enough. And programmers that learned it, tended to write code in other languages as if those other languages were BASIC. It was comfortable. But Bruce Lee had it right: “There are no limits. There are plateaus, and you must not stay there; you must go beyond them. If it kills you, it kills you.” Bruce studied martial arts. It's hard to imagine that learning Lisp will kill you. And, Lisp might have been what Dijkstra was thinking about as an alternative. It gave you block structure, recursion, complex data structures, and things that are difficult to imagine if all you've seen before is BASIC. The Lisp/Algol course i took in school gave us five weeks for Lisp and two weeks for Algol. Algol is more similar to BASIC. Five weeks was not nearly enough for Lisp. Two weeks was like luxury for Algol.

The use of COBOL cripples the mind; its teaching should, therefore, be regarded as a criminal offence. I've just started with COBOL in detail. I suppose that Dijkstra would have considered this, like suicide, to have the perpetrator and the victim be the same person. So he'd likely consider it an unpardonable sin. Maybe i'd get special dispensation for learning it as my fiftieth language. But from what i've seen of COBOL, all of the complaints that Dijkstra had for BASIC and FORTran apply to COBOL. There may be more complaints. Perhaps the idea that COBOL is so verbose is one of them.

APL is a mistake, carried through to perfection. It is the language of the future for the programming techniques of the past: it creates a new generation of coding bums. I haven't seen APL (A Programing Language) in decades. Perhaps it's dead now. It had some warts. It required a non-ASCII character set that included the entire Greek alphabet. That made it difficult to use in an era when most computer terminals could only display UPPER CASE. APL used single greek letters for built-in function names. And, one would string together dozens of these letters together without spaces to form a new function. Calling it hard to read is an understatement. I thought of it as a write-only language. However, it was terse. Whole programs were often a single line, and a short one at that. And, terse can be good.

The problems of business administration in general and data base management in particular are much too difficult for people that think in IBMerese, compounded with sloppy English. I believe Dijkstra is talking about COBOL again, though maybe with JCL - the other language i'm learning currently. I don't think he was talking about SQL - the Standard Query Language, used by most databases today, invented at IBM. I have issues with SQL, but i'll save that for some other rant. Obviously, business administration has worked using COBOL. I'll grant that other languages would have been OK too, possibly better. But the computer scientists of the 70's turned out to be wrong on many, many fronts, when predicting the future. Their logic was sound, generally. It was the assumptions that were mostly wrong. Can't fault them too much for that. Things happened in computers in the past 30 years that would have been hard to believe. So they probably wouldn't have given much thought to the ramifications. But memory is more than a million times larger. Disk storage is a million times larger. Everything is 10,000 to a million times faster. Everything is cheaper. The rules and goals have changed.

About the use of language: it is impossible to sharpen a pencil with a blunt axe. It is equally vain to try to do it with ten blunt axes instead. I agree with him here. Well, he was vague enough that he could actually get away with being general.

Besides a mathematical inclination, an exceptionally good mastery of one's native tongue is the most vital asset of a competent programmer. I'd agree if i thought that mathematical inclination was very important for computer programming. Native language skill is paramount, to be sure. But i know people who are very good at math that absolutely do not grasp programming concepts in any practical way. I was pretty good at math, but i don't see that it helped me overly much. Skills are skills. Is there one skill that everyone will find more difficult to master than every other? I doubt it.

Many companies that have made themselves dependent on IBM-equipment (and in doing so have sold their soul to the devil) will collapse under the sheer weight of the unmastered complexity of their data processing systems. This simply hasn't turned out to be the case. Perhaps all the big companies have made themselves dependent on IBM or MicroSoft, and so are on equal footing with each other. Digital Equipment, which was a clear alternative to IBM in the 70's, is gone. IBm is still with us. Of course Digital's demise didn't necessarily have anything to do with the quality of their technology, for good or ill.

Simplicity is prerequisite for reliability. What is a prerequisite for reliability is program correctness and maintainability. Generally, these are achieved through simplicity. But i've written programs that i could maintain, but had much difficulty in explaining. They were as simple as i could make them, but that didn't turn out to be very simple. The requirements demanded a certain minimum level of complexity. Yet, these programs had long lifetimes. They were configurable by anyone, and that was pretty much the only maintenance required.

We can found no scientific discipline, nor a hearty profession on the technical mistakes of the Department of Defense and, mainly, one computer manufacturer. Obviously, it was done. I agree that it was a bad idea. And, the industry has managed to move away from that model to some extent. Unix, and the open source movement have had an incredible effect on the industry.

The use of anthropomorphic terminology when dealing with computing systems is a symptom of professional immaturity. I'm not entirely sure where Dijkstra is coming from with this. It's certainly a mistake to talk about computers as "thinking", at least at the moment. Take the example of the chess player. Humans and computers do use some of the same logic. But they don't get at strategy from the same perspective. Humans do better at recognizing situations as similar to historic situations, and work with classes of problems. Computers tend to work at the tactical level so deeply that strategy emerges. So it's different. And that's just one example. It gets worse with more complicated problems. But maybe he meant this: So, there's a bug, and because the computer saw this datum, it came to this erroneous conclusion. It happens. And Dijkstra may call it immature because that's what parents do with their infants, when no such claim could possibly be scientifically made.

By claiming that they can contribute to software engineering, the soft scientists make themselves even more ridiculous. (Not less dangerous, alas!) In spite of its name, software engineering requires (cruelly) hard science for its support. If by soft sciences, Dijkstra includes philosophy or psychology, then i agree. Otherwise, i've no idea what he's talking about.

In the good old days physicists repeated each other's experiments, just to be sure. Today they stick to FORTRAN, so that they can share each other's programs, bugs included. In the 1980's, when C++ was gaining momentum, the claim was that you'd write a good class (set of methods combined with a data representation), and it would simply be reused. You were done with that problem. And the joke was, "Now we can reuse all of our mistakes". My good friend Karl lamented that he was rewritting his subroutine library (the equivelent of a class) for the third time, so solve some issue. I thought version two was pretty damned good. So i told him that "all software
needs to be rewritten". (And in this sense, Dijkstra was right, you are doing it wrong. It can always be better in some sense.) But in the open source arena, you can use the existing code to stand on, and fix it if it's broken. And, you can contribute your fixes, so that when the next version comes out, it has your fixes, but also everyone else's. And there's open competition to have the best code to steal. Physicists still repeat each other's experiments, when at all practical. Otherwise, they examine each other's data.

Projects promoting programming in "natural language" are intrinsically doomed to fail. I think, with the victory of IBM's Watson in the game Jeopardy, natural language is within the grasp of computers in the near future. But Dijkstra was likely talking about COBOL, which was touted as readable by (non-technical) mangers.

PS. If the conjecture "You would rather that I had not disturbed you by sending you this." is correct, you may add it to the list of uncomfortable truths. The current most disturbing thing i've heard is from Carl Sagan's 1980 Cosmos series. He talks about how carbon dioxide has formed a greenhouse on Venus that keeps the surface temperatures hot enough to melt lead. Then he goes on to say that we are engaged in a similar, but uncontrolled experiment with our own atmosphere. Back in 1980, there wasn't much talk about it. We're talking about it now. Sagan didn't say anything in his series that wasn't already solid science. That's why so much of the series is still so relevant, 30 years later. What's most disturbing is that many are still in denial about climate change.

If Dijkstra wanted computer engineering to be practiced by an elite, then perhaps politics, on which our shared planetary environment depends, should be dictated by the best scientists. Just because industries of all sorts have survived with mediocre computer programming, doesn't mean that the Earth will make it. Consider that moving to Mars isn't a solution. Moving to Antarctica is much easier. You don't need to manufacture your own air.

Tuesday, March 08, 2011

Sounds Fast

My newest Sansa mp3 player has slow, normal, and fast modes for podcast play. The fast mode increases the rate at which sound is played back. And the idea is clearly to get through material faster. A side effect is that the pitch of the sound is increased. It's like playing a tape faster than it was recorded. There are techniques for playing back a digital recording faster, without changing the pitch, but this unit isn't doing that. There are both computational and quality advantages to the way the Sansa does it.

I measured the speed at which fast mode plays. It takes 80% of normal time. So, a track which would normally take an hour will take 48 minutes. That's a 12 minute savings. The speed is therefore 1/0.8 = 1.25 times normal. As an aside, in marketing, people do the sale percent math inconsistently with each other, often making it difficult or impossible to predict what the final price will be. This case might be reported as either 20% faster or 25% faster. I'm trying not to be sloppy.

Some of the podcasts either have music introductions, or the show is actually about music. So, for example, i listen to my friend Craig's Open MetalCast. He interviews artists, but also plays tracks from their albums. I was curious how the pitch changes for music and voices. How would one figure this out? It should be a case of a little math.

A piano keyboard is organized into octaves. Each octave going up in pitch has a frequency that is exactly twice as fast as the previous octave. Now, you might think that there are eight notes in an octave - since the oct prefix means eight. The notes are labeled A through G, which is seven notes. The eight comes from counting the note that you start on. So, in this case, A is counted twice. And, indeed, there are eight. But, there are 5 black keys interspersed. There are a total of 12 notes to an octave. You still have to count the starting note twice. It's a fence post problem. The way to solve fence post problems is to think about each one carefully. Otherwise, you'll be off by one.

In the modern equal tempered scale, each half note - adacent keys on a piano, has the exact same frequency ratio as any other adjacent keys. Since there are 12 steps in an octave, and an octave gives you a factor of 2 frequency change, the ratio for a half step is the 12th root of 2, or 2^(1/12).

Now, remember that the speed change is a factor of 1.25. If we want to find out how many half steps that is, we need to know how many times we must multiply the 12th root of 2 by itself to get 1.25. So, here it is in algebra. We just need to solve for x.

(2^(1/12))^x = 1.25

We can take the logarithm of both sides and preserve the equality. It doesn't matter what base log you use. Your calculator may have a base 10 logarithm funcion labeled "log", and a natural logarithm (base 2.718...) button labeled "ln". The Windows calculator, in scientific mode (use the View menu), has these.

log(2^(1/12)) * x = log(1.25)

we can divide both sides by the constant log(2^(1/12)) and get:

x = log(1.25) / log(2^(1/12))

Plugging this into a calculator:

x = 3.8631371386483481744438331538727

This is the first thirty two digits of the answer. I'd be very surprised if the full answer has fewer than an infinite number of decimal digits. Since i only measured the speedup to about a part per 1000 (to the second over about 17 minutes), the result should be rounded to 3 significant digits, or 3.86. So, the speedup is more than a minor 3rd, and closer to a major third. It's not exact. So, all music played this way will not be in an A 440 based key.

As an aside, the quartz crystal used to regulate how the sound is produced is likely accurate to at least nine significant digits. A part per billion. It's quite possible that the manufacturer designed the speedup to be arbitrarily exactly 25% faster. In that case, nine digits, or a value of 3.86313714 might be justifiable. Or, again, who knows, the manufacturer could have wanted A 440 music to stay A 440 (but transposed), and set the speedup to be about 1.25992105 times faster (to get a major 3rd).

Anyway, more or less a major third. What's interesting is how a major third changes everything. Many voices are nearly unrecognizable. The tonal quality of voices generally change dramatically. There are very few spoken voices that you thought were typical deep male radio voices that you'd consider at all deep when played faster. Many adult voices sound like children. And music vocals, singing or rap, change in character similarly. But instrumental music usually sounds pretty normal right away, or pretty normal after a few seconds.

What amazes me about this is that my musical sense of pitch is quite relative, not so much absolute in nature. I can't tell you if a piano is a half step flat, generally speaking, even if i play it. Sometimes i'll accidently play a left hand part in the wrong octave without noticing. Yet, the character of the voice is quite apparent.

Another aside, when i play violin, i carefully tune each string with an electronic tuner. If a string goes out of tune, it generally goes out of tune with respect with the other strings. Once my brain has an absolute reference, i can get the instrument to play accurately pitched notes. There are no frets on a violin. You have to put your fingers in the right spots to get the right pitches.

In the mean time, there is a little music in my podcasts. This music, when played up a major 3rd, often sounds odd for a bit, then i get used to it. There is the odd piece that doesn't translate. For example, Beethoven wrote the Moonlight Sonata in C# minor. You can get a sheet music version transcribed (transposed down a half step) in C minor, which, having fewer sharps and flats, some people find easier to play. If i hear it played in C# minor, then hear it in C minor, it sounds disturbing to me. But if my piano is consistently tuned a half step down, and there's no absolute reference, i'm totally cool with it.

Anyway, this is a little thing. There's a function on my mp3 player. A curious thing, and i was curious. Was there more to think about for this function? Maybe. This musing was well within my comfort zone. I just sort of rambled around and played with what appeared interesting in my most distracted ADHD sort of way. But Bruce Lee had a different idea. He said, There are no limits. There are plateaus, and you must not stay there; you must go beyond them. If it kills you, it kills you. Bruce was into martial arts. A little curiosity won't kill you, unless you're a cat.

Wednesday, March 02, 2011

Pope: Jews not to be blamed for death of Jesus

Pope: Jewish people must never again be blamed for crucifixion

So, Pope Benedict XVI says that Jews are not responsible for the Death of Jesus. Must be a slow news day. The Vatican has maintained this view for decades. But i'd heard the view as a kid and rejected it out of hand.

There's a passage in the Gospel of Matthew, where the Jews shout to Pilate, Let his blood be on us and on our children. For one thing, if this was said at all, these people didn't have the authority to say such a thing. How could they? But since Christianity didn't exist, all Christians at the time were Jews. Further, despite the rampant ramblings of Paul, the Christian Church is founded on Peter, who taught at the synagogue. Christianity is built upon Judaism. Get over it. So, if the Jews are somehow responsible for the death of Christ, so are Christians. And probably Islam. Everyone else is innocent. BTW, if i'm responsible for the death of Jesus, i'm cool with it.

One expects that Biblical scholars have thought about this before. And, they probably have thought about the next puzzle. After all, Biblical scholars should be thinking about the basest blasphemy possible, if only to strengthen the faith. And that is, this. Given that Jesus partakes in the divinity, he could certainly have avoided his own death. He clearly knew about its coming in advance. Scripture says he was tempted to do something about it, and chose not to. So, was Jesus responsible for his own death? Was it assisted suicide?

Wednesday, February 23, 2011

Task Master

I've been using Windows since 3.0, even if it wasn't my first choice. Sitting in front of Windows XP, i happened to notice something i'd not seen before. I had a long running task - consuming CPU time. The interactive response had become crappy, even though the machine is generally pretty capable and modern. I brought up the task manager, and found my program in the Processes tab. On a whim, i right clicked on my task. A pull down menu came up. One of the entries is Set Priority. There are six entries, Realtime, High, AboveNormal, Normal, BelowNormal, and Low. There was a bullet by Normal. I set it to BelowNormal. My interactive response snapped back to reasonable. And, the task seemed to be getting most of the wall clock time in CPU time, as i'd wanted.

Now, i could rant about how under Linux, or other Unix variants including MacOS, the normal priority for a CPU bound task does not, in general totally mess up interactive response. It's just under Windows. I could also rant about how right clicking on random data is not a particularly discoverable user interface. It's not like my employer gives me a Windows manual to read, or the time to read it. I can't very well right click on every little piece of data in every window. But at the moment, the fact that there's a problem i can actually fix, and easily, is a good thing.

Tuesday, February 22, 2011

Vaccination

The US Supreme Court has ruled that vaccine lawsuits can be preempted. I'm no lawyer. I know neither the law involved, nor the case involved. But here's my take on it.

As a parent, what i want is the highest chance of a good outcome for my child. No vaccines are perfect. None protect every child. Often it's just 80%. But if all children are vaccinated, then the disease has fewer places for transmission, and the all children are protected. So, vaccines protect not only my child, but all children against some dread disease. It may also harm a few, even if everything is done as well as can be done. Chances are still way better for all of the children. Having parents opt out of a vaccination program doesn't just fail to protect their kids, it also fails to protect my child. And, we're starting to see cases of dread diseases for the first time in decades. Kids now face death at much greater numbers than they did with vaccines.

It's not a perfect world. But vaccines have certainly made it better.

I'm no lawyer, and won't comment on any particular litigation. But as a society, we're smarter if we decide to protect ourselves. Is it worthwhile to compensate the one in a million harmed while protecting the million? It's a fair question. Perhaps the vaccination laws could have put in non-confrontational compensation to the few. For all i know, they did. Having been to court, i've come to this conclusion. We'd like justice, but we have the courts instead.

On the subject of protecting ourselves, there are diseases, like polio, where we vaccinate, but haven't had a case in the US for ages. It costs alot to vaccinate. But we could forego it once we've eliminated polio from the Earth, as was done for smallpox. And we could fund such an all out attack on polio, and come out ahead in just a few years. The economics make sense, even if we're all totally selfish bastards.

Monday, February 14, 2011

Valentine's day car

Saw an advertisement from a car company suggesting that having a cool car loaded with features might impress your first date. Yes, it's Valentine's Day. Of course, St. Valentine had nothing to do with sex.

My first date (in a car) was with a Lincoln Continental Mark iv. Quiet, smooth, electric sun roof, and with a 7.5 liter v8. The family Lincolns actually had climate control, not a silly blend door control. We'd set the thermostat to 72 year round, and it'd turn on the a/c or heat as needed. But my date was disappointed. She knew i had access to a real beater: an F-250 with three quarters of a ton of character. No tail gate, an electric bench seat taken from a Buick - not even bolted to the floor, AM radio, starter motor on it's last legs, and zero fear of dirt. Every ride was an adventure, with no cell phone to call for help. What more could one want?

And these days, my car is a stripped down 2000 Saturn. It's a 4 door sedan with a 1.9 liter straight four, front wheel drive and 5 speed manual. It's got 285k miles now, and has averaged over 43 MPG. The 12 gallon tank costs $36 to fill at $3 a gallon. Sure, it only goes 500 miles on a tank. When the wife and i go somewhere, it's not in her much younger, more comfortable vehicle. We keep the excitement going.

A USA Today article says that the Ford Escape hybrid is $7,600 more than the Ford Escape non-hybrid. It gets 9 more miles per gallon (MPG) - 32 MPG vs 23 MPG combined. The obvious question is how many miles before the hybrid breaks even on cost?

$7600 / (($3/g / 23m/g) - ($3 / 32m/g)) = 207,170 miles.

This assumes that maintenance for the hybrid will be zero. That's probably not true. But it also assumes that gas will be $3 a gallon for the life of the car. My guess is that gas will go up. It was $4 a gallon in 2008. Math is a powerful tool, if used to inform. But it's important to know what the math is telling you, and what it doesn't say.

I did this math for the Escape in 2008. The answer was 270k miles. Gas was $4 then. My car at the time had 295k miles, so it seemed at least a possible win. But, given that the break even cost is lower now, at least Ford is making headway towards making hybrids worthwhile economically. That's encouraging. Hybrids make more sense for people with lots of city miles, like taxi drivers. I drive lots of highway. I don't expect a hybrid in my near future. Turbo diesel might be nice.

There's more math. If $7,600 makes such a big difference that it takes 200k miles to make it up, clearly, the purchase costs dominate. Since i didn't get a car that's bigger than i needed, i saved huge amounts up front. And i bought it used, saving most of that. I spent less than 10% of the $23k non-hybrid Escape. And, since it's smaller, it gets better economy too. What have i spent my money on? Well, mostly on family essentials.

The total dollars aren't the only concern. There's also capability. My current favorite new car on the market is the Fiesta. I don't happen to know if my telescope will fit in it. I'd like a vehicle that can tow a boat. I've got a boat. The Fiesta won't do it. One cheap way is to get an old body-on-frame car. I've got the car. It needs an engine. I expect to come out ahead compared with buying a truck. It'll get 30 MPG when not towing.

I remain convinced that cars are not a good investment. It often makes sense to put money in an old car even if the resale value is lower. Invest in your own comfort. Realize that comfort is ephemeral. What's the cheapest way to get what you want for the longest time? Buying another junk can set you up for expensive diagnostic costs. Taxes devalue other vehicles compared to yours. I'm glad that people buy new cars, though. Please buy a new Fiesta so that in a few years when my Saturn dies at 350k miles, i can buy it from you. I'd like the smallest engine, turbo if you can get it, with the manual transmission, please.

Tuesday, February 01, 2011

Trader Joe's Wine

So, i've got a head cold. Concrete in the sinuses. I'm not on my death bed, so i'm going to work. Last night, i got a free music track download from Sharon Bautista, called Trader Joe's Wine. It's a preview of her new album. I put it on my mp3 player in the morning, but waited until i was at my desk to listen to it. After all, it's noisy in the car. By the time i got to work, i was in a kind of sour mood. Damned cold. As i started the tune, i felt like a music critic. Was this another song about song writing? Almost no one can pull that off. But half way through the piece, i'd calmed down and just let it move through me. When it seemed to be getting slow (i really doubt the tempo changed), it switched to some sort of bridge, which really does pick up. Sharon has a beautiful voice with some vocal range and variety.

My music biases are few. I listen to Contemporary American Folk, Classical, Indian, Industrial, Rock, Disco, Movie Soundtracks and so on, and even in shuffle mode. Mozart next to Sister Machine Gun. Rap isn't music. I don't listen to much Country. My rules are these: If there are no lyrics, then the music has to do something. I would say that there must be melody and chord progression, but i've heard good atonal music that really goes somewhere. If there are lyrics, they have to be presented so the listener can hear them, and they have to have something to say. And it can't be some dead horse you're flogging. Country often violates this. It's "he left her", or some such tear jerker, but the same plot as the last ten songs.

This bit about saying something is tricky, since it's really easy to sound like you're on a soap box, preaching your personal Gospel. Worse, my all time favorite pieces really are someone preaching their personal Gospel. The main trick that saves these pieces for me is to show some insight. For example, P!nk's So What? is a "He left her" song, but she's already picked herself up and figured out that he's not her whole life. Sure, it hurts, but life goes on, and there's hope for the future after all, and it could be even better. Without giving away the plot, Trader Joe's Wine has a situation, and presents, well, if not a full solution, then at least something that makes it suck less. If Sharon writes her own stuff (and i think she does), then in addition to a voice, she's got serious writing talent.

If this track is representative of the album, then it's pure gold. In the old days, when albums had mostly top 40 radio (which was really top 5 with a few stray tracks), i was happy if an album had only one track i liked. In this case, i've heard one track. And if that's the only track on the album i'll end up liking, it will still be worth it. Even though i've already got the one track. Perhaps i don't really have a one track mind.