0
$\begingroup$

When I run $x^2 - y^2$ with x=8.8888888888 and y=9.9999999999 in python, I get the following result:

>>> 8.8888888888**2 - 9.9999999999**2
-20.9876543205679

However, if I rearrange it to $(x-y)(x+y)$ with the same x and y values, I get:

>>> (8.8888888888 - 9.9999999999) * (8.8888888888 + 9.9999999999)
-20.987654320567895

It seems that the two equations, though logically equivalent, give varying amounts of floating point precision by a difference of 2 digits. What could be causing this?

$\endgroup$
4
$\begingroup$

First of all, the different numbers of digits are misleading. The two numbers store the same amount of precision; Python is just leaving off final zeroes.

However, there is a loss of precision here, and it comes down to the intermediate results.

Floating-point values aren't infinitely precise, and the larger their absolute value, the fewer places they can store after the decimal point. (Hence the name "floating point": one way to think of floating point numbers is that they're a fixed number of digits long, but you can move the decimal point back and forth to represent both really big and really small values.)

When you compute 8.8888888888**2, you're effectively using more of the available bits to store things before the decimal point. So there are fewer left over to store things after the decimal point. It gets less precise.

When you instead compute 8.8888888888 - 9.9999999999, you're not using those extra bits before the decimal point, so they can all be devoted to the part after the decimal point.

(Note: this is an intuitive explanation, not a technical one. The essence is correct, but the details are somewhat handwaved. If you want more technical details, look into how an IEEE float is stored.)

$\endgroup$
  • $\begingroup$ I don't know what the semantics of the ** operator are, but if that's a floating-point-raise-to-the-power-of, x**2 is probably going to be less precise than x*x. $\endgroup$ – Pseudonym Jan 17 at 6:49
  • $\begingroup$ @Pseudonym It's an exponent, yeah, though given that the 2 is a constant I'd be surprised if the compiler didn't optimize that down to a multiplication. $\endgroup$ – Draconis Jan 17 at 6:58
  • $\begingroup$ Any decent library calculating x^y for arbitrary y will have special cases for y = small integer, y = 0.5, y = -1 and possibly others. $\endgroup$ – gnasher729 Sep 14 at 21:17
0
$\begingroup$

You can roughly say that every floating point operation has an error proportional to the size of the result (with the notable exception of subtracting x - y when x/2 ≤ y ≤ 2x).

So in the first case, the errors per operation with $x^2 ≈ 80$, $y^2 ≈ 100$, are (very roughly) x^2 -> 80 eps, y^2 -> 100 eps, x^2 - y^2 = no error, total 180 eps. vs x - y -> no error, x + y ≈ 19 -> 19 eps, (x+y)(x-y) ≈ 21 -> 21 eps, total 40 eps.

This is very simplified, but it shows the principle that by rearranging calculations in a clever way you can vastly reduce floating point errors.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.