Monday, May 24, 2010

MATLAB & C++: Car Talk 1016 Puzzler

Car Talk is a weekly call-in radio show about cars and car repairs on National Public Radio. The hosts, Tom and Ray Magliozzi, are extremely funny and very knowledgeable about the subject. I tend to listen to the show by downloading the podcasts of ‘classic’ episodes (which means ‘old’, ‘previously aired’!)

Among other things the two brothers discuss is the weekly puzzler. That is, every week they hold a contest with a puzzle (brain-teaser) with the winners announced during the following episode (a week later.)

The puzzler on April 19th (I am a few episodes behind) is called Stevie and his Moto and in brief, it asked listeners to find (the) two temperatures in Fahrenheit and Celsius that have the digits ‘exactly reversed.’

For example, [one of the big signs that display the time and temperature] might have read 31 degrees Fahrenheit, and when it showed the centigrade reading it said "13."

Though the contest is now about a month old I decided to spend a few minutes to code a solution in MATLAB and then for kicks re-coded the solution in C++.

MATLAB

The algorithm is straight forward:

  1. Define array of values for temperature in degrees Fahrenheit – no decimals.
  2. Calculate equivalent temperature in degrees Celsius – rounded towards the nearest integer.
  3. Compare 1st digit of degrees F with 2nd digit of degrees C AND 2nd digit of degrees F with 1st digit of degrees C.
  4. If-and-only-if BOTH are equal then we have a match.

For this algorithm to work the range of Fahrenheit values needs to be restricted to the ones that would result in positive Celsius values that also have two digits (which was set as a requirement when the puzzler was explained.) If the range is not restricted then there would be a match for 40F and 4C. And since I like to play around with ideas I added on more test to make sure that the algorithm is more correct: count the digits of the integer.

For integers a quick solution is to count the number of digits for both degrees F and C and compare. For positive non-zero numbers we can use:

>> floor( log10( number) ) + 1;

This works because for positive non-zero numbers the base-10 logarithm provides the exponent of the base that would result in the number. That is:

x = 10^y then y = log10(x)

E.g.

1000 = 10^3 then log10(1000) = 3

Therefore, if the exponent is known the number of digits if the number can be calculated.

The snapshots of the code and output are shown below:

cartalk mfile

cartalk mfile out

C++

The idea is exactly the same. The only difference is that I had to code my own rounding function which is straight forward (even for me!)

 cartalk c   01

The rounding function might not very elegant but works!

cartalk c   02

The output is shown below.

cartalk c   03

5 comments:

  1. Great work! Thanks
    (Give me a few days to check it :D )

    ReplyDelete
  2. Just for fun, here's another way to do it in MATLAB without a loop:

    f = 33:99;
    c = round((f-32)*(5/9));
    i = all(num2str(f')==fliplr(num2str(c')),2);
    [f(i);c(i)]'

    ReplyDelete
  3. hi, MATLAB just posted this entry on fb.
    cool puzzle, I decided to have a go myself in python (not perfect solution but only 6 lines):

    for C in xrange(10, 100):
    F = round(1.8*C+32)
    C = str(C)
    F = str(F)
    if C[1] == F[0] and C[0] == F[1]:
    print 'C=', C,'F=', F

    output:

    C= 16 F= 61.0
    C= 28 F= 82.0
    C= 91 F= 196.0 <-- I know, just ignore that one ;)

    ReplyDelete
  4. @Anonymous: You are right, it is a way to avoid the loop. I have been using MATLAB for a long time and always tried to vectorize and use MATLAB functions. However, since TMW worked on the performance aspect (2-3 years ago?) I have found that you can write intuitive and fast code using brute force methods (i.e. loops). I still vectorize if I have to deal with large data sets or for... old times' sake!

    ReplyDelete
  5. @Rafal: Thanks for the heads up!

    ReplyDelete