Allen Bradley Data Storage

Tstevic

Member
Join Date
Aug 2011
Location
Dayton, Ohio
Posts
14
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.

I have a Compact Logix L33 with RSlogix 5000.

Is there a math error bit anywhere I can monitor to detect the failed instruction?
 
There is no math error. You have simply encountered machine epsilon.

Wikipedia Link

There are methods for working around your problem by utilizing integer math to accumulate the various place values of your totalization, and then re-summing these integer values within a single computation so as to create a floating point totalization number with a minimum of rounding errors.
 
Mr. Bucket,
Thank you for the reply. I had already put yhe work around into place. I understand that technically, the function does not actually cause an 'error' in the CPU and machine code, but I disagree that the add function not completing, or being able to complete, is not an error of the function. Other PLCs have underflow, overflow and carry bits that turn on when a math function is given data it can not handle. I don't understand why the CompactLogix did not. It was simply dumb luck that I saw it at all.
 
Think of 'floating point' a a fixed number of digits number with the decimal point being able to float. When the number is small the decimal point is way over on the left hand side. As the number grows bigger the decimal point starts moving to the right as eventually whole numbers are accumulated. it finally gets large enough that the digits of the small number you add are off the right side of the total. Their addition has no effect on the total. This is true even if you are adding '1' each time. Eventually the number grows large enough that adding '1' makes no difference. It is important to realize that IT IS NOT AN ERROR. It is a limitation of floating point. The limitations of whole number data types are well known, smaller than the least negative and larger than the greatest positive. The limitations of floating point are in between the numbers. It is not an error if you have a large number and attempt to add a vary small number. There are just not enough significant digits to show the result.
 
Think of 'floating point' a a fixed number of digits number with the decimal point being able to float. When the number is small the decimal point is way over on the left hand side. As the number grows bigger the decimal point starts moving to the right as eventually whole numbers are accumulated. it finally gets large enough that the digits of the small number you add are off the right side of the total. Their addition has no effect on the total. This is true even if you are adding '1' each time. Eventually the number grows large enough that adding '1' makes no difference. It is important to realize that IT IS NOT AN ERROR. It is a limitation of floating point. The limitations of whole number data types are well known, smaller than the least negative and larger than the greatest positive. The limitations of floating point are in between the numbers. It is not an error if you have a large number and attempt to add a vary small number. There are just not enough significant digits to show the result.

That is the best and simplest explanation of the problem I have ever read.
 
I'm pretty sure it would be done as an IEEE-32 REAL as most any floating pt. # is. I'm not sure if they processors support IEEE-64 which would probably serve you well. You may want to create your own # system in this case and use the math that causes the most acceptable outcome. Many floating pt.#s lose precision almost immediately (usually imperceptible but nonetheless, repeating fractions and transcendental #s cannot be represented exactly by bit-encoding. BTW, I hate BCD. I like AD PLCs but have grown to despise BCD...inefficient and clumsy as hell to use at times. But, it does make for program obfuscation, if that is ever a goal. LD Kfe8 BIN BCD....haha
 
BTW, I hate BCD. I like AD PLCs but have grown to despise BCD...inefficient and clumsy as hell to use at times. But, it does make for program obfuscation, if that is ever a goal. LD Kfe8 BIN BCD....haha


BCD was far more useful back in the days when panel meters were the norm, rather than HMI displays.
 
Let me add a little hope for those trying to understand floating point and offer a possible solution for this particular application.

First this site has helped me the most to visualize what is going on in floating point storage. Try entering a small decimal number. Note that the representation in many cases is not exact. Any storage has limitations. Try showing the decimal equivalent of 1/3 without using the little 'continue forever' line.

But for the original poster's application ... if a value less than one is being added each time then prepare an additional DINT (preset to zero when appropriate). After each addition of the small value to the floating point tag add the following...

If Floating_Point_Tag >= 1.0 then add 1 to the DINT. Subtract 1.0 (be sure to include the '.0') from the floating point tag. The DINT will preserve the whole number while the floating point tag will preserve the rest. While still not perfect (no computer number system can be absolutely exact) it will help in your application. What you now do with the two separate tags is up to you. If you need more than 2 billion the DINT can hold then you have bigger (literally) problems.
 
Last edited:
I do understand the limitations of floating point math, perhaps not to the degree of some of you guys o_O.

I do, however, contend that 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. I am not an expert in modern CPU design, but all the old ones had such a flag built in for cases when the accumulator could not handle the math. If there is such a flag in CLX, it is well hidden.

I will now have to look at every accumulating math function I ever wrote with AB and try to determine if it will exceed the limitations of the CPU.

lee1968nh: I agree. Sometimes HEX and Binary are very, very helpful.
 
I do, however, contend that 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. I am not an expert in modern CPU design, but all the old ones had such a flag built in for cases when the accumulator could not handle the math. If there is such a flag in CLX, it is well hidden.


Here's the problem. If you got a math error every time a floating point operation rounded off, you'd log so many errors as to render them meaningless.
 
If Floating_Point_Tag >= 1.0 then add 1 to the DINT. Subtract 1.0 (be sure to include the '.0') from the floating point tag. The DINT will preserve the whole number while the floating point tag will preserve the rest. While still not perfect (no computer number system can be absolutely exact) it will help in your application. What you now do with the two separate tags is up to you. If you need more than 2 billion the DINT can hold then you have bigger (literally) problems.


Not really. You simply extend the same concept to subtract 2 billion from your accumulator and increment the value by 1 in a register that has the place value of 2 billion.

To convert back to floating point, simply multiply the value of that register by 2 billion and then add back the value of your "one's place" accumulator.

You might still experience a small rounding error in this final calculation, but the error won't be accumulative, as it would be by continuously adding floating point values.
 
If you take a Numerical Analysis class you will spend a lot of time covering this topic. There are right ways and wrongs ways to do the math. I even have round off errors with my Mathcad that uses 64 bit floats.

Now that it establish that the 'bug' is not a 'bug' but a limitation I have a question that is more to the point. Why are you adding a small number to a big number?
 
If you MOV a Real to a DINT you are expecting the rounding which takes place to achieve an whole number. You do this because a 'limitation' of a DINT is that it doesn't have a fractional component. You, or at least I, do not expect an error to pop up to signal that rounding has taken place.

The equivalent thing is taking place in your repeated adding of a very small value to a growing Real accumulator. The loss of precision as the accumulator grows large, in relation to the size of the value being added, is a natural occurrence and doesn't trigger any error because it isn't one.

Yes, you should review other uses of Real tags as accumulators. You may have other effects of your assumptions waiting.
 
When I first started doing PLC programming, a billion years ago, we had the limitation of doing 4 digit math. It was expected to reset the carry bit just before an add function and to check it just after to make sure that the add function didn't exceed the 4 digit limitation. If it did, we would then take the carry bit and increment a second register to indicate the sum was more that 9999 (or FFFF). I see no problem in treating an 'overflow' bit the same way.

I understand the rounding limitations of floating point numbers. I think it would be a better solution to round up the smaller number in order to fit within the available bits left over from the whole number part of the sum. To do nothing, again IMHO, is a very poor solution.

Mr. Nachtwey,
The reason I am adding a very small number to a very big number is as follows:

I read an analog signal from a belt scale that represents 'Tons Per Hour' of material that is calculated by the scale control unit. I use the GSV values to calculate the number of microseconds that have passed since the last scan of the PLC. I then take those two pieces of information to calculate four values: 1-Tons Per 8 Hour Shift, 2-Tons Per Month 3-Tons Per Year 4-Tons Total Life Time Of The Plant (Note: The plant has only been in operation for about a month)

The Tons Per Shift Works Reasonably Well, but it would never exceed 800 tons (limitation of the mechanics of the plant). I noticed that the Tons Per Month, Tons Per Year and Tons Lifetime had all stopped incrementing a little above 8000.

Within a few days (hopefully) the communications between the PLC and the scale controllers will be operational. At this time, I will be reading the total accumulated tons lifetime value from the scale controller itself so all this is actually a moot point.

Also, yes, I could take the tons per shift that seems to be working reasonable well and calculate the other three values.

The logic that currently exists adds the tons per last scan into a subtotal, then, in one rung of ladder code, compares the subtotal to the value 0.1. If it is less than that, it does nothing. If greater, it adds 0.1 to my totals and subtracts 0.1 from the subtotal. Before enabling the changed code, I set the totals to whole numbers.

This gives me a reasonably good result for the time being. I did notice something odd though. Occasionally, the total is incremented by a value of 0.111 and not 0.1. Odd, but I am not going to chase that one right now.
 
Try using the '1' I suggested or some binary sub-multiple of 1 (I think I just made that up). By that I mean 1/2, 1/4. 1/8 etc. These fractions (and fractional numbers made up a reasonable number of them) are EXACTLY representable in the floating point system. Using that site/calculator I noted you will see that 1/10th is not. That's why you are getting the occasional weird number.
 

Similar Topics

Hi everyone, I have a small project where I need to use plc to get sensor data and log them to an sql server locally or remote. I have found...
Replies
7
Views
2,793
Hello guys, I should communicate an L33ERM with firmware 30 with L35E with firmware 19. The idea is not to modify the firmware, because in L35E...
Replies
2
Views
1,533
Hi, I am working on a project in Digi Module ConnectME9210 and sending data to Allen Bradley PLC (CompactLogix 5370 family). I am not sure which...
Replies
2
Views
3,974
Hello guys, I am new to allen bradley systems, and I have question about access to M0 and M1 data file. I have SLC 5/03 processor, with prosoft...
Replies
2
Views
3,051
Dear friends, I need to access the data of various energy meters connected to Allen Bradley PLC. My general approach to access data from any...
Replies
0
Views
2,417
Back
Top Bottom