TBASIC Floating Point Constants, Variables & Operators
(i-TRiLOGI version 7 only)


The most important capability added to TL7 is the support of floating-point math operations.

It is important to realize that TL7 does not add floating-point capability to those PLCs that do not support it. It is only meant for programming PLCs that already has the firmware to support the floating-point math and variables.  The following table shows the current PLC models and whether they can be programmed with TL6 or TL7:

PLC Model

i-TRiLOGI

1. Nano-10, FMD88-10, FMD1616-10 Version 6 only
2. F2424, F1616-BA and FCPU Version 6 only
3. FP+2424, FP+1616-BA and FP+CPU Version 7 & Version 6

Of course more new PLCs model may be added in future that are not shown in the above table. Note that PLCs that supports floating-point operation will have firmware >= F90.0 whereas PLC that supports only integers will have firmware <= r8x .

1.     Floating Point Number Representation

TL7 uses IEEE, 32-bit Single Precision format to represent all float numbers. For more information on how single precision float are encoded into 32-bit of data, please refer to the following link:

http://en.wikipedia.org/wiki/Single-precision_floating-point_format

However, in-depth knowledge of how float are actually encoded are not required for TL7 users since TL7 automatically handles the floating-point data conversion to and from its binary representation. All you need to know are the range of numbers that an IEEE single precision floating-point number can represent, as follow:

Minimum positive value 1.18 × 10-38
Maximum positive value 3.4 × 10-38
Minimum negative value -3.4 × 10-38
Maximum negative value -1.18 × 10-38
±Zero Yes
± Infinity Yes
NaN (not a number) Yes

Special formats are used to represent special numbers such as zeros (there are positive zero and negative zeros but they compare as equal), infinity and NaN. These are supported by TL7.

Note: Having the basic knowledge of how the float data are actually encoded in 32-bit binary number is useful when you need to transport the numbers to and from external devices via serial or Ethernet communication. TL7 supports special function “Float2Bits(float)” to convert a float into its 32-bit IEEE format and the function “Bits2Float(integer)” to decode a 32-bit IEEE representation (of a single precision float) back into a floating-point number. This makes it very simple to send and retrieve float data via Modbus and Hostlink commands that traditionally support only 16-bit and 32-bit integer data.

2.     Floating Point Constants

Float constants can be entered into TBASIC using the popular floating-point format as shown in the following examples:

Number Format 1 Format 2 Format 3 Format 4
123.4567 123.4567 1.234567E2 1.234567e+02 +1.234567E+02
-0.0004567 -0.0004567 -4.567E-4 -4.567e-04 -4.56700E-04
12345 12345.0 1,2345E4 +1.2345e04 1.2345e+04
0 +0.0 -0.0 - -

It is important to note that if you want to use a whole number as a floating-point number in an expression, you should append it with a decimal point and a 0.  i.e. 123   should be entered as 123.0. The reason being that certain operators such as “/”  (divide by) operate differently on floating-point numbers than that on integers.

 E.g.     A# =  11.0/2.0  =  5.5
          A# = 11/2 = 5.0

In the second expression, 11/2 is treated as an integer divide between two integers 11 and 2 and the result is an integer 5 without any fractional part. When the result is finally assigned to A# it has already lost its fractional part.   But as long as one of the two operands is a float (such as 11.0 or 2.0) the divide operator will perform floating-point division and return a float.  Likewise,          

    A# = 345/0  => Run time error: Divide by Zero 
    A# = 345/0.0 = +Infinity

Special Floating-point Constant

Due to their relatively rare use in control system, TL7 does not create special keywords to represent special float numbers such as +infinity. If you really need to use such special numbers in your program you can use the Bits2Float() function to convert their 32-bit integer representation into these special numbers, as follow:

 + Infinity        E.g.  A# = Bits2Float(&H7F800000)
- Infinity         E.g.  B# = Bits2Float(&HFF800000)
   NaN             E.g.  C# = Bist2Float(&H7FC00000)

TL7 however thus support the keyword NaN (not a number) since this may be used to return to a caller to alert the caller that it has supplied invalid parameters to the function.

3.     Floating Point Variables:

TL7 support the following new Floating-point variables :

Floating-point Variables Type
A# to Z# Global Variables
FP[1] to FP[1000] Global Variables
%[1] to %[9] Local Variables

a) A Global variable means that it is accessible by every custom function in the program. When a custom function changes the data in a global variable the new value is immediately available to all other custom functions.

b)  "Local variable" is a completely new addition to TL7 that allows up to 9 floating-point parameters to be passed to and used within a custom function. This will be described in the next section

4.     Local variables & Function Parameters Passing:

Before TL7, all variables are global in scope, which means all variables are accessible to all custom functions, and that changes to any variable inside a custom function will affect all other custom functions that use the same variable. Since all variables are global their value can be monitored and changed via the online monitoring screen.

TL7 now supports the concept of local variables and parameter passing to and from a custom function to make it simpler to create a library of portable custom functions.

Up to 9 floating-point local variables: %[1] to %[9] are now available to a custom function which are local in scope. Since these are elements of a one-dimensional array they can be easily accessed using their index.

In TL7 you can now call a custom function with label name: "MyFunc" by one of the following methods:

1 CALL MyFunc ' same as TL6
2 FP[1] = MyFunc (p1, p2, p3……p9)
3 D# = MyFunc( ) ' no parameter
4 Y# = Function (CusF#, p1, p2, p3…..p9)

Method 1 is the only method available in TL6 where no parameter is passed to the called function and no parameters are returned. All parameters that MyFunc needs can only be passed via global variables (A to Z, DM[n] and EMINT[n], etc) and what MyFunc need to return to the caller are also passed via global variables. TL7 continues to support this method to maintain compatibility and also for calling functions that do not require parameters passing.

Method 2, 3 are new to TL7 and allows you to call your custom function by its label name as if it is a built-in function and you can pass the parameters p1, p2, p3… etc enclosed between the parentheses. The variables are separated by comma and you can pass from zero up to a maximum of 9 variables to the called function "MyFunc()". When called this way the function is expected to return a data back to the caller which is assigned to a variable (Y# in this example)

Method 4 is also new and allows you to call a function by using the new keyword "FUNCTION" and specify the custom function by its number or its label name as the first parameter. The actual parameters to be passed are contained from second parameter onwards. It is compiled to the same code as Method 2 and 3.

Parameters Passing

The parameters p1 to p9 can only be either integer or float data type. Integer are automatically converted to float when passed to MyFunc() as part of the parameter list.

The parameters that are passed to MyFunc() are accessible by MyFunc() as the local variables %[1] to %[9]. Basically p1 is passed to %[1], p2 is passed to %[2] and so on.

E.g. Y# = MyFunc(0.25, 100, DM[1]/3.5)

When the custom function MyFunc() runs, it will find the following variables already contain the data passed in the parameter list:

%[1] = 0.25; %[2] = 100.0 ; %[3] = result of DM[1]/3.5

In the above examples only 3 parameters are passed. So %[4] to %[9] are not used but are always available to the custom function as local variables.

Your custom function "MyFunc" can use any of these 9 local variables without restriction and changes made to these variables does not affect other custom functions. This is what is meant by "local variable" since the local variables are only valid when the function is called and once the custom function ends these variables will no longer contain valid data.

Needless to say any local variables used in MyFunc that is not passed as a parameter must be initialized with valid values before being used since they may contain stale data resulted from execution of the other custom functions.

Returning Data To Calling Function

As explained above in a statement such as

Y# = MyFunc(p1, p2, p3)

Y# will be assigned a float data returned from MyFunc(). MyFunc will return the data using the following syntax:

RETURN = [data to be returned]

    E.g.    RETURN = %[7]
            RETURN = FP[20] / %[5]

If no valid data need to be returned then a simple RETURN statement suffice but the calling function will receive a stale data that it should discard.

5.     Floating-point Operators:

"Operators" perform mathematical or logical operations on data. TBASIC supports the following integer operators:

i) Assignment Operator ( = ):

    A floating point variable (FP[], A# to Z#, %[1] to %[9]) may be assigned a numeric value or the result of a numeric expression using the assignment operator " = ":

        A# = 1000
        X = H*I+J + len(A$)/FP[5]

ii) Arithmetic Operators:  

Symbol

Operation

Example

+

Addition

A# = B+C+25

-

Subtraction

Z = TIME[3]-10

*

Multiplication

PRINT #1 X*Y

/

Division

X = A/(100+B)

A numeric expression using the above arithmetic operator can include both integers and floating-point numbers. As long as one of the two numbers is a float the integer number will be converted to float and then the floating-point operator will be used and the result is a float. However if both operands of an arithmetic operator are integers then the integer operator will be used and an integer number will be returned.

 

iv) Relational Operators :

Used exclusively for decision making expression in statement such as IF expression THEN ..... and WHILE expression ....

Symbol

Operation

Example

=

Equal To

IF A = 100

<>

Not Equal To

WHILE CTR_PV[0]<> 0

>

Greater Than

IF B > C/(D+10)

<

Less Than

IF TIME[3] < 59

>=

Greater Than or Equal To

WHILE X >= 10

<=

Less Than or Equal To

IF DM[I] <= 5678

AND

Relational AND

IF A# >B# AND C<=D

OR

Relational OR

IF A#<>0.0   OR B# >=1000

The programmer should bear in mind that a decimal floating-point number in a computer is at best an approximation of the real data and not an exact number. Any arithmetic operation carried out on a number could result in rounding or truncation errors of the resulting. So comparison of two numbers using the "Equal" operator may not always work as expected.  E.g.

A# = 0.0
FOR I = 1 to 1000
     A# = A# + 0.1
NEXT

IF A# = 100.0 THEN
    SETLCD 1,1, "True"
ELSE
    SETLCD 1,1, "False"
ENDIF

At first glance you may expect that the result should be "True" since adding 0.1 to A# 100 times should means A# = 100.000 after the program is run? However, when you execute this program you may be surprised that the result is "False". Further examination of the execution result you can see that after adding 0.1 to A# 100 times, A# actually contain the value "99.999", which is quite close to 100.0 but not exactly. The error is due to cumulative truncation errors resulting from floating point addition. Hence you shoudl avoid using the "Equal" operator to compare two floating point numbers directly .

v) Functional Operators :

TL7 added a number of built in functions that takes floating-point parameters and return a floating result. Some examples are shown below:

ARCSIN, COS, EXP, LOG, LOG10, POWER, ...etc.

For detailed explanation of these functions please refer to the TBASIC Keyword Reference

backbutton.gif (507 bytes)  Basic to TBASIC Reference Manual