Rounding Can Really Be a Pain in the Rump

bug.gif

This morning I had a funny little bug in the Greek Engine that was really a hold-over from my Ticker Plants, regarding the creation of the security ID - the 128-bit version of the complete instrument description for use in maps, keys, etc. The problem was that the exchange codecs were correct in their work, it was the creation of the security ID that was at fault, and I needed to dig there to find the solution.

Basically, I pack the components of the instrument definition into a 128-bit unsigned integer, and to so this efficiently, I need to have a pointer that points to where the next component needs to be "dropped in". When I got to the strike, which was passed in as a double, I had the code:

  // finally, slam down the strike
  *((uint32_t *)ptr) = htonl((uint32_t)(aStrike * 1000));
  // swap the network order bytes to host order
  byteSwap();

and because of the (aStrike * 1000), I was getting 64.099 when I should have been getting 64.10, among other rounding errors. What I needed to do was pretty simple, but essential to get the right answer:

  // finally, slam down the strike
  *((uint32_t *)ptr) = htonl((uint32_t)(aStrike * 1000.0 + 0.5));
  // swap the network order bytes to host order
  byteSwap();

and with that, we got the right numbers. We even got the right thousandths place in the case of 8.125, for example. I'm sure there was partly the need to cast the 1000 into a double, but the additional movement by a half was the thing that brought it home.

Now we're OK.