Twincat REAL_TO_STRING command 5.1 giving 50.099998

matt_sd

Member
Join Date
Jan 2007
Location
Australia
Posts
96
Hello,

I am doing some real to string conversion to send out on a serial string using the REAL_TO_STRING command.

My problem is that when the REAL is 50.1 the string is then rounded down very slightly to '50.0999984741211'

It is only when the real has a value after the decimal point.

50 is represented as 50.0 in the string.

1) Why is this doing this?
2) How can I stop it? There is a TRUNC instruction to truncate but then I loose everything after the decimal point.

I can't see a round function neither.

Thanks for any help


Matt
 
Last edited:
Hi Matt.

Is the value 50.1 a result from math functions ? If so, the 50.1 you see may be a rounded value whereas the 50.0999984771211 is the true value.

In S7 SCL there is the ROUND instruction, so it should be there in IEC ST too.
You could try
rVALrounded := (DINT_TO_REAL(ROUND(rVAL * 10.0))) / 10.0 ;
 
No ROUND in TwinCat. Use REAL_TO_INT and TRUNC to manipulate the integer and fractional parts of your numbers, convert them to strings and then combine them to produce your required string.

Certain numbers cannot be represented in floating point (e.g. 0.1)
 
But if there is no rounding function, even if he split it into integer and fraction, and if he just strip decimals, it will not be correct.
50.099 with a mask xxxx.y becomes 50.0
50.099 with a mask xxxx.yy becomes 50.09
It sounds odd that there is no rounding function i Twincat.
 
Use trunc to get the integer part.
Subtract the integer part from the original number to get the fractional part, multiply by, say 100 if you want two digits, use trunc again to get the integer part of the fractional part. Finally convert the ints to strings and then combine them with a decimal point.
 
LD[..]

Something like this ?:
Code:
diValFract := TRUNC(rVal - DINT_TO_REAL(TRUNC(rVal)) * 100.0) ;
 = TRUNC((50.0999984741211 - 50.0) * 100.0) 
 = TRUNC(0.0999984741211 * 100.0)
 = TRUNC(9.99984741211)
 = 9
I think with the input value 50.0999984741211 the output value will be 9 (interpreted as "09"). One must add the "0" in front of "9" with some IF THEN code.
Combining this with the integer part still produces 50.09 and not 50.10 that would be the correct value.

Without some kind of rounding function it is simply not possible.

edit: Oh, and by the way, what if you have 50.9999 ? Then the rounding must carry over into the integer part. It is not simple.
 
Last edited:
matt_sd said:
Hello,

I am doing some real to string conversion to send out on a serial string using the REAL_TO_STRING command.

My problem is that when the REAL is 50.1 the string is then rounded down very slightly to '50.0999984741211'

It is only when the real has a value after the decimal point.

50 is represented as 50.0 in the string.

1) Why is this doing this?
2) How can I stop it? There is a TRUNC instruction to truncate but then I loose everything after the decimal point.

I can't see a round function neither.

Thanks for any help


Matt


I've seen that with Contrologix as well. Converting a float to string with loss of resolution. I found by limiting the length of the string after the decimal point lessens the visual distraction of all those extra digits
 
50.9999 would convert to 50.99

Sorry if I misled, but yes, a rounding function is required. You have to use REAL_TO_INT in Twincat for this.
 
Last edited:
Maybe the problem is not so big.
From TwinCat help:
Converting from the variable type REAL or LREAL to a different type:The value will be rounded up or down to the nearest whole number and converted into the new variable type.
Exceptions to this are the variable types STRING, BOOL, REAL and LREAL.
So this should do the trick if I understand correctly:
rVALrounded := (DINT_TO_REAL(REAL_TO_DINT(rVAL * 10.0))) / 10.0 ;

edit: I see that LD[] answered above in the meantime.

edit again: One can see that ROUND in S7 SCL does exactlythe same as REAL_TO_DINT in TwinCat ST. I wonder which one conforms most to IEC61131-3 ?
edit again again: It turns out that there is a REAL_TO_DINT in S7 SCL as well ! And it does excatly the same as ROUND.
 
Last edited:
There isn't an ROUND in the IEC spec. I just looked it up.

As said about the REAL_TO_DINT does rounding.

I bothers me that so many are willing to patch the problem instead of looking for a possible cure. It is important to first ask how the 50.0999999.. was calculated.
Then we can determine the best solution which may be the rounding suggested above or perhaps using better math techniques.

For instance. Adding 0.001 1000 times does not result in 1.0.
Adding 1 1000 times and multiplying by 0.001 does result in 1.0.

The same will go for adding 0.1 1000 times because no matter what you do 0.1 cannot be represented accurately with 32 bit reals. In matt_sd's case it could be a simple problem of adding 0.1 501 times. We don't know but it should be the first thing asked instead of just patching.
 
I would consider downloading the oscat library. (www.oscat.de)
Take a look at the function REAL_TO_STRF(), which converts a real to a fixed length string.
 
Hello all, thanks for the replies.

The real value is not being created from a calculation - I am entering it myself by hand.
I will try your comments and report back shortly.

Thanks

Matt
 
You have FB called FB_FormatString.
You format output like in standardc C example:
%d, %S, %f... etc %f4.1 means 4xplaces for number and .1 for decimal nad it will round. The same syntax is used in Twincat/Codesys Visualization!

fbFormat1(
sFormat:='%S;%S;%S;%S;%4.1f;%4.1f;%4.1f;%4.1f;%6.1f;%4.1f$L' ,
arg1:=F_STRING(File_Date),
arg2:= F_STRING(f_av_Compass) ,
arg3:= F_STRING(f_av_Dm),
arg4:= F_STRING(f_av_Sm) ,
arg5:= F_REAL(rTa) ,
arg6:= F_REAL(rUa),
arg7:= F_REAL(rPa),
arg8:= F_REAL(rRc),
arg9:= F_REAL(rRd),
arg10:= F_REAL(rRi),
bError=> ,
nErrId=> ,
sOut=> );

On sOut you will get formated string as you typed in sFormat.
 

Similar Topics

Hello, First, please excuse my question I am new to Modbus. I have a CX-5140 control unit from Beckhoff and an instrumentation device that...
Replies
3
Views
3,121
Hey all, We're trying to read values from a Beckhoff PLC that is programmed by a third party. We see in the PLC the value...
Replies
1
Views
3,384
Hi, I have used the GETSYSTEMTIME function block and have the time in a dword high and low format. These word doesn't represent the actual time...
Replies
0
Views
6,143
I am using twincat 3 to send some strings over TCP/IP. Where the server is a sensor and my PLC is the client. I noticed that the sensor didnt...
Replies
2
Views
78
I'm trying to control a device via MODBUS RTU and the ModbusRtuMasterV2_PcCOM in Twincat 3. I've configured a device with the right com port and...
Replies
7
Views
222
Back
Top Bottom