C++11 Fixed Point Arithmetic Library

When working with embedded systems, it's not uncommon to encounter fixed-point mathematical operations. Many processors lack floating-point hardware support, resulting in inefficient software emulation of floating-point operations. Some situations require avoiding precision variability, and other situations require fixing the significand or exponent sizes to achieve specific precision targets. Additionally, fixed-point operations are portable and consistent across toolchains and architectures.

I recently stumbled across a C++11 fixed_point header-only library. The library introduces a fixed_point type, which is templated on two values:

template <class Rep, int Exponent>
class fixed_point;

The Rep parameter indicates the capacity and signedness of the underlying representative data type. The default representation is int, but you can supply any fundamental integral type or integral-like type. The library author's recommendation:

The most suitable types are: std::int8_t, std::uint8_t, std::int16_t, std::uint16_t, std::int32_t and std::uint32_t. In limited situations, std::int64_t and std::uint64_t can be used. The reasons for these limitations relate to the difficulty in finding a type that is suitable for performing lossless integer division.

The Exponent parameter is equivalent to the exponent field in a standard floating-point type and sets the precision of the fixed_point number. Resolution of a fixed_point number is 2^(Exponent), so expect Exponent to be negative.

The library also provides two helper functions: make_fixed and make_ufixed. These are declared as:

template <int IntegerDigits, int FractionalDigits = 0, 
    class Type = signed>
using make_fixed;

template <int IntegerDigits, int FractionalDigits = 0, 
    class Type = unsigned>
using make_ufixed;

Rather than worrying about underlying data types or exponent values, these helper functions allow you to specify the number of integral and fractional bits you wish to support:

//8-bit, unsigned, with 4 integer digits and 4 fractional digits
auto t = make_ufixed<4, 4> value { 15.9375 };

//32-bit, signed, with two integer digits and 29 fractional digits:
auto v = make_fixed<2, 29> value { 3.141592653 };

Normal mathematical operators (+, -, /, *) are supported with the fixed_point class and work with one or two fixed-point arguments. However, the operators perform as little computation as possible, resulting in the possibility of overflows and information loss. To combat this, the library supports mathematical functions that handle data widening for the user: negate, add, subtract, multiply, divide. These functional operations should be preferred to the mathematical operators.

auto f = fixed_point<uint8_t, -4>{15.9375};
auto p = multiply(f, f);
// p === fixed_point<uint16_t, -8>{254.00390625}

You can find the fixed_point library on GitHub, or you can take a shortcut and clone it using:

$ git clone https://github.com/johnmcfarlane/fixed_point.git

The API is exposed through headers in the include directory. Add this to your system header list and include:

#include <sg14/fixed_point>

Further Reading