By Andrew Dowd
This nifty little algorithm can quickly round a 2’s complement fixedpoint value with a fractional binary point. It requires two easy operations and no branching. Unlike most rounding algorithms, this method does not require a compare operation (i.e. a branch). Consequently, it does not cause a cache flush and is very fast on modern processors. Also, implementation of this method requires minimal resources on an FPGA. To illustrate, I have provided some code snippets to demonstration this algorithm in C and VHDL. This rounding is sometimes called “Round half up”.
In words, the algorithm can be described as follows:
 Add the equivalent of 0.5 to the value
 Truncate all bits below the binary decimal point
This algorithm makes intuitive sense. Consider a two simple examples:
Round 12.2: floor(12.2 + 0.5) = floor(12.7) = 12
Round 12.7: floor(12.7 + 0.5) = floor(13.2) = 13
Two’s Complement Examples–Positive and Negative
To implement this on a two’s complement number requires two steps. First add the value 0.5 in the same fixedpoint format as the number to be rounded. Next, zero all the bits below the binary point. This is equivalent to “anding” the result by 1 expressed in the same fixedpoint format.
Here is a detailed breakdown of applying this algorithm to the value 4.1172 expressed in Q8.7 fixedpoint format:
RealWorld Value  Binary Value  Hex Value  
Initial value  +4.1172  0000001000001111  0x020F 
0.5 (in Q8.7 format)  +0.5  0000000001000000  0x0040 
+ Operation  +4.6172  0000001001001111  0x024F 
1 (in Q8.7 format)  1  1111111110000000  0xFF80 
& Operation  +4.000  0000001000000000  0x0200 
For programmer that encounter this algorithm for the first time, there is always a worry about how it behaves with negative numbers. Some rounding algorithms require different operations on positive and negative numbers, so this concern is justified. Fortunately, in this case, the algorithm is the same regardless of the sign of the original data. To demonstrate that this algorithm works the same on negative values, consider the following example:
RealWorld Value  Binary Value  Hex Value  
Initial value  4.1172  1111110111110001  0xFDF1 
0.5 (in Q8.7 format)  +0.5  0000000001000000  0x0040 
+ Operation  3.6172  1111111000110001  0xFE31 
1 (in Q8.7 format)  1  1111111110000000  0xFF80 
& Operation  4.0000  1111111000000000  0xFE00 
Code Snippets
A Cimplementation of this algorithm is shown below. This code is very general but it is not optimized for fast execution. By precomputing two temporary values for a given binary point, the result can be computed in two steps. The binary point is passed into the function. This inputs equals the second value number : i.e. n is the number of bits used to designate the fractional portion of the number.

A VHDL implementation is shown below. It is implemented as a function and suitable for most data widths.

Cavet Emptor–Rounding Bias
An unbiased rounding method has an equal probability of rounding up or down, assuming a uniform distribution of possible values. The algorithm described here is slightly biased. For input with a factional value of precisely .5, this algorithm will always roundup (toward positive infinity). Depending on your application, rounding bias is either a mild curiosity or a fatal flaw. The imbalance is worst for types with fewer binary digits. For applications that require unbiased rounding, it is possible to extend this simple algorithm, at the expense of additional operations. By detecting the case where the factional value of precisely 0.5, it is possible to alternate between rounding up and down. This can be done in any number of different ways such as alternating the methods or randomly applying them.