Applies To: CitectSCADA 3.xx, 4.xx, 5.xx, 6.xx, 7.xx CitectHMI 3.xx, 4.xx, 5.xx, 6.xx, 7.xx

 Summary: It is often necessary to reduce the number of decimal places or significant digits in a value. This is done automatically (implicitly) when copying the value of a REAL tag into an INT tag. It can also be done explicitly using built-in functions like Round(). However, there are multiple methods for choosing when to round a value up or down. The method chosen and the type of data it is used on will determine whether the results, on average, will be close to the original value. For example, if values often end with .5, always rounding them up to the next integer and then adding them together will result in a much higher total than expected.   Following are common methods of rounding. Cicode does some of these out-of-the-box, and others can be accomplished with the Cicode functions attached to this article.

Solution:

Rounding Down

Rounding down symmetrically rounds all numbers toward 0. This simply drops (truncates) the decimal places. Use the Fix() and RoundDown() functions (attached to this article). The CSV_Math_RoundDown() and CSV_Math_Truncate functions in the CSV_Include project do the same thing but do not work correctly in Citect 5.40 through 7.10 Service Pack 1, and they use inefficient string conversions that take about 3x as long to execute.

Rounding down asymmetrically returns the highest integer less than or equal to the value. It is the same as truncation for positive numbers, but for negative numbers it returns 1 less. Use the attached Floor() function.

Rounding Up

Rounding up symmetrically rounds all numbers away from 0. Use the attached RoundUp() function. Rounding up asymmetrically returns the lowest integer greater than or equal to the value. Use attached Ceiling() function.

Arithmetic Rounding

The standard rounding method we’re taught in school is to round to the nearest whole number. So, decimals .5 and higher round up to the next whole number (away from 0) and decimal places less than .5 round down (toward 0). This is symmetric arithmetic rounding. Asymmetric rounding rounds -.5 toward 0 instead of -1. The built-in Round() function does arithmetic rounding for positive numbers, but simply truncates the decimals for negative numbers. The RealToStr() function and numeric display graphic objects use symmetric arithmetic rounding but incorrectly return -0 for values between 0 and -0.5. Use the attached RealToInt() function to correctly round both positive and negative numbers using symmetric arithmetic rounding. This is done automatically when converting a floating point (REAL) value to an integer. For example:

INT nValue;

nValue = 1.5; 'Sets nValue to 2

Banker’s Rounding

This is similar to Arithmetic rounding except the decimal .5 is rounded to the nearest even number to account for the bias caused by always rounding .5 up. This is useful if many of the values being rounded will have the decimal .5. Use the attached RoundB() function.

Dithering

Dithering can be used to randomly round a number up or down, weighted by the decimal places. For example, 1.9 would have a 90% chance of rounding up to 2 and 10% chance of rounding down to 1. If you dither the same value multiple times and average the results, it will be close to the original value. This can be used for signals such as audio that would sound distorted if the value was always rounded the same way, or even randomly. Use the attached Dither() function.

Other Rounding

To eliminate the bias caused by other rounding methods, you can randomly decide whether to round .5 up or down each time. Or, alternate between rounding .5 up and down each time. With either method, you may get different results each time you round the same number. Use the attached RoundRand() and RoundAlt() functions, respectively.

The attached RoundNear() function rounds to the nearest multiple of the specified number It uses Banker's Rounding to determine which multiple is nearest but could be modified to use any of the other rounding types.

Rounding Results
The following table shows the effects of the different rounding methods on a set of values.

```
Value Fmt RealToStr Round RealToInt Fix Down Up Floor Ceil Bank Arith Arith-As Rand Altern Dither
```
``` 2.6   3	 3	3	 3	2	2   3   2	 3	3	3	 3	3	 3	 2/3
```
``` 2.5   3	 3	3	 3	2	2   3   2	 3	2	3	 3	 2/3   2/3	2/3
```
``` 2.4   2	 2	2	 2	2	2   3   2	 3	2	2	 2	2	 2	 2/3
```
``` 1.6   2	 2	2	 2	1	1   2   1	 2	2	2	 2	2	 2	 1/2
```
``` 1.5   2	 2	2	 2	1	1   2   1	 2	2	2	 2	 1/2   1/2	1/2
```
``` 1.4   1	 1	1	 1	1	1   2   1	 2	1	1	 1	1	 1	 1/2
```
``` 0.6   1	 1	1	 1	0	0   1   0	 1	1	1	 1	1	 1	 0/1
```
``` 0.5   1	 1	1	 1	0	0   1   0	 1	0	1	 1	 0/1   0/1	0/1
```
``` 0.4  -0	-0	0	 0	0	0   1   0	 1	0	0	 0	0	 0	 0/1
```
``` 0	-0	-0	0	 0	0	0   0   0	 0	0	0	 0	0	 0	0
```
```-0.4   0	 0	0	 0	0	0  -1  -1	 0	0	0	 0	0	 0	 0/-1
```
```-0.5  -1	-1	0	-1	0	0  -1  -1	 0	0   -1	 0	0/-1   0/-1   0/-1
```
```-0.6  -1	-1	0	-1	0	0  -1  -1	 0   -1   -1	-1	 -1	-1	 0/-1
```
```-1.4  -1	-1	 -1	-1	 -1   -1  -2  -2	-1   -1   -1	-1	 -1	-1	-1/-2
```
```-1.5  -2	-2	 -1	-2	 -1   -1  -2  -2	-1   -2   -2	-1   -1/-2  -1/-2  -1/-2
```
```-1.6  -2	-2	 -1	-2	 -1   -1  -2  -2	-1   -2   -2	-2	 -2	-2	-1/-2
```
```-2.4  -2	-2	 -2	-2	 -2   -2  -3  -3	-2   -2   -2	-2	 -2	-2	-2/-3
```
```-2.5  -3	-3	 -2	-3	 -2   -2  -3  -3	-2   -2   -3	-2   -2/-3  -2/-3  -2/-3
```
```-2.6  -3	-3	 -2	-3	 -2   -2  -3  -3	-2   -3   -3	-3	 -3	-3	-2/-3
```

1. Fmt refers to the built in format operator ‘:’ (e.g. Tag1:#.###) or the format applied by a numeric display object.
2. RealToStr() and Round() are Built-in Cicode functions
3. Two values separated by a slash means either value may be returned.

Using the Cicode Functions

All the attached functions accept a REAL value and return a REAL value (except RealToInt() which returns an INT). This allows them to return values outside the range of a long integer as well as numbers rounded to a certain number of decimal places. To specify the number of decimal places, pass it as the second argument to the function. To round off digits to the left of the decimal point, use a negative number. For example:

Floor(123.456,  2) returns 123.45
Floor(123.456, -2) returns 100

Equivalents

CiVBA includes some rounding functions that are similar to the attached Cicode functions. See MS KB article 196652 for other VB rounding functions.

 CiVBA Cicode Fix() Fix() Int() Floor() CByte(), CInt(), CLng(), CCur(), Round() RoundB()

References

Microsoft Knowledge Base, Q196652 How To Implement Custom Rounding Procedures, http://support.microsoft.com/kb/196652

Wikipedia, Rounding, http://en.wikipedia.org/wiki/Rounding

 Keywords: Ceil

Rounding.ci