This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
Anavrins's profile picture

[1.63][SMP/SSP] Floating point error with setCursorPos

Started by Anavrins, 30 July 2014 - 04:11 AM
Anavrins #1
Posted 30 July 2014 - 06:11 AM
VERSION:
ComputerCraft 1.63, singleplayer world and multiplayer world (vanilla, mcpc+)
DESCRIPTION:
Idk if it should be called that way, but there seems to be a floating point error with the setCursorPos function
REPRODUCTION STEPS:
This code

term.clear()
term.setCursorPos(1,1)

for i = 1, 4, 0.2 do
  local x, y = term.getCursorPos()
  term.setCursorPos(i, y)
  print(i)
end
Should output something like
Spoiler

1
1.2
1.4
1.6
1.8
 2.0
 2.2
 2.4
 2.6
 2.8
  3.0
  3.2
  3.4
  3.6
  3.8
But yet, it outputs this
Spoiler

1
1.2
1.4
1.6
1.8
2.0 // This is not on the second column
 2.2
 2.4
 2.6
 2.8
  3.0
  3.2
  3.4
  3.6
  3.8
Edited on 30 July 2014 - 05:49 AM
flaghacker #2
Posted 30 July 2014 - 07:10 AM
I think you made a tiny mistake, in you screenshot the 3.0 is correct, but in your spoiler it is not.
Lyqyd #3
Posted 30 July 2014 - 03:29 PM
How does it behave on a normal computer?
Sebra #4
Posted 30 July 2014 - 03:39 PM
As I understand computer can remember exactly 1, 2, 4, but not 0.2 .
It seems 0.2 in float is slightly less than 0.2. Five times added difference become five times more. So 1+0.2+0.2+0.2+0.2+0.2 < 2 and was truncated to 1.
But I do not see why 3.0 is in the right place.
theoriginalbit #5
Posted 30 July 2014 - 04:23 PM
This is an artefact caused by LuaJ1 and- well- Java.

The first thing to understand is LuaJ uses Doubles to represent any Lua number. The second thing to understand is that in ComputerCraft these doubles are cast to an integer when used for terminal operations; casting from a floating-point value (double or float) to an int in Java will always result in a math.floor being performed, that is 1.9 will become 1, not 2. Lastly as Sebra kind-of stated, floating-point values don't have fantastic precision.

Knowing all of this take the following Java code

for (double i = 1d; i < 4d; i += 0.2d) {
  System.out.println(i);
}

the above will output the following to the console

1.0
1.2
1.4
1.5999999999999999
1.7999999999999998
1.9999999999999998
2.1999999999999997
2.4
2.6
2.8000000000000003
3.0000000000000004
3.2000000000000006
3.400000000000001
3.600000000000001
3.800000000000001

given the above example you can clearly see the artefact.
The only thing that can be done here to fix this Java-side is by performing a round before casting, something which you could also perform Lua-side as a fix in your own code.


local function round( num )
  if num >= 0 then
	return math.floor( num + 0.5 )
  end
  return math.ceil( num - 0.5 )
end

EDIT: Actually even that wouldn't work, 'cause then anything above (and including) 1.5 would appear on the second line, which isn't what you expect, therefore there isn't actually a fix for this, other than, well, not using floats when trying to deal with something that requires integer precision.

1 LuaJ is the Java implementation of Lua that ComputerCraft uses.
Edited on 30 July 2014 - 02:29 PM
Sebra #6
Posted 30 July 2014 - 08:58 PM
Hm. Thanks.
If we thinks a little more, we will see 0.2 in double becomes slightly more than 0.2 when added to 2. The reason should be the other point of roundation (may be wrong word as I do not know right in english). Two is longer than one. Next situation change can be around four.
Funny math ;)/>
MatthewC529 #7
Posted 01 August 2014 - 09:42 AM
A possibility to fix this is something that is done in some Java libraries like LibGDX, they have IEEE754 (Floating Point Numbers) utilities where it checks if a number is within a given error, this is tweaked by application. For instance the error could be 0.000001 or something like that for floats. Since it is double this would require a lot more precision but you can alter it to your application's needs.

Java Side this could be:


public boolean isEqual(double a, double B)/>{
return Math.abs(a-B)/> <= ROUNDING_ERROR;
}

Lua Side this could be


function isEqual(a, B)/>
return math.abs(a-B)/> <= ROUND_ERROR
end

Though I am assuming this is a problem with the actual Terminal display in ComputerCraft as a Java Rounding Error and not LuaJ itself.