2010-12-08

How many days in a month?

A coworker proposed to me a little challenge sometimes I think about. My first solution, though correct, was rejected since it used the ternary operator ?: and there's a way to succeed without.

Today is holiday here in Italy and I am using my spare time pushing the button of my almost-dead laptop just to hear the one-long-beep-two-short-beeps sequence (hoping not to hear it), then hold the button to turn it off and then stick hitting keys on the job laptop — where I am now.

After I've read a lot of pages from On the Edge - The Spectacular Rise and Fall of Commodore, almost finishing it, I decided to let my eyes be enlightened by the LCD of the job laptop, where there's nothing more interesting to do than surfing the net and using gcc (MinGW) in the unpleasant environment MS Windows XP provides.

Ok stop making the post longer than it could be...

The challenge was: using just an expression, get the number of days in a specified month (given as a number from 1 to 12). No-one told me about constraints for February so I assumed it has 28 days; moreover, initially there was no prohibition of the ternary operator...

My first solution was:

g = 31 - ((m < 9)? (m+1)%2 : m%2) - 2*(m==2);

which worked on all the system I've tested it (MS Windows, Sun Solaris on SPARC, and GNU/Linux on Intel) but obviously contains a possible bug dued to m==2 that does not need to be evaluated as 1 when true, though likely it does (As std C says, boolean expressions evaluate to 1 when true; unless we're dealing with non std compliant compiler, or if we translate the idea in other languages).

My second solution is:

g = "103012310321"[m-1] - 18 - (m&2);

This one is maybe tricky but is more robust (provided m is in [1,12] and we are on a system using ASCII), and can be easily modified in order to yield 29 for February. Moreover, what it makes me like it is that it uses something rarely many non-expert programmers are aware of about C (I mean using "array notation" for a literal string). The practice could be marked as bad, but it is great when codegolfing!

About codegolfing... If I am not wrong, that code in GolfRun would be "103012310321"m(=18-m2&- but currently I can't test it since my already-compiled (for GNU/Linux) work-in-progress GolfRun interpreter is on the Real Out-Of-Work Laptop, though I could checkout the SVN repository on this machine and try to compile it with MinGW on MS Windows — what a pity it uses Gtk+ and GMP extensively and I want not to go into the trouble of having them properly installed (ready for development usage) on this hateable system.

The third solution to the challenge that comes into my mind is about looking at the bits. The previous solution already does it... a bit! But the idea can be extended; for this purpose I've made the following table


XY ABCD
31 1F 1 11 11 1 0001
28 1C 1 11 00 2 0010
31 1F 1 11 11 3 0011
30 1E 1 11 10 4 0100
31 1F 1 11 11 5 0101
30 1E 1 11 10 6 0110
31 1F 1 11 11 7 0111
31 1F 1 11 11 8 1000
30 1E 1 11 10 9 1001
31 1F 1 11 11 10 1010
30 1E 1 11 10 11 1011
31 1F 1 11 11 12 1100


We have four bits in input and we need to "produce" just 4 "patterns" (two bits) in output. The boolean table old school (and semplification thereafter) will give us a solution (paper and pen here for a while...) (^ stands for an overbar on the following letter, i.e. for the logical not):


^X = A + B + ^C + D
^Y = ^A^D(B + C) + AD^B



That gave me the code:


g = 28 |
((((((((~m)>>2)&((~m)<<1)&((~m)>>1))^1) &
(((~m)^2)&((~m)>>3))) |
((m>>3)&((~m)>>2)&m&1))^3)&3);


I am rather dissatisfied with this: surely it can be optimised someway, e.g. by doing simple observations like: no need to handle higher bit in logic since it needs just an exception (when m is 2); try to work in "positive logic"; mix ideas from the previous solution with the "gate logic" stuff... Anyway, for now it is enough, I have to go and do better things: I have a button I must push.

No comments:

Post a Comment