Happy Birthday, Bill! (in COBOL)

COBOL turned 50 a few years ago, and today is the birthday of the only person I know who programs in COBOL.  So, here’s a COBOL program, because I get really easily distracted.

      * Wish Bill a Happy Birthday if it's 05-06
      * Wish COBOL a Happy Birthday if it's 05-28.
      * Tell us how old COBOL is now (full years only)
      * Works for other people who share the same birthday, of course.
       IDENTIFICATION DIVISION.
       PROGRAM-ID. BillsBirthday.
       ENVIRONMENT DIVISION.
       DATA DIVISION.
       WORKING-STORAGE SECTION.
       01  TODAY.
           02  YYYY  PIC 9(4).
           02  MMDD  PIC 9(4).
       01  BILLBDAY.
           02  YYYY  PIC 9(4).
           02  MMDD  PIC 9(4) VALUE "0506".
       01  COBOLBDAY.
           02  YYYY  PIC 9(4) VALUE "1959".
           02  MMDD  PIC 9(4) VALUE "0528".
       01  AGE       PIC ZZ9.
       PROCEDURE DIVISION.
       MOVE FUNCTION CURRENT-DATE TO TODAY.
       IF MMDD OF COBOLBDAY <= MMDD OF TODAY THEN
         COMPUTE AGE = YYYY OF TODAY - YYYY OF COBOLBDAY
       ELSE
         COMPUTE AGE = YYYY OF TODAY - YYYY OF COBOLBDAY - 1
       END-IF.
       DISPLAY "COBOL has been around for " AGE " years."
       IF MMDD OF COBOLBDAY IS = MMDD OF TODAY THEN
         DISPLAY "Happy Birthday, COBOL!"
       END-IF.
       IF MMDD OF BILLBDAY IS = MMDD OF TODAY THEN
         DISPLAY "Happy Birthday, Bill!" 
       END-IF.
       STOP RUN.

To try it out, see opencobol.org

 

Math Trick vs Coding Trick

I have some code where I have a value x=2^n, and I wanted to see what that n was, knowing that there’s only one 1 in the binary representation, and it’s not a huge number.  I know it’s not hard, but I was wondering if there was a better way, so I looked around.  I ran into a post from someone (student?) who had to compute the same thing without branching, and that got me thinking.

I’ve now written this two times and found a few more ways, unrolled one of them by hand to see how much that helped (some, but not a whole lot), but here are the main four contenders:  the naive way, the log-trick way, inline assembly language, and using DeBruijn sequence:

Code: (all were set inside an int func(int) wrapper)

  1. while((x>>=1)>1) y++;
  2. y=log(x)/log(2);
  3. asm(“fld1; fld x; fyl2x; fstp y;”)  (wrapped with type conversions from integer to float and back)
  4. y=myDeBruijnArray[(unsigned int)(x*0x077CB531U) >> 27]; (where “myDeBruijnArray” is a lookup table 32 32-bit numbers)

Times:  (for 10,000,000 iterations)

  1. 0.602, our base case for 16 bits.  Counting 8 bits ran almost twice as fast, as one would expect, and I’d imagine that counting out 32 bits would take even longer.
  2. 2.098, which makes sense because we’re doing two function call to math libraries, but it met the condition of “no branching” that the one student had.
  3. 0.521 or 0.715 (see below), which gets us out of our conditional, but at the cost of using the FPU which has a suprising amount of overhead, and again, the number of bits makes no appreciable difference.
  4. 0.283, which has an “expensive” imul opcode, but that’s it.

One interesting thing about the assembly language:

I expected the function that was all inline assembly language and some space for variable to result in the smallest code, and it wasn’t.  There were 14 more extra assembly language operations to convert between the unsigned int value I had to start with and the floating point values I needed for the assembly language and back again.  The DeBruijn method used the standard headers and footers for the command that all of the versions used, and then four lines:

mov  eax,dword ptr [x]
imul eax, eax,77CB531h
shr eax, 1Bh
mov eax, dword ptr myDeBruijnArray [eax*4]

Because of conversion time, I wanted to try doing the inline assembly code, but instead of calling the routine with the integers I was using elsewhere, I changed from an integer to a floating point before making the call to the routine, leaving the assembly language version strictly in floating point numbers, and it turns out that using assembly language with all floating-point values saved enough time for assembly language to be a hair faster than the naive approach, and of course if I had to use floating points anyways, it’s a *lot* faster than calling the math libraries.  It turns out that I could even drop the last “store my FPU register in Y” and leave it on the top of the stack for the return value, which is what “return y” does anyways, so now that function looks like this in assembly language,

fld1
fld         dword ptr [x] 
fyl2x

They take longer to run than the op codes we needed for the DeBruijn code, but that code *only* works for integers, and knowing that there’s a log2 function in the processor that’s not in the standard library cuts my time by 75%, which if I had to do a lot of it (data mining?  Video processing?) could be very significant.  Also, use integer variables instead of floating-point variables when you do not need the latter.

Special icons

It’s common knowledge that favicon.ico will let you change the icon that most browsers use for the bookmarks, tabs, etc.

For Apple devices, you want to read this:

http://developer.apple.com/library/safari/#documentation/appleapplications/reference/safariwebcontent/configuringwebapplications/configuringwebapplications.html

To summarize:

apple-touch-icon.png for iPhones before 4.0, and they should be 57×57 pixels.

apple-touch-icon-72×72.png for iPads

apple-touch-icon-114×114.png for iPhone4

5-bit code

While in the employment of PSU, I was charged with implementing an online license system. Part of that implementation involved the user entering in data that was printed, either in a textbook or from a webpage, and at some point we were using an SHA-1 digest, which meant that this involved 160 bits, or 20 bytes, of data.

From http://en.wikipedia.org/wiki/SHA-1, we have the SHA1 hash of “The quick brown fox jumps over the lazy dog” represented as 2fd4e1c6 7a2d28fc ed849ee1 bb76e739 1b93eb12, which, as it’s using hex which uses 4 bits per digit, is 40 keystrokes.

While I didn’t really consider this option at the time, it turns out that using A-Z, a-z, 0-9, and two more characters, we could get 6-bits per keystroke for 27 characters, but that would involve a lot of confusion and hitting the Shift key a lot, which if you count as a keystroke, would bring up the keystroke count to (27*(1+(26/64))=almost 38 actual keystrokes, if you only needed the Shift key for the uppercase alphabet. That number could be decreased a little by removing some of the uppercase alphabet and using more non-alphanumeric symbols, but it also would be slightly less efficient to code and is a lot less elegant.

The solution was to use a 5-bit alphabet that was not case-sensitive. Using A-Z and 0-9 gives us 36 characters, and for a 5-bit alphabet we would only need 32 different characters. Using 5 bits per keystroke, we would also have 32 characters, a 20% improvement over the original 40. My solution was to drop the numbers 0 and 1, and the letters o and i, and to always display these codes that the user needed to enter in uppercase letters. None of these 32 characters look so similar that they would be mistyped, and they are all available on American and European keyboard layouts: 23456789ABCDEFGHJKLMNPQRSTUVWXYZ. Furthermore, two of the blocks of characters appear in the ASCII table in 3-bit blocks: 2-9 and A-H, making it easy and fast to decode using one bit test, one integer comparison, and one integer subtraction per 5-bit digit, plus whatever bit shifting would be necessary to line it up as part of a larger value.

Representing the two most significant bits by column, and the 3 least significant bits by row, we get the following, color-coded for each grouping of characters that are adjacent in both ASCII and my 5-bit encoding:

5-bit Code
msb=0 msb=1
00 01 10 11
000 2 A J S
001 3 B K T
010 4 C L U
011 5 D M V
100 6 E N W
101 7 F P X
110 8 G Q Y
111 9 H R Z

The fact that my initials are the first characters each of the letter-based columns is purely coincidental.

Example, using the previous sample data:

2fd4e1c67a 2d28fced84 9ee1bb76e7 391b93eb12 (grouped as 4 40-bit groupings)

2fd4e1c67a = 0010 1111 1101 0100 1110 0001 1100 0110 0111 1010 (grouped in 4-bits)

00101 11111 01010 01110 00011 10001 10011 11010 = 7ZCG5KMU(grouped in 5-bits)

2d28fced84 = 00101 10100 10100 01111 11001 11011 01100 00100 = 7NNHTVE6

9ee1bb76e7 = 10011 11011 10000 11011 10110 11101 10111 00111 = MVJVQXR9

391b93eb12 = 00111 00100 01101 11001 00111 11010 11000 10010 = 96FT9USL

So, instead of

2fd4e 1c67a 2d28f ced84 9ee1b b76e7 391b9 3eb12

we have

7ZCG 5KMU7NNH TVE6 MVJV QXR9 96FT 9USL

with no confusion over the “is it an 0 or an O, a 1 or an l or an I?” issue, fewer keystrokes than some other systems (hex),nearly maximized data per keystroke.