# Thoughts on float equality in LSL

Please take a moment to consider if this thread is worth bumping.

## Recommended Posts

Another discussion in this section got me wondering about equality operations on floats in lsl.

In c# for example it is advised to avoid using strict equality operators because floats can end up unequal due to precision errors but still relatively close to eachothers (within 0.0001 for example)

I'm now wondering if those recommendations are valid for LSL too.

• 2
##### Share on other sites

I'm sure they are, but a point here is that LSL might not need to go to the number of decimal places that approaches the area of vacillation: for example, since you can only scale an object to a minimum size of 0.01 metres testing for equality is unlikely to be affected, similarly just how fine a precision does on need for a position vector? If you can also only position to +- 1cm then again you're not at the point where a difference in the fifth significant digit is going to be noticeable.

This problem pre-dates c# by several decades, by the way, In the past there were two standard ways of dealing with it, (three if you count turning a blind eye to the problem). Method one is to declare your smallest amount that is to be taken as a difference such as 0.00001 and then taking the absolute value of the difference between two floats and testing for greater than or less than. Method two was to work in fixed precision, say three decimal places, and do integer arithmetic, sticking the decimal point in at moments of display "the output, as the Ita name it".

##### Share on other sites

Coincidentally, I faced this question recently. I'd have to go back and look at the code for details, but I was doing something involving finding the point(s, if any) where a line intersects a circle, and I was trying to test for a special case to avoid division by zero. When I created that special case, though, the denominator that "should" be zero was off by a minuscule floating point error. I remember being kind of amazed that this doesn't come up more often.

• 1
##### Share on other sites

2 hours ago, Profaitchikenz Haiku said:

I'm sure they are, but a point here is that LSL might not need to go to the number of decimal places that approaches the area of vacillation: for example, since you can only scale an object to a minimum size of 0.01 metres testing for equality is unlikely to be affected, similarly just how fine a precision does on need for a position vector?

You need them to be extremely precise, exact in nature, and able to be debugged true to their value. A conditional test needs to succeed as expected, because all logic and action following it depends on that outcome.

##### Share on other sites

10 hours ago, Kyrah Abattoir said:

In c# for example it is advised to avoid using strict equality operators because floats can end up unequal due to precision errors but still relatively close to each others (within 0.0001 for example)

I'm now wondering if those recommendations are valid for LSL too.

With IEEE 754 floating point, which SL (and all modern CPUs) uses, you are guaranteed that all integers with 7 or fewer decimal digits are represented exactly. So, 99 will always be 99, not 98.9997. This does not apply to fractional values. 99.1 may be 99.09997. See this Wikipedia article for the theory.

32-bit floats do have implications in world. It's not really enough precision at high altitudes a few thousand meters up. It can even give trouble near the far corner of a sim, near <256,256>. You lose some precision when you apply a rotation to a vector or rotation, and that error can accumulate. Keyframe animation (llSetKeyframedMotion)  is especially subject to this problem, because each step in the animation has a position and a rotation that is applied to the previous result. Being off by 10cm at the end of keyframe motion is not unusual. I have to check for this in my NPCs.

##### Share on other sites

It may very well be that LSL handles epsilon implicitly. @Rider Linden?

Otherwise, just test for a threshold:

```if ( llFabs(a - b) < tolerance )
// Everything is fine.```
Edited by Wulfie Reanimator
• 1
##### Share on other sites

like animats mentions a IEEE 754 float type is guaranteed to 7 digits of precision

LSL uses binary rounding (the IEEE 754 default method) to truncate float bits to this degree of precision

this happens when a float is cast to a string. So given that this happens then we can cast to string and compare the strings

the example code uses the problem cases from the article that Wulfie linked to

```default
{
state_entry()
{
float f = 0.1;
float sum;
integer i;
for (i = 0; i < 10; ++i)
sum += f;
float product = f * 10.;

integer sumIsOne = (sum == 1.);  // FALSE
integer productIsOne = (product == 1.); // TRUE
integer fx10IsOne = (sum == f * 10.); // FALSE
llOwnerSay(llDumpList2String(["float", sumIsOne, productIsOne, fx10IsOne], " "));

sumIsOne = ((string)(sum) == (string)1.);  // TRUE
productIsOne = ((string)product == (string)1.); // TRUE
fx10IsOne = ((string)sum == (string)(f * 10.)); // TRUE
llOwnerSay(llDumpList2String(["string", sumIsOne, productIsOne, fx10IsOne], " "));

f = llSin(PI);
integer sinpiIsZero = (f == 0.0); // FALSE
llOwnerSay(llDumpList2String(["float", sinpiIsZero], " "));

sinpiIsZero = ((string)f == (string)0.); // TRUE
llOwnerSay(llDumpList2String(["string", sinpiIsZero], " "));
}
}```

##### Share on other sites

After reading the very introductory lines on the Epsilon topic, I doubt it compares a difference and passes. Seeing as when you feed a valid six precision float into a vector, obtain a five precision (that used to be six) from a prims colour, and fail to return true for a difference of 0.000001. @Wulfie Reanimator "When is Orange not Orange" problem, and the failing to have a same band of colour that acts as its own case. Unless I completely misunderstand the point of it.

##### Share on other sites

Just for completeness, the example I was muttering about earlier boils down to this:

```default
{
state_entry()
{
// set up by rotating the prim to 90 degrees in Z
vector fwd = <1,0,0>*llGetRot();
if (fwd.x == 0.0)
llOwnerSay((string)fwd.x+" == 0.0");
else
llOwnerSay((string)fwd.x+" != 0.0");
}
}```

It's not surprising at all, unless one forgets how floating point works.

• 1
##### Share on other sites

We NEED 4-digit precision because of prim drift!

• 1
##### Share on other sites

1 hour ago, Qie Niangao said:

It's not surprising at all, unless one forgets how floating point works.

45 minutes ago, Love Zhaoying said:

We NEED 4-digit precision because of prim drift!

As a side tangent it's a shame we don't have zeropoint shifting like some other places (for rendering)

##### Share on other sites

4 hours ago, NaomiLocket said:

As a side tangent it's a shame we don't have zero point shifting like some other places (for rendering)

We do. Objects in each region are referenced to the region's <0,0,0> corner.

##### Share on other sites

5 hours ago, Love Zhaoying said:

We NEED 4-digit precision because of prim drift!

i would like to be able to set floating decimal point precision in a script

• 1
##### Share on other sites

12 hours ago, animats said:

We do. Objects in each region are referenced to the region's <0,0,0> corner.

No we don't and that is why we don't. The simulators by themselves are a static container with a origin corner that never moves. That is old school and by definition no shift of the zeropoint. In order to zeropoint shift the origin must move figuratively or philosophically speaking. We have global coordinates because when we have contiguous regions we have to be able to know how to draw child regions in reference to the simulator we occupy. Then we have a camera that has a position that moves, as an observer not as an origin.

To zeropoint shift properly the camera would effectively never move, the rest of the world would, in a sense. Eliminating the rending bugs and loss of precision for the depth buffer and high altitudes because all objects have a consistent vanishing margin of error the closer they get to the camera approaching no error at all. Because the camera is no longer an observer (it becomes the origin, clientside; the day we see that happen is the day things are no longer wibbly thousands of meters above the ground level).

ETA: I believe Stationeers implemented or planned to implement zeropoint shifting for the very purpose to handle the very specific problem of the further you travel and the integrity of display. I don't believe they came up with it originally, but learned of it in the course of things. Just as a point of reference. Any simulation and game that has vast distances has to deal with "what to do with it as you approach or exceed the initial play area". The short answer to that problem, is to never exceed it and never have a boundary.

Edited by NaomiLocket
• 1
##### Share on other sites

i remember a long discussion on here a long while ago about zeropoint shifting. It might have been across the street, cant remember now exactly. It was quite a few years ago

basically the avatar is the sim. when so then the world is one continuous region from each avatar sim perspective

the number of avatars that can be seen from each sim is limited only by the client side draw distance capability of the client computer that the avatar sim is being viewed from

• 1
##### Share on other sites

4 minutes ago, Mollymews said:

basically the avatar is the sim.

It is a nice way of putting it, but unless it is the camera specifically at the end of it all, I would still expect issues when camming far from the avatar. The biggest driving point of it is no matter where you cam there is no longer a perceivable error with where the surfaces of prims or the faces that make them are between each other.

##### Share on other sites

yes the camera comes into it as well. Probably best to go with your method. Avatar sim camera is <0, 0, 0> and avatar object is relative to this same as inworld objects

the other big thing is preserving script and object state when a avatar sim is not present in that part of the world, which means object positioning would be on the grid scale to avoid partitioning. On present day client side capabilties then the max. linear size of the grid would be equal to the size of a signed 64-bit float (double). 64-bits on the Z as well.  Which is a pretty big box

edit: took out a sentence which added another topic. Might end up talking about how to design a whole new world otherwise

Edited by Mollymews
##### Share on other sites

15 hours ago, NaomiLocket said:

It is a nice way of putting it, but unless it is the camera specifically at the end of it all, I would still expect issues when camming far from the avatar. The biggest driving point of it is no matter where you cam there is no longer a perceivable error with where the surfaces of prims or the faces that make them are between each other.

Requires additional transform operations I believe.

Maybe once we finally bring avatars tricount under control.

##### Share on other sites

BDC math anyone?

I keep telling people their ARM processors are not suitable for use in industrial and financial systems because they do not have BCD math instructions.  I can drop an old Motorola 68H or 68K in and never miss a penny or a time slice.  Oh well.  Back to integers.

One industrial system I worked on used two integers as a fraction to represent every real world value.  It was weird but they were easy to compare without using floating point math.  It was designed as a replacement for analog process control systems and, as far as I could tell, there were no "microprocessor" devices in it.  The micro-code was all custom written and the processing was performed by a lot of logic gates.  We did things differently back then.  The 'significant digits' were stored as a signed integer and the magnitude was modified by another signed integer.  If you are familiar with 'scientific notation' then you know how this worked.  Would this be too slow to use on contemporary multitasking systems?