Ask for good ideas about handling floating point number!

iuhytvYUTCU

Member
Join Date
Jun 2018
Location
Shanghai
Posts
28
We have AOIs for projects, which handle material dosing (by hand or by pipes and pumps), obviously they have comparison between setpoint and actual dosed amount, to ensure dosed amount is within range, not too little nor too much. And obviously they handle floating point numbers as they process quantity, and floating point numbers just have their problems regarding accuracy, which results in headache.

For example if opeator is to dose 0.016 kg of material, and range is +-0.001 kg, which means lower threshold is 0.015 kg, but actually in PLC (AB CLX in this matter) after SUB is scanned, the outcome is 0.015000001, it is obviously greater than 0.015, so if operator scans a package of right 0.015 kg, system will not let the dosing pass.

So guys, when dealing with floating point numbers, what is good practice to your experiences??
 
Comparing for exact equality is not advised when using floating point numbers.
From our user manual:

Analog equal difference

This value is the maximum difference between two floating point values and to be "considered"
equal.

Floating point numbers are represented in binary fractions and therefore are always an
approximation of a decimal fraction.
That is why occasionally you see a value like 1.980000000001 for something that you would expect
to have only a few decimal places of precision. When comparing two floating point values, the
comparison should be on how close the two values are to each other rather than testing for
equality.

AED = 0.001 (default)
Equal = ((a - b) <= AED)
 
The tiny difference between 0.015 and 0.015000001 is not significant for the comparison of the weight.
Measuring errors will have greater significance. For example if the full scale is 1 kg, and the accuracy is 0.01% (which is very fine), the weighing error will be +/- 0.0001 kg, which will be more significant than the floating point precision.

So what I am saying, the problem you describe is a non-issue.
 
Last edited:
This is a great site to help understand how computers (and PLCs) store and interpret floating point numbers.

https://www.h-schmidt.net/FloatConverter/IEEE754.html

If you do a lot of comparisons I would write a function that takes in the actual value, the set point and the tolerance and returns a bool for in range. As mentioned above, just make sure you are not looking for an exact match to a float. Use the comparison operators <, <=, >, >=.
 
depending on precision, with most only looking to a 2 or 3 point precision level, a lot of times i will multiply/divide the floating point into and out of integers. that way never having to worry about any floating point math/comparison issues.
 
This is a difference of a difference (non-)issue. IEEE-754 floating-point representation cannot represent any of the rational numbers 0.016, 0.015, and 0.001 exactly. It loses (cannot represent) digits (bits, actually) past ~6-7 decimal places to the right of the first non-zero decimal digit.

Here is a demo of the (non-)problem:

$ python -c "import numpy ; print('{0:.20f} {1:.20f}'.format(numpy.float32(0.015), numpy.float32(0.016)-numpy.float32(0.001)))"

0.01499999966472387314 0.01500000059604644775


Here is an idea for a possible workaround (N.B. the digits in bold blue):

python -c "import numpy ; print('{0:.20f} {1:.20f}'.format(numpy.float32(0.015), numpy.float32(0.016)-numpy.float32(0.001000001)))"

0.01499999966472387314 0.01499999966472387314


The exact extra blue digits to use will depend on the magnitude of the scanned value and require some extra research.

Here is something that suggests another approach:

$ python -c "import numpy ; print('{0:.20f} {1:.20f}'.format( numpy.float32(0.015),(numpy.float32(0.016) - numpy.float32(0.001))-( numpy.float32(0.016)/numpy.float32(16777216))))"

0.01499999966472387314 0.01499999966472387314


That does everything in floating-point; since 0.001 is the resolution of all numbers, multiplying the floating point values by 1000 with rounding to integer values, and then comparing the integers (15 vs. [16-1]) would be another approach.

P.S. it is possible the 16777216 should be 8388608; the difference between the two should be a non-issue.

-
 
Last edited:
Comparing for exact equality is not advised when using floating point numbers.
From our user manual:
This is indeed an idea, but the nature of comparison need just that threshold to work. If to consider the result to be true (aka. within range) as long as the bias is small enough, isn't it violating the nature rule of comparison, especially when there's really a small bias beyond range?
 
...isn't it violating the nature rule of comparison, especially when there's really a small bias beyond range?


If you think it is true, switch to a fixed point decimal type, if supported on the selected platform/language. The type is sometimes called "currency".
 
The tiny difference between 0.015 and 0.015000001 is not significant for the comparison of the weight.
Measuring errors will have greater significance. For example if the full scale is 1 kg, and the accuracy is 0.01% (which is very fine), the weighing error will be +/- 0.0001 kg, which will be more significant than the floating point precision.

So what I am saying, the problem you describe is a non-issue.
Yeah I know that small difference is actually non-problematic, but math is still math, and PLC knows nothing more than numbers bigger or smaller, bits opened or closed. And to compare numbers so that program gets to know how dosing result is going, is not just how we program logic from the first day, but also nature requirement of industry operation. So at the end of the day, we still need to overcome this in a proper way.
 
If you think it is true, switch to a fixed point decimal type, if supported on the selected platform/language. The type is sometimes called "currency".
I know in something like C# programming and SQL languages, there's decimal datatype available to store float in a accurate way, but unfortunately the example is on AB CLX which leaves us without an option...
 
depending on precision, with most only looking to a 2 or 3 point precision level, a lot of times i will multiply/divide the floating point into and out of integers. that way never having to worry about any floating point math/comparison issues.
Plz kindly instruct me how to ignore that possible bias at the far end of the decimal part...
 
I use DINT's.


Multiply the floating point value by a set value to truncate decimal places.


I heating tanks it is common to read the thermocouple/RTD card X10 so 125.0° reads 1250 and use that.
For conveyor speeds I multiply the PV by 100 usually, and the SP too. Dealing with a floating point number down to 7 decimal places is problematic and unless you are aiming a rocket at another planet that resolution isn't needed. (If you are aiming a rocket and the planet just happens to be TorPoul please let me hitch a ride home)
 
Last edited:
This is a great site to help understand how computers (and PLCs) store and interpret floating point numbers.

https://www.h-schmidt.net/FloatConverter/IEEE754.html

If you do a lot of comparisons I would write a function that takes in the actual value, the set point and the tolerance and returns a bool for in range. As mentioned above, just make sure you are not looking for an exact match to a float. Use the comparison operators <, <=, >, >=.
I got to know the nature of floating point store mechianism not far ago, anyway have to overcome it...

Speaking of the term 'comparison' itself, from the looking of it, it is not finding an exact match of two REALs, but it actually is. You can tell from my example, to calculate lower threshold I have to subtract an amount of tolerance from setpoint. So it's inevitable an exact number appears in the PLC data area, and then is stored in an approxiamtion form.
 
This is a difference of a difference (non-)issue. IEEE-754 floating-point representation cannot represent any of the rational numbers 0.016, 0.015, and 0.001 exactly. It loses (cannot represent) digits (bits, actually) past ~6-7 decimal places to the right of the first non-zero decimal digit.

Here is a demo of the (non-)problem:

$ python -c "import numpy ; print('{0:.20f} {1:.20f}'.format(numpy.float32(0.015), numpy.float32(0.016)-numpy.float32(0.001)))"

0.01499999966472387314 0.01500000059604644775


Here is an idea for a possible workaround (N.B. the digits in bold blue):

python -c "import numpy ; print('{0:.20f} {1:.20f}'.format(numpy.float32(0.015), numpy.float32(0.016)-numpy.float32(0.001000001)))"

0.01499999966472387314 0.01499999966472387314


The exact extra blue digits to use will depend on the magnitude of the scanned value and require some extra research.

Here is something that suggests another approach:

$ python -c "import numpy ; print('{0:.20f} {1:.20f}'.format( numpy.float32(0.015),(numpy.float32(0.016) - numpy.float32(0.001))-( numpy.float32(0.016)/numpy.float32(16777216))))"

0.01499999966472387314 0.01499999966472387314


That does everything in floating-point; since 0.001 is the resolution of all numbers, multiplying the floating point values by 1000 with rounding to integer values, and then comparing the integers (15 vs. [16-1]) would be another approach.

P.S. it is possible the 16777216 should be 8388608; the difference between the two should be a non-issue.

-
WOW your post suggested an interesting knowledge, is it true that 0.001 is the resolution of all numbers and multiplying by 1000 will do the magic?
 

Similar Topics

I have a program that I've used 100 times. SQO settings: File N7:0, Mask 0FFFFh, Dest B3:1, Control R6:0, Length 8, Pos 2. Length & Position...
Replies
48
Views
952
We are to develop a first application in Codesys. It will contain motion (Softmotion) with drives on Ethercat (CSP mode). Off course there will be...
Replies
2
Views
909
Hi. Rockwell learning curve 132-1b. I was having trouble to change IP address on a EN2TR. Finally found out that I need to change the IP...
Replies
1
Views
747
Hi guys.. I am using Vijeo Citect 7.4.. I am doing a function inside a function.. What I want to do is I want to put a function to sleep but want...
Replies
7
Views
1,437
I am working with a 1768-ENBT and I was able to connect to it through my laptop. My laptop IP is 192.168.1.10 subnet 255.255.255.0 and the PLC...
Replies
12
Views
1,566
Back
Top Bottom