Well, you need to encapsulate your value inside a class, so then you can provide your own operator overloads to work with it. I'd suggest even making it a template, so you can choose the underlying representation size and the number of bits to shift; e.g.
template <typename Valtype, size_t ShiftCount>
class fixed {
Valtype value;
⋮
};
Addition and Subtraction between identical fixed types just work by adding/subtracting their underlying value. For
mixed fixed types, e.g. if a has
a
shift count of 16 bits and
b
has a shift count of 8 bits, then you have to align them before adding, and consider what the result type should be. I avoid the latter issue by not allowing mixed types in
operator+
, but I do in
operator+=
since it is explicit that the result needs to be the type of the left operand.
For multiplication, the result has a shift count that is the sum of the arguments' shift counts.
Now division is the hard one. I don't have a general solution in my own code, but have arranged things to suit the specific needs of the code that uses it. When you divide, how many fractional bits do you
want in the answer?
If you don't generalize to a template that allows different shift counts, then multiplication will necessarily chop off the extra bits, and division gives your (only) type as a result. But you'll need more complex stuff inside the operators.
If you do allow different shift counts, then you can automatically allow promotion but not conversions that lose precision. The latter can be available with an explicit conversion.
Of course, it's also good to provide ways to view these values: have a
to_string
function, make it work with
ostream
, and make it work with the
fmt
library. But, also consider making the underlying conversion code follow the more efficient model introduced in C++17:
to_chars allows the caller to supply a local buffer, which is practical since the maximum length is known. This makes implementing the
ostream
and
fmt
output functions more efficient.