WeBWorK Problems

Currency Context

Re: Currency Context

by Davide Cervone -
Number of replies: 0
I agree that that's probably what Perl is trying to do (though it looks more like round-to-odd than round-to-even), but I think the problem really is that the binary representations are not actually equal to the decimal ones, so what you think of as 1.235 is not actually that but something slightly less than that (on the order of 1E-16) and so is not "really" 5 followed by 0's but actually more like 1.2349999999999999999999 and so rounds to 1.23.

In fact, I just did the following: 1.235 - 1.23 and got 0.00499999999999989, not .5, so that confirms it. Similarly, 1.225 - 1.22 yields 0.00500000000000012, so 1.225 rounds up to 1.23. These small errors at the tail of the decimal are due to the fact that the infinite binary expansion has been truncated (or more likely, rounded). For example, the binary expansion for .1 has repeating 1100 digits, giving ...110011001100110011..., so if the cut-off occurs before a zero, as in ..1100110|0110011..., then the resulting binary number is slightly too small, and we have the case like the one in 1.235 (it rounds down because it is slightly below 1.235). On the other hand, if it cuts off before a 1, as in ..11001100|110011..., then the number stored might be rounded up to ..11001101, which is slightly too big. This is like the 1.225, which rounds up, because the internal representation is just a little over 1.225 (by 1.2*10^(-16)).

Numbers stored as IEEE double-precision floating point reals (like the Perl I'm running uses) have 54 binary digits for the mantissa (the constant in front of the 10^(-16)) and 11 for the exponent (yes, that's 65, which I could also explain). So the error should be in the 54th binary "decimal" place, so the error should be on the order or 2^(-54). As a rough estimate of how big that is, we can use the fact that 2^10=1024 is about 1000=10^3, so

2^(-54) = 2^6*2^(-60) = 64*2^(10*-6) = 64*(2^10)^(-6) = 64*(10^3)^(-6) = 64*10^(-18) = 6.4*10^(-17)

which is just about exactly the sized error we see (and since 1024 is a little bigger than 1000, our estimate is a little smaller than the actual error).

Anyway, the reason the rounding doesn't work as expected is that the numbers actually being rounded are in binary not decimal, and so are not exactly what you think they are. The reason you don't see these error when you print the numbers is that the numbers are printed using one or two fewer (decimal) digits than the binary representation actually allows, and the result is rounded for printing, so 1.234999999999999999 becomes 1.235 even though internally it isn't exactly that.

The upshot is, you can't trust printed numbers to display the actual number stored, and the actual number stored may not be the one you entered.


PS, I don't even want to THINK about what banks do.