Ask for good ideas about handling floating point number!

When you multiply a floating point by a factor of 10 and store in a DINT or INT, all of the remainder is automatically truncated or dropped. so 0.0015000001 * 10000 into a DINT becomes 15. the remainder is dropped out.
 
Ok so the solution points to using integer actually, I think integer will receive most of the votes now
It isn't a matter of which method is the most popular. The art of engineering lies in the application of the best tool to the task at hand. The "Equal" and "Range" instructions are both viable tools. "Equal" is better suited to integer comparisons than to floating point comparisons. If speed is a factor, integer instructions have faster execution times than floating point. You need to consider all of the pertinent parameters for your application. Pursuit of greater precision quickly reaches a point of diminishing return for the effort expended. There is no exact value for PI.
 
  1. Calculate ratio = 16777215.0 / 16777216.0
  2. Multiply the [lower limit calculated by difference] by ratio to get the actual lower limit i.e. lower_limit = (0.016 - 0.001) * ratio
  3. Divide the [upper limit calculated by sum] by ratio to get the actual lower limit i.e. upper_limit = (0.016 + 0.001) ÷ ratio
Using the calculated lower_limit and upper_limit will solve this difference-of-difference "non-"issue.

TL;DR
The PLC make and model are as yet unknown, but the following example in python should emulate the suggested solution.

>>> import numpy
>>> import struct

>>> ratio = numpy.float32(16777215) / numpy.float32(16777216)

>>> one = numpy.float32(1)

>>> hex(struct.unpack('I',struct.pack('f',one))[0])
'0x3f800000'

>>> hex(struct.unpack('I',struct.pack('f',ratio))[0]) <== Mantissa decreased by one bit
'0x3f7fffff'

>>> hex(struct.unpack('I',struct.pack('f', ratio*ratio ))[0]) <== Mantissa decreased by another bit
'0x3f7ffffe'

>>> hex(struct.unpack('I',struct.pack('f',one/ratio))[0]) <== Mantissa increased by one bit
'0x3f800001'

>>> hex(struct.unpack('I',struct.pack('f',numpy.float32(0.015)))[0])
'0x3c75c28f'

>>> hex(struct.unpack('I',struct.pack('f',numpy.float32(0.016)-numpy.float32(0.001)))[0])
'0x3c75c290'

>>> hex(struct.unpack('I',struct.pack('f', (numpy.float32(0.016)-numpy.float32(0.001)) * ratio ))[0]) <== Multiplying by ratio decreases mantissa by one bit; lower limit is now <= 0.015
'0x3c75c28f'

>>> hex(struct.unpack('I',struct.pack('f',numpy.float32(0.017)))[0])
'0x3c8b4396'

>>> hex(struct.unpack('I',struct.pack('f',numpy.float32(0.016)+numpy.float32(0.001)))[0])
'0x3c8b4396'

>>> hex(struct.unpack('I',struct.pack('f', (numpy.float32(0.016)+numpy.float32(0.001)) / ratio ))[0]) <== Dividing by ratio increases mantissa by one bit; upper limit is now >= 0.017
'0x3c8b4397'


P.S. This is more or less the same as converting to INT or DINT milli-units, as suggested by others; either way will work. This way will take less code and allows using the floating point value to be used as-is when it is compared to the massaged limits. That said, since this all encapsulated in an AOI those are not reasons to choose this path over the 1k/INT/DINT route, a better metric for choosing one over the other is whether the coders and maintainers understand it.

-
 
Last edited:
If speed is a factor, integer instructions have faster execution times than floating point.


This has limited relevance: the only thing being done in integer is the compare, which compare will be no different than the floating-point compare; every other step is a floating-point operation.

That is, unless the entire problem is moved to integer domain from the start i.e. (16-1) <= 15 <= (16+1) and there are no floating-point values involved at all.
 
Last edited:
Yes you are right about that, sorry I am not native English speaker. :unsure:


Please do not apologize for that; your English is far better than my 中文!

I apologize if I offended; I was only trying to emphasize the distinction between precision and accuracy. Also, now that I think about it, while it is the precision limits of floating point that give rise to the problem, it is ultimately the accuracy of floating point that is the problem itself, so perhaps you were correct to use accuracy in the first place.

-
 
Last edited:
is it true that 0.001 is the resolution of all numbers and multiplying by 1000 will do the magic?


Yes, but the real issue then becomes the conversion of the scaled values from floating-point to integer, specifically whether it is done via truncation or rounding.
 
Yes, but the real issue then becomes the conversion of the scaled values from floating-point to integer, specifically whether it is done via truncation or rounding.
I undertand, however I am just trying to compare two numbers in the first place, rather than doing more math in depth, I just care about the relation of the value of them, so the simplest way to compare REALs while not maintaining/converting they is okay
 
Please do not apologize for that; your English is far better than my 中文!

I apologize if I offended; I was only trying to emphasize the distinction between precision and accuracy. Also, now that I think about it, while it is the precision limits of floating point that give rise to the problem, it is ultimately the accuracy of floating point that is the problem itself, so perhaps you were correct to use accuracy in the first place.

-
It is nice that you happen to know some of Chinese, haha

I did not give much attention to which word to use to represent precision, however the fact of precision ultimatly causes accuracy problem in the program, so either way of saying is the same thing
 
  1. Calculate ratio = 16777215.0 / 16777216.0
  2. Multiply the [lower limit calculated by difference] by ratio to get the actual lower limit i.e. lower_limit = (0.016 - 0.001) * ratio
  3. Divide the [upper limit calculated by sum] by ratio to get the actual lower limit i.e. upper_limit = (0.016 + 0.001) ÷ ratio
Using the calculated lower_limit and upper_limit will solve this difference-of-difference "non-"issue.

TL;DR
The PLC make and model are as yet unknown, but the following example in python should emulate the suggested solution.

>>> import numpy
>>> import struct

>>> ratio = numpy.float32(16777215) / numpy.float32(16777216)

>>> one = numpy.float32(1)

>>> hex(struct.unpack('I',struct.pack('f',one))[0])
'0x3f800000'

>>> hex(struct.unpack('I',struct.pack('f',ratio))[0]) <== Mantissa decreased by one bit
'0x3f7fffff'

>>> hex(struct.unpack('I',struct.pack('f', ratio*ratio ))[0]) <== Mantissa decreased by another bit
'0x3f7ffffe'

>>> hex(struct.unpack('I',struct.pack('f',one/ratio))[0]) <== Mantissa increased by one bit
'0x3f800001'

>>> hex(struct.unpack('I',struct.pack('f',numpy.float32(0.015)))[0])
'0x3c75c28f'

>>> hex(struct.unpack('I',struct.pack('f',numpy.float32(0.016)-numpy.float32(0.001)))[0])
'0x3c75c290'

>>> hex(struct.unpack('I',struct.pack('f', (numpy.float32(0.016)-numpy.float32(0.001)) * ratio ))[0]) <== Multiplying by ratio decreases mantissa by one bit; lower limit is now <= 0.015
'0x3c75c28f'

>>> hex(struct.unpack('I',struct.pack('f',numpy.float32(0.017)))[0])
'0x3c8b4396'

>>> hex(struct.unpack('I',struct.pack('f',numpy.float32(0.016)+numpy.float32(0.001)))[0])
'0x3c8b4396'

>>> hex(struct.unpack('I',struct.pack('f', (numpy.float32(0.016)+numpy.float32(0.001)) / ratio ))[0]) <== Dividing by ratio increases mantissa by one bit; upper limit is now >= 0.017
'0x3c8b4397'


P.S. This is more or less the same as converting to INT or DINT milli-units, as suggested by others; either way will work. This way will take less code and allows using the floating point value to be used as-is when it is compared to the massaged limits. That said, since this all encapsulated in an AOI those are not reasons to choose this path over the 1k/INT/DINT route, a better metric for choosing one over the other is whether the coders and maintainers understand it.

-
Looks like I will take some time to digest your post...

BTW the PLC platform is AB CLX (rev 30), single-precision floating point REAL datatype is used
 
I deal with international salespeople and engineers that always apologize for their English and think they are terrible. I point out that they speak English better than half the people I know born here.
It may still be some hard-to-do to find a person who's fluent in written and oral (just refer to China, don't know much situation of other regions), but it depends, case by case and people by people. Able to communicate inter-language is okay to me, but people tend to wish they could do better, that's also the fact
 
Last edited:
BTW the PLC platform is AB CLX (rev 30), single-precision floating point REAL datatype is used


Inputs: target_value (REAL, e.g. 0.016); tolerance (REAL, e.g. 0.001)

Outputs: lower_limit (REAL, e.g. ~0.015); upper_limit (REAL, e.g. ~0.017)

AOI Code, to set limits when target_value and tolerance change:

SUB target_value tolerance lower_limit MUL lower_limit 16777215.0 lower_limit DIV lower_limit 16777216.0 lower_limit

ADD target_value tolerance upper_limit MUL upper_limit 16777216.0 upper_limit DIV upper_limit 16777215.0 upper_limit


Comparison code:
LIM lower_limit scanned_value upper_limit OTE scanned_value_is_in_range
N.B. assumes scanned value and limits are positive
 
Last edited:

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
961
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
915
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
2
Views
776
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,439
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,574
Back
Top Bottom