Over the last few months, I have been sending to my software group at work a puzzle/quiz in the form of a bug I have found in my robot code. They seem to get a kick out of especialy since I offer a Peppermint Patty as a prize to the first right guess.
#1
Over the weekend I spend a few frustrating hours tracking down a bug in this seemingly simple idiot proof code. All it does is take the absolute value of a long integer (32 bits on an ARM processor).
long labs(long val) { long retval; if (val < 0) { retval = -val; } else { retval = val; } return retval; }
So most of the time this code does exactly what you might expect. It returns the absolute value of the parameter you pass in. All except in one case. Can you figure it out?
#2
What does this code do and why do it this way?
uint32_t val; val = (val << 3) + (val << 1);
#3
What is the next larger number greater than 8,388,608.0 when using an IEEE float.
a) 8,388,608.002 b) 8,388,608.2 c) 8,388,609.0 d) 8,388,680.0
#4
Over the weekend I was working on a section of code that would increase then decrease the speed of my robot every 6 seconds to check the stability of my PID control loop. My task was running at 5Hz and each call to GetTimeInMilliseconds returned a number in the sequence 0, 200, 400, 600, … Needless to say I had a bug in this code as it did not change the speed at the desired rate. What did I do wrong?
uint32_t systemTime; double speedSP; /* Get the current time in milliseconds */ systemTime = GetTimeInMilliseconds(); /* Alternate between fast and slow every n seconds */ if ( (systemTime % 6*1000) == 0) { /* The error is not in this comparison as 4.0 is exactly represented as a float */ if (speedSP == 4.0) { speedSP = 2.0; /* Set speed setpoint at 2 m/s */ } else { speedSP = 4.0; /* Set speed setpoint at 4 m/s */ } }
Great challenge, thanks!
#1 is a problem because integers are represented in 2’s compliment in the range ?2^(n?1) to (2^(n?1))?1 so -(-2^(n-1)) = 2^(n-1) which is outside the positive integer range. So if you’re using 8-bit ints (int8_t), then abs(-128) returns -128. 🙁
#4 is a precedence bug. In C, *, /, and % have the same precedence and so they evaluate left-to-right; effectively the line:
if ( (systemTime % 6*1000) == 0)
is equivalent to:
if ((systemTime%6)*1000) == 0)
So speed would will change every 600ms instead of every 6s.
#2 is equivalent to val*2^3 + val*2^1 = val*8 + val*2 = val*(8+2) = val*10
in most processors, shift operations are faster than multiplication. So this is a faster way of multiplying by 10, perhaps? On the ARM it appears at very quick first glance that some early termination optimization is in place for small number multipliers, reducing the number of cycles required. http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0084f/I20211.html
Michael,
Good job. So far you hit them all on the head.
So far my distribution at work has been about 5 people. Now my manager wants me to send out these puzzles to all his reports totaling about 15 people. If you have any good simple bugs to share, I would love to see them. I can’t always guarantee finding a good one in my own code each week!