3

I noticed that according to Lua, 2 ~= math.sqrt(2) ^ 2

print(2 == math.sqrt(2) ^ 2) --> false
print(2, math.sqrt(2) ^ 2) --> 2  2

Why is this happening?

Yu Hao
  • 119,891
  • 44
  • 235
  • 294
David
  • 693
  • 1
  • 7
  • 20
  • 1
    Most likely floating point imprecision. – Thilo Nov 20 '14 at 05:47
  • 2
    possible duplicate of [Why is Lua arithmetic is not equal to itself?](http://stackoverflow.com/questions/6366954/why-is-lua-arithmetic-is-not-equal-to-itself) – hjpotter92 Nov 20 '14 at 05:58
  • possible duplicate of [What is a simple example of floating point/rounding error?](http://stackoverflow.com/questions/249467/what-is-a-simple-example-of-floating-point-rounding-error) – andand Nov 21 '14 at 02:50
  • I would not consider this to be an exact duplicate of the linked questions and would suggest to leave this question open. As I explain in my answer below, there is a specific principle behind the observation made in the question. – njuffa Nov 21 '14 at 05:38

3 Answers3

9

Most floating point numbers can't be stored precisely in Lua's number type (C's double by default). math.sqrt(2) is one of them.

If you try:

print(2 - math.sqrt(2) ^ 2)

Output: -4.4408920985006e-016 which is a very small number, but still, making the two numbers not exactly equivalent.


This floating point precision problem exists not only in Lua, but also in many other languages. As @Thilo comments, you can use a small "delta" when comparing for equality in practice. You might be interested in: C FAQ: What's a good way to check for ``close enough'' floating-point equality?.

Yu Hao
  • 119,891
  • 44
  • 235
  • 294
  • The way to work around this is to allow a small "delta" when comparing for equality. Choosing how big that delta has to be is probably application-specific. – Thilo Nov 20 '14 at 05:50
  • The floating point number is why the values sqrt(2)^2 doesn't equal 2, but the fact that when you print it says 2 is due to the imprecision of the tostring method. You can print much more accurate numbers such as `tostring(0.000000000000000000001) -> 1e-021` – doog abides Nov 20 '14 at 06:07
  • 1
    @doogabides Sure, if number is `double` in C, Lua uses the format `"%.14g"` to print numbers by default, if I recall correctly. – Yu Hao Nov 20 '14 at 06:17
  • @yu-hao Right, I was just adding to your good answer, since he still may have been confused about the print output with "2 2" – doog abides Nov 20 '14 at 06:19
2

The following reasoning shows that in general it is not possible for sqrt(x)*sqrt(x) == x to hold for all operands in floating-point arithmetic, whether it be binary or decimal, even if the square root operation returns correctly rounded results (as is typically the case on modern computers that are compliant with the IEEE-754 floating-point standard).

In a finite-precision binary floating point representation, each binade (the space between two successive powers of 2) comprises the same count of exactly representable numbers. For IEEE-754 single precision, there are 223 of these machine numbers per binade, for IEEE-754 double precision there are 252 such numbers per binade.

Square root is a contracting operation, in that it maps an input domain of two binades, say [1,4), to a result range of only one binade, say [1,2). So in the case of IEEE-754 double-precision operands, 253 possible function arguments across two binades are mapped to at most 252 different square root results. If we now square the results of the square root operation, we wind up with at most 252 different products spread out over two binades able to represent 253 machine numbers.

Therefore, the equality sqrt(x)*sqrt(x) == x can hold for at most half of the possible floating-point inputs. Experimentally one can show that it holds for exactly half of the inputs from the two binades.

On the other hand, the equality x == sqrt (x * x) does hold in IEEE-754 floating-point arithmetic, provided there is no intermediate overflow or underflow in the computation of the product.

njuffa
  • 23,970
  • 4
  • 78
  • 130
-1

The nature of floating-point arithmetic is very important in general programming environments. Classic C static source code analysis programs (e.g., "lint") will actually give you a warning if you use relational operators on floating-point numbers. As other have said, usa a tolerance in comparisons.

However, the example you chose, √2, is irrational. No calculating number system can hold that number. It can only be exact as a symbolic expression. There are a few symbolic programming systems available: Octave-Symbolic, MathCAD, MATLAB, ... and now Wolfram (I think). They will keep √2 as a expression and evaluate √2 * √2 as exactly 2.

Community
  • 1
  • 1
Tom Blodget
  • 20,260
  • 3
  • 39
  • 72
  • One way you could represent √2 exactly is as an [algebraic number](http://en.wikipedia.org/wiki/Algebraic_number). These are define as the solutions of a polynomial. A rational numbers p/q could be represented as the polynomial `q x-p=0` the solution of which is p/q. The square root of 2 can be represented as the polynomial `x^2-2=0`. Algebraic number have nice properties, you can add, multiply and divide them. – Salix alba Nov 22 '14 at 21:45