3

Today morning I found a bug on my Lua Script, wich seem very weird. How can this evaluation fail this way? Examples can be tested in here

First example:

if( math.abs(29.7 - 30) <=  0.3 ) then
  result = 1
else
  result = 0
end
print("result = "..result )
-->> result = 0

Second example:

if( 0.3 <=  0.3 ) then
   result = 1
else
   result = 0
end
  print("result = "..result )
-->> result = 1

Third example

if( math.abs(29.7-30) == 0.3 )then
   print("Lua says: "..math.abs(29.7-30).." == 0.3")
else
   print("Lua says: "..math.abs(29.7-30).." ~= 0.3")
end
-->> Lua says: 0.3 ~= 0.3 WHAT?

I am really confuse, and I would like to understand this to avoid similiar bugs in the future. Thanks

MRodrigues
  • 1,927
  • 1
  • 17
  • 22

2 Answers2

8

You are being hit by the fact that Lua uses (IEEE 754) 64-bit double-precision floating point numbers.

Look at the following examples
> print(0.3 == 0.3)
true
> print(0.3 <= 0.3)
true
> print(0.3 >= 0.3)
true

The actual value of 0.3 in memory is:
> print(string.format("%1.64f",math.abs(-0.3)))
0.2999999999999999888977697537484345957636833190917968750000000000

Now look at you example:
> print(math.abs(29.7-30) == 0.3)
false
> print(math.abs(29.7-30) >= 0.3)
true
> print(math.abs(29.7-30) <= 0.3)
false

The actual value of 29.7-30 is:
> print(string.format("%1.64f",29.7-30))
-0.3000000000000007105427357601001858711242675781250000000000000000

The actual value of math.abs(29.7-30) is:
> print(string.format("%1.64f", math.abs(29.7-30))
0.3000000000000007105427357601001858711242675781250000000000000000

And just for fun the value of math.abs(-0.3) is:
> print(string.format("%1.64f", math.abs(-0.3)))
0.2999999999999999888977697537484345957636833190917968750000000000

There are two solutions to you problem, the first is read What Every Computer Scientist Should Know About Floating-Point Arithmetic, and understand it :-). The second solution is to configure Lua to use another type for numbers, see Values and Types for hints.

Edit I just thought of another way of "solving" the problem, but it is a bit of a hack, and not guarantied to always work. You can use fixed point numbers in lua by first converting the float to a string with a fixed precision.

In your case that would look something like:

a = string.format("%1.1f", math.abs(29.7 - 30))
print(a == "0.3")

or a bit more robust:

a = string.format("%1.1f", math.abs(29.7 - 30))
print(a == string.format("%1.1f", 0.3))

However you must make sure that you use a precision that is both adequate and the same for all you comparisons.

jbr
  • 6,198
  • 3
  • 30
  • 42
  • OH my God. I would have never tought of that. Very nice justification. I got really surprised. Any suggestion for making this work? like this? Comparing to 0.31? – MRodrigues May 02 '13 at 08:26
  • 1
    My best suggestions are in the edit I made, there is really no simple way around this problem except understanding it. – jbr May 02 '13 at 08:32
  • 2
    Note that this is a case where the problem is the test for exact equality. While there are cases where you can expect an exact result from a floating point calculation, this is not one of those cases. The alternative of using an arbitrary precision representation is very expensive computationally, so compromise is required. The cited article explains in depth. – RBerteig May 02 '13 at 09:04
  • Thanks a lot for the tips. I was working on something similiar to solve, but I'm happy I was on the right way. Thanks a lot for the other article very interesting. – MRodrigues May 02 '13 at 12:31
  • `Any suggestion for making this work?` => multiply by 10, convert to integer, work with integers, divide by 10 after calculation. – dualed May 03 '13 at 02:49
  • There are no integers in Lua, so your suggestion will not work in general. It will however work in this case, as long as your results are within certain limits, where the precision is good enough. Try: `print(string.format("%1.64f", 0.0003 * 10000))` and `print(string.format("%1.64f", 0.003 * 1000))`. The lesson is still, you have to understand floats if you don't want to get surprised. – jbr May 03 '13 at 07:36
  • "The second solution is to configure Lua to use another type for numbers" This will fix the problem by not allowing floating point arithmetic at all? – stands2reason Jul 17 '14 at 21:01
0

As we know, float point has a precision problem

Refer: http://lua-users.org/wiki/FloatingPoint

a = 1
if a < 1 then print("<1") end

Will never print "<1". Not unless you actually change a

Linga
  • 10,379
  • 10
  • 52
  • 104