Too REAL to ADD up?
Tstevic said:
Does anyone know the binary structure AB uses to store a float data type? For example is the number 16 stored as 00010110 (BCD) or 0001000 (Hex). The reason I am asking is that I have a piece of code that adds a very small number such as 0.0123456 -4 to an accumulating value. The add instruction basically stopped working after the value rose above 8000. I am thinking that because 8000 is 1000000000000, the smaller addend the would have violated the 32 bit size of the data word...
You should not be using REAL data types for a totalizer application, especially where the sum total can reach a very large number, and you're adding fractional values to it. Floating point's inherent inaccuracy lies in the fact that they must be stored in the processor in binary format. The Logix CPUs uses the IEEE 754 single precision floating point standard, using a 32 bit address to store the float. The first 23 bits hold the mantissa (fractional bits), the next 8 bits hold the exponent, and the last holds the sign bit. As Bernie pointed out, not all decimal values can be represented in binary format accurately, so some loss in precision occurs. This loss happens when a non representable value is written and converted to the 23 bit mantissa for a REAL data type. So before you even use the value in an arithmetic instruction you have lost precision.
This article, and the articles linked at the bottom of it, covers most, if not all, of what has been asked and discussed here thus far, including Rockwell's method for storing floats in binary format...
59372 - Why is my Real (Floating Point) number wrong? (a non-technical explanation)
Access Level: TechConnect
This article (also the last link on the above page) is Rockwell's most accurate method of totalizing using an array of DINTs.
The attached example program requires RSLogix 5000 v16 using an Edition that supports the ControlLogix family.
57186 - Accumulator / Totalizer that Maintains Absolute Accuracy
Access Level: TechConnect
Tstevic said:
...Is there a math error bit anywhere I can monitor to detect the failed instruction?...
The instruction itself is not failing, it adds the two values every time. The float is limited to 6 significant digits of precision. You are adding small fractional values to the running total. Once that total has reached, or passed a high enough value that the 6 significant digits are no longer being written to, it will appear as though it's stuck at that value. However, it's not stuck, it just does not have enough significant digits to display the smaller fractional portion, so it will keep dropping the rest of the fraction being added.
In your example,
ADD 8000.(somefractionalvalue) + 0.0123456e-4
Which is the same as 8000.(somefractionalvalue) + 0.00000123456
It's not the fact that the total has reached the whole number 8000, it's that it has reached a fractional value which can no longer write to the 6 significant digits:
8000.00(restoffractionalvalue)
___
0.00000123456
+
------------------
8000.00 <<< only the 6 significant digits are represented
Here the 6 significant digits of precision are not being written to any more, except for the zeros that are continuously being overwritten with more zeros 800
0.00. So the instruction will keep adding and rounding down to the 6 digits, adding and rounding down, etc. This is a rounding error, but not a major or minor error as far as the controller is concerned. So what happened when the total got to a value where it could no longer display the least significant digits?
It started to carry over...
Tstevic said:
...Other PLCs have underflow, overflow and carry bits that turn on when a math function is given data it can not handle...if I have a float (or DINT for that matter) of 99999999 and I add 1 to it, the result should not be 99999999. It should be, IMHO, 00000000 + a carry or overflow flag...If there is such a flag in CLX, it is well hidden.
So where and how can you handle the carry over?
For a SINT, INT, or DINT, if a value is written that results in a carry over, a Carry Flag "
S:C" is set. This Flag is a theoretical extra bit at the end of the SINT, INT, or DINT that holds a "1". You then have to use it, or loose it.
Attached is a small description of the Carry Flag and some examples of how to use it to increment, decrement, etc.
So to recap...
There are two problems with using REAL data type.
1. If a non representable decimal value is written to the 32 bit address, it is converted to the 23 bit mantissa format and precision will be lost.
2. If repetitively adding a fractional value to a larger value, the exponent value will grow and the fractional value will move nearer to zero. As it does, the rounding errors grow exponentially, eventually "freezing" the value.
Use DINTs!
Regards,
George