|Most Used Stack Overflow Snippet Has A Bug|
|Written by Mike James|
|Wednesday, 11 December 2019|
It is not really a joke that programming has become a matter of copy-and-paste from a variety of sources. Yes, it can save time, but when you just copy-and-paste how do you know the code works? Even a highly up-voted SO answer could, and did, have a bug.
This story has appeared in a few places with a sense of outrage that a snippet of so few lines of Java could be so reused and yet so flawed. How could any decent programmer offer up a solution with so serious and blatant a flaw? How could any programmer copy-and-paste said solution without checking it and without noticing the glaring error? I thought that under the view of thousands of eyes every bug was supposed to be shallow, spottable and correctable. What were the users of SO thinking!
And so the outrage could continue, but the truth is more interesting. The actual bug was subtle, if predictable when I mention that floating-point arithmetic was involved. The big problem with using floating-point is that we all simply assume it is going to work, even though we should know better and have been told a thousand times to be careful. Let's look at the problem in a little more detail.
This all came to light when an academic paper looking in to code reuse announced that a code snippet in Java that printed byte counts in "reasonable" units was the most copied and was embedded in more than 6,000 GitHub repros. This caused the author, Andreas Lundblad, to look at it again, almost a decade after he originally wrote it, and he found it was buggy.
The problem is to print a value using suitable units as a value from 1 to 999.9 followed by the unit. For example 999,999 should be printed as 1.0M. Notice that in this specification printing it as 1000K is not acceptable and this is subtly more difficult to achieve.
The solution proposed used a fairly simple approach. If you have a value and want to scale it into units of K, M, G, T etc then all you need to work out is
After all, the log is the value you have to raise 10 by to get value. So:
and taking an integer value gives 2 as the result.
This means that the units should Mega and the value written with one decimal place is:
You can use:
as an index into a string array for the multiplier and the value in the selected units is just:
where ^ is the raise to a power operator in the language you are using.
So far so good, and it looks like a textbook answer. What could possibly go wrong?
Seriously, many programmers would simply accept the truth of mathematics. The math is correct so the program is correct. Unfortunately the math is only correct if arithmetic is performed with perfect precision and floating-point is far from perfect. The first problem is that 999,999 is displayed as 1000.0KB. The reason for this is that log(999999)/3 is 1.9999.. which when truncated to an int is 1 so the unit is KB and 999999/1000 is 999.999 which rounds to 1000.0KB. As already stated, the correct result is 1.0M.
You can see that the problem is the interaction between computing the exponent as an int and the rounding applied to the scaled value. The fix suggested is to round the exponent up when the value would be rounded up to 1000:
Another possible solution is to check that the log of the proposed rounded value is less than 3 and increment exp if it is.
There are some other problems with the calculation, but they are all of the same subtle sort. The problems come down to the fact that a Long int has more digits of precision than a double. You can read the author's blog post to investigate them.
What all this proves is that floating-point, and computer math in general, is difficult and this sort of error is very easy to make.
Is it a serous error? Not really, given that a human wouldn't be misled by the result presented. However, imagine that the data was being sent to some industrial device - it might well malfunction. A test to make sure that the data was in the correct format would be a good idea.
What this is not is a huge failure of the programming community to spot a glaring bug. What it does prove is that we are too willing to accept code that seems to work from Stack Overflow without testing it.
or email your comment to: firstname.lastname@example.org
|Last Updated ( Saturday, 14 December 2019 )|