Skip to content

Instantly share code, notes, and snippets.

@Rseding91
Created January 14, 2021 14:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Rseding91/074c36c2d70296c4892ea88d65e3432f to your computer and use it in GitHub Desktop.
Save Rseding91/074c36c2d70296c4892ea88d65e3432f to your computer and use it in GitHub Desktop.
FixedPointNumber
#pragma once
#include <TypeTraitsExtensions.hpp>
#include <Util/FixedPointNumberTemplateForwards.hpp>
#include <cstdlib> // keep me
#include <limits> // keep me
#include <stdint.h>
class Deserialiser;
class Serialiser;
template<class T, uint32_t PrecisionBits>
class FixedPointNumberTemplate
{
public:
using ValueType = T;
static constexpr uint32_t FractionalBits = PrecisionBits;
static constexpr T ValuesPerOne = T(1) << PrecisionBits;
constexpr FixedPointNumberTemplate() : value(0) {}
constexpr FixedPointNumberTemplate(int32_t number) : value(T(T(number) << PrecisionBits)) {}
constexpr FixedPointNumberTemplate(uint32_t number) : value(T(T(number) << PrecisionBits)) {}
constexpr FixedPointNumberTemplate(int64_t number) : value(T(T(number) << PrecisionBits)) {}
constexpr FixedPointNumberTemplate(uint64_t number) : value(T(T(number) << PrecisionBits)) {}
constexpr FixedPointNumberTemplate(double number) : value(T(number * ValuesPerOne)) {}
constexpr FixedPointNumberTemplate(int32_t, T value) : value(value) {}
explicit FixedPointNumberTemplate(Deserialiser& input);
template <class K, uint32_t OtherPrecisionBits>
constexpr FixedPointNumberTemplate(const FixedPointNumberTemplate<K, OtherPrecisionBits>& other)
{
if constexpr (PrecisionBits < OtherPrecisionBits)
this->value = T(other.value >> (OtherPrecisionBits - PrecisionBits));
else
this->value = T(other.value << (PrecisionBits - OtherPrecisionBits));
}
static FixedPointNumberTemplate powerOfTwo(int32_t exponent) { return FixedPointNumberTemplate(0, T(1) << (PrecisionBits + exponent)); }
INLINE_CPP void save(Serialiser& output) const;
constexpr double getDouble() const { constexpr double ValuePerIncrement = 1.0 / ValuesPerOne; return double(this->value) * ValuePerIncrement; }
constexpr float getFloat() const { constexpr float ValuePerIncrement = 1.0f / ValuesPerOne; return float(this->value) * ValuePerIncrement; }
static constexpr FixedPointNumberTemplate max() { return FixedPointNumberTemplate(0, std::numeric_limits<T>::max()); }
static constexpr FixedPointNumberTemplate min() { return FixedPointNumberTemplate(0, std::numeric_limits<T>::min()); }
constexpr void cutBits(uint32_t bits) { this->value >>= bits; this->value <<= bits; }
constexpr FixedPointNumberTemplate next() const { FixedPointNumberTemplate result(*this); ++result.value; return result; }
constexpr FixedPointNumberTemplate previous() const { FixedPointNumberTemplate result(*this); --result.value; return result; }
constexpr FixedPointNumberTemplate abs() const
{
FixedPointNumberTemplate result(*this);
if constexpr (std::numeric_limits<T>::min() < 0)
result.value = T(result.value < 0 ? -result.value : result.value);
return result;
}
constexpr FixedPointNumberTemplate& operator+=(double addition) { return this->value += T(addition * ValuesPerOne), *this; }
constexpr FixedPointNumberTemplate& operator+=(const FixedPointNumberTemplate& addition) { return this->value += addition.value, *this; }
constexpr FixedPointNumberTemplate& operator-=(double minus) { return this->value -= T(minus * ValuesPerOne), *this; }
constexpr FixedPointNumberTemplate& operator-=(const FixedPointNumberTemplate& minus) { return this->value -= minus.value, *this; }
constexpr FixedPointNumberTemplate& operator*=(const double& multiplier) { return this->value = T(this->value * multiplier), *this; }
constexpr FixedPointNumberTemplate& operator/=(const double& divisor) { return this->value = T(this->value / divisor), *this; }
constexpr FixedPointNumberTemplate& operator++() { return this->value += T(1) << PrecisionBits, *this; }
constexpr bool operator<(const FixedPointNumberTemplate& cmp) const { return this->value < cmp.value; }
constexpr bool operator<=(const FixedPointNumberTemplate& cmp) const { return this->value <= cmp.value; }
constexpr bool operator>(const FixedPointNumberTemplate& cmp) const { return this->value > cmp.value; }
constexpr bool operator>=(const FixedPointNumberTemplate& cmp) const { return this->value >= cmp.value; }
constexpr bool operator==(const FixedPointNumberTemplate& cmp) const { return this->value == cmp.value; }
constexpr bool operator!=(const FixedPointNumberTemplate& cmp) const { return this->value != cmp.value; }
constexpr FixedPointNumberTemplate operator-() const
{
FixedPointNumberTemplate result(*this);
if constexpr (std::numeric_limits<T>::min() < 0)
result.value = -result.value;
return result;
}
constexpr T floor() const { return this->value >> PrecisionBits; }
constexpr FixedPointNumberTemplate cutPrecision(int32_t remainingPrecision) { return FixedPointNumberTemplate(0, T(this->value & ~((1 << (PrecisionBits - remainingPrecision)) - 1))); }
constexpr FixedPointNumberTemplate floorAsFixedPoint() const { FixedPointNumberTemplate result(*this); result.value >>= PrecisionBits; result.value <<= PrecisionBits; return result; }
constexpr T ceil() const { return (this->value + (ValuesPerOne - 1)) >> PrecisionBits; } constexpr FixedPointNumberTemplate ceilAsFixedPoint() const { FixedPointNumberTemplate result(*this); result.value += (ValuesPerOne - 1); result.value >>= PrecisionBits; result.value <<= PrecisionBits; return result; }
constexpr T round() const { return (this->value >= 0) ? (*this + FixedPointNumberTemplate(0.5)).floor() : (*this - FixedPointNumberTemplate(0.5)).ceil(); }
constexpr FixedPointNumberTemplate roundAsFixedPoint() const { return (this->value >= 0) ? (*this + FixedPointNumberTemplate(0.5)).floorAsFixedPoint() : (*this - FixedPointNumberTemplate(0.5)).ceilAsFixedPoint(); }
constexpr FixedPointNumberTemplate operator+(const FixedPointNumberTemplate& other) const { return FixedPointNumberTemplate(0, this->value + other.value); }
constexpr FixedPointNumberTemplate operator-(const FixedPointNumberTemplate& other) const { return FixedPointNumberTemplate(0, this->value - other.value); }
constexpr FixedPointNumberTemplate operator*(double multiplier) const { return FixedPointNumberTemplate(0, T(this->value * multiplier)); }
constexpr FixedPointNumberTemplate operator/(double divisor) const { return FixedPointNumberTemplate(0, T(this->value / divisor)); }
constexpr FixedPointNumberTemplate operator<<(uint32_t shift) const { return FixedPointNumberTemplate(0, this->value << shift); }
constexpr FixedPointNumberTemplate operator>>(uint32_t shift) const { return FixedPointNumberTemplate(0, this->value >> shift); }
constexpr FixedPointNumberTemplate fround(double divisor) const { FixedPointNumberTemplate result(*this); result /= divisor; result = result.roundAsFixedPoint(); result *= divisor; return result; }
T value;
};
using FixedPointNumber = FixedPointNumberTemplate<>;
static_assert(uses_memcpy<FixedPointNumber>);
#include <Map/MapSerialiser.hpp>
#include <Util/Deserialiser.hpp>
template<class T, uint32_t PrecisionBits>
FixedPointNumberTemplate<T, PrecisionBits>::FixedPointNumberTemplate(Deserialiser& input)
: value(input.load<T>())
{}
template<class T, uint32_t PrecisionBits>
INLINE_CPP void FixedPointNumberTemplate<T, PrecisionBits>::save(Serialiser& output) const
{
output << this->value;
}
template class FixedPointNumberTemplate<uint8_t, 3>;
template class FixedPointNumberTemplate<int8_t, 4>;
template class FixedPointNumberTemplate<int16_t, 10>;
template class FixedPointNumberTemplate<int16_t, 8>;
template class FixedPointNumberTemplate<uint16_t, 8>;
template class FixedPointNumberTemplate<int32_t, 8>;
template class FixedPointNumberTemplate<int32_t, 24>;
template class FixedPointNumberTemplate<int64_t, 8>;
template class FixedPointNumberTemplate<int64_t, 32>;
template class FixedPointNumberTemplate<uint32_t, 8>;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment