I'm working on a fixed-point math library. The accepted way of handling multiplications for fixed-point numbers is to multiply them into an integer variable that's larger than what you're storing, then shift the result to the right based on the scale factor.
The thing is, I'm already using 64-bit integers for storage, so in order to be able to multiply two values, I'm going to need access to a 128-bit integer. Otherwise, I'm going to have to split each value into two 32-bit integers and multiply them separately. (Either that, or do something creative with std::bitset
s; I haven't decided yet.)
In other words, I need to do something like the following pseudocode:
typedef int64_t storage_t;
if (type_exits(int128_t)) {
typedef int128_t math_t;
const bool use_32_bit_algorithm = false;
} else if (type_exists(__int128)) {
typedef __int128 math_t;
const bool use_32_bit_algorithm = false;
} else {
typedef int64_t math_t;
const bool use_32_bit_algorithm = true;
}
How do I implement type_exists()
?
Originally, I had gone with the option suggested in the comments of checking which compiler was being used, then typedef
whatever that particular compiler called its 128-bit integer. Then, I found a much better answer, entirely by accident, when I was looking up something else.
The answer is to switch to the C++23
standard, which allows me to use the new _BitInt
keyword to just make up an integer of whatever size I want, and let the compiler handle it. So, now my code looks something like this:
using value_t = int64_t;
int constexpr max_bits_math = std::numeric_limits<value_t>::digits * 2;
using math_value_t = _BitInt(max_bits_math);
int constexpr bit_shift = 8;
value_t operator*(value_t lhs, value_t rhs) {
math_value_t answer = static_cast<math_value_t>(lhs) * static_cast<math_value_t>(rhs);
return static_cast<value_t>(answer >> bit_shift);
}
Yes, I know that not a lot of compilers support _BitInt
yet, because it's so new. Then again, I'm still in the very early stages of this project, so I'm confident support will be more widespread when I'm ready to release.