One thing you should know about numbers in Arma is that they adhere to IEEE floating point standard. Go ahead and look it up on wikipedia for details, but in layman’s terms this means that there is a limit after which the numbers start losing their precision, among other things like -1 x 0 = – 0 (though 0 == – 0 returns true).
Anyway, if you want to display the number and see it with your own eyes you have to convert it to string first. The thing is, the automatic number to string conversion in Arma whether using str command or format is limited to 6 digits and this goes for both, floats and integers. So the smallest number you can display this way is -999999 while the biggest one is 999999. Anything above this threshold starts to get rounded: 9999999 => 1e+007
Because of that, the floats converted to string will drastically reduce precision the greater they are. 9.99999 has 5 digits after floating point while 99999.9 has only 1. Why is this a problem? The position coordinates of objects are in metres and they are floats too. If my X coordinate displays 1234.12, this means I’m one kilometre, two hundred and thirty four metres and twelve centimetres away from the map origin, which is [0,0,0].
In reality my position on the map is much more precise than just 2 digits after floating point. It could be 1234.123456 for what we know. But if I were to store it in a database, because database extension only accepts string, after default number to string conversion and rounding, 1234.12 is what will get stored. If I then want to restore position from the database, I can only restore it to the nearest centimetre. And the further away I’m from map origin the worse displayed precision. SaMatra even made some tests far away from the origin to see how this would affect models:
So here is the challenge, how to convert float to string without losing precision needed for the map placement? We know the floats stored as numbers preserve their precision. To check it I will store my X coordinate in a variable as a number and then subtract a default 6 digit rounded variant from it.
This means that if I add both values together I should theoretically restore my original position with acceptable precision. Let’s check this out:
It’s true! If I manually add both number together I will get 2475.52829102. Let’s do one more check:
It works! I’ve even made a function earlier that would store coordinates in a database as an array of 2 strings, rounded and precision: [“2475.53″,”-0.00170898″] . All you need is to add them together after reading them from database to get your precise coordinate. But then HeliJunkie reminded me that I’m overlooking a very useful in this case % (modulo) command. Let’s see how the same works out with alternative method:
This gives us 2475.52832, which is little bit different from 2475.52829102. Will this be enough?
Success! This also means that lower level of precision in this case is enough and that we can also just store this as one string instead of two with little effort. It’s time to wrap it all up into a nice function:
Let’s run a few tests to ensure this works as intended:
So far so good, we now have a function to preserve float precision and store it in a string for later. Now it is time to construct another function that would convert passed position array to string for the use with database extension. Basically what we need is a string that looks like array, that we can simply call compile later to return the array:
This is what a sample output looks like:
A final test to make sure everything works. This time we measure the distance between 2 positions. If the distance between the original position and stored position is 0 we are spot on.
Sweet! Here you go, an essential set of functions for DB operations. I’m also not quite finished with Arma and numbers. I’m planning at least one more blog post about it, in the meantime…
Enjoy,
KK
EDIT: Decided to optimise KK_fnc_positionToString for speed and make it self-contained. The new variant is about 1.3 times faster:
EDIT2: BUG FIX! Big thanks to Das Attorney for pointing out (below in comments) a bug with negative numbers. All fixed (_arr = toArray str (_this % 1); should be _arr = toArray str abs (_this % 1); of course 🙂 )
EDIT3: BUG FIX! Again, big thanks to Das Attorney for pointing out yet another bug with, abs!!! 🙂 )
EDIT4: Decided to rewrite both functions after some array commands have been expanded to include string functionality. New KK_fnc_positionToString execution time is 0.08ms vs 0.09ms of the old one. Not major, but still:
EDIT5: ACE’s Nouber gave me an idea so I rewrote float to string a little bit and so far it is the fastest:
And here is position function based on the above solution. Use these two functions as they are faster and also do not fail on large numbers when engine starts rounding them: