fixed: add integer logical operators

This commit is contained in:
Danny Robson 2017-01-04 22:38:41 +11:00
parent 0997bbbaac
commit b770e5f370
3 changed files with 119 additions and 72 deletions

View File

@ -22,21 +22,6 @@ using namespace util;
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// Constructors
template <typename T, unsigned I, unsigned E>
fixed<T,I,E>::fixed (native_t val):
m_value (val << E)
{
static_assert (I > 0, "must use positive integer bits");
static_assert (E > 0, "must use positive fractional bits");
static_assert (I + E == sizeof (m_value) * 8,
"underlying storage must be exactly I+E sized");
}
///////////////////////////////////////////////////////////////////////////////
// Conversions
template <typename T, unsigned I, unsigned E> template <typename T, unsigned I, unsigned E>
double double
fixed<T,I,E>::to_double (void) const fixed<T,I,E>::to_double (void) const
@ -56,7 +41,7 @@ fixed<T,I,E>::to_float (void) const
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
template <typename T, unsigned I, unsigned E> template <typename T, unsigned I, unsigned E>
typename fixed<T,I,E>::native_t typename fixed<T,I,E>::integer_type
fixed<T,I,E>::to_integer (void) const fixed<T,I,E>::to_integer (void) const
{ {
return m_value >> E; return m_value >> E;
@ -65,7 +50,7 @@ fixed<T,I,E>::to_integer (void) const
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
template <typename T, unsigned I, unsigned E> template <typename T, unsigned I, unsigned E>
typename fixed<T,I,E>::native_t typename fixed<T,I,E>::native_type
fixed<T,I,E>::to_native (void) const fixed<T,I,E>::to_native (void) const
{ {
return m_value; return m_value;
@ -75,7 +60,7 @@ fixed<T,I,E>::to_native (void) const
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
template <typename T, unsigned I, unsigned E> template <typename T, unsigned I, unsigned E>
fixed<T,I,E> fixed<T,I,E>
fixed<T,I,E>::from_native (native_t i) fixed<T,I,E>::from_native (native_type i)
{ {
fixed<T,I,E> v; fixed<T,I,E> v;
v.m_value = i; v.m_value = i;
@ -85,8 +70,22 @@ fixed<T,I,E>::from_native (native_t i)
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
template <typename T, unsigned I, unsigned E> template <typename T, unsigned I, unsigned E>
typename fixed<T,I,E>::native_t fixed<T,I,E>
fixed<T,I,E>::to_integer (native_t n) fixed<T,I,E>::from_integer (integer_type val)
{
constexpr auto rshift = sizeof (val) * 8 - I;
constexpr auto lshift = E - rshift;
fixed<T,I,E> res;
res.m_value = static_cast<native_type> (val) << lshift;
return res;
}
//-----------------------------------------------------------------------------
template <typename T, unsigned I, unsigned E>
typename fixed<T,I,E>::integer_type
fixed<T,I,E>::to_integer (native_type n)
{ {
return n >> E; return n >> E;
} }
@ -123,13 +122,13 @@ SIMPLE_FIXED_LIT(+)
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// Integer operators // Integer operators
#define SIMPLE_INTEGER_REF(OP) \ #define SIMPLE_INTEGER_REF(OP) \
template <typename T, unsigned I, unsigned E> \ template <typename T, unsigned I, unsigned E> \
fixed<T,I,E>& \ fixed<T,I,E>& \
fixed<T,I,E>::operator OP (native_t val) \ fixed<T,I,E>::operator OP (integer_type val) \
{ \ { \
m_value OP val << E; \ m_value OP (static_cast<native_type> (val) << E); \
return *this; \ return *this; \
} }
SIMPLE_INTEGER_REF(+=) SIMPLE_INTEGER_REF(+=)
@ -139,10 +138,10 @@ SIMPLE_INTEGER_REF(/=)
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
#define SIMPLE_INTEGER_LIT(OP) \ #define SIMPLE_INTEGER_LIT(OP) \
template <typename T, unsigned I, unsigned E> \ template <typename T, unsigned I, unsigned E> \
fixed<T,I,E> \ fixed<T,I,E> \
fixed<T,I,E>::operator OP (native_t val) const \ fixed<T,I,E>::operator OP (integer_type val) const \
{ \ { \
return fixed<T,I,E>::from_native (m_value OP val << E); \ return fixed<T,I,E>::from_native (m_value OP val << E); \
} }
@ -163,6 +162,14 @@ util::operator OP (util::fixed<T,I,E> a, \
util::fixed<T,I,E> b) \ util::fixed<T,I,E> b) \
{ \ { \
return a.to_native () OP b.to_native (); \ return a.to_native () OP b.to_native (); \
} \
\
template <typename T, unsigned I, unsigned E> \
bool \
util::operator OP (util::fixed<T,I,E> a, \
typename util::fixed<T,I,E>::integer_type b) \
{ \
return a OP util::fixed<T,I,E>::from_integer (b); \
} }
LOGIC_OP(==) LOGIC_OP(==)
@ -172,6 +179,7 @@ LOGIC_OP(<=)
LOGIC_OP(>) LOGIC_OP(>)
LOGIC_OP(>=) LOGIC_OP(>=)
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// iostream operators // iostream operators
template <typename T, unsigned I, unsigned E> template <typename T, unsigned I, unsigned E>
@ -193,10 +201,17 @@ template bool util::operator!= (util::fixed<T,I,E>, util::fixed<T,I,E>); \
template bool util::operator< (util::fixed<T,I,E>, util::fixed<T,I,E>); \ template bool util::operator< (util::fixed<T,I,E>, util::fixed<T,I,E>); \
template bool util::operator<= (util::fixed<T,I,E>, util::fixed<T,I,E>); \ template bool util::operator<= (util::fixed<T,I,E>, util::fixed<T,I,E>); \
template bool util::operator> (util::fixed<T,I,E>, util::fixed<T,I,E>); \ template bool util::operator> (util::fixed<T,I,E>, util::fixed<T,I,E>); \
template bool util::operator>= (util::fixed<T,I,E>, util::fixed<T,I,E>); template bool util::operator>= (util::fixed<T,I,E>, util::fixed<T,I,E>); \
template bool util::operator== (util::fixed<T,I,E>, typename util::fixed<T,I,E>::integer_type); \
template bool util::operator!= (util::fixed<T,I,E>, typename util::fixed<T,I,E>::integer_type); \
template bool util::operator< (util::fixed<T,I,E>, typename util::fixed<T,I,E>::integer_type); \
template bool util::operator<= (util::fixed<T,I,E>, typename util::fixed<T,I,E>::integer_type); \
template bool util::operator> (util::fixed<T,I,E>, typename util::fixed<T,I,E>::integer_type); \
template bool util::operator>= (util::fixed<T,I,E>, typename util::fixed<T,I,E>::integer_type);
template class util::fixed<signed,8,8>; template class util::fixed<signed,8,8>;
INSTANTIATE(signed, 2,14)
INSTANTIATE(signed,16,16) INSTANTIATE(signed,16,16)
INSTANTIATE(signed,26, 6) INSTANTIATE(signed,26, 6)
INSTANTIATE(signed,32,32) INSTANTIATE(signed,32,32)

105
fixed.hpp
View File

@ -17,69 +17,98 @@
#ifndef __UTIL_FIXED_HPP #ifndef __UTIL_FIXED_HPP
#define __UTIL_FIXED_HPP #define __UTIL_FIXED_HPP
#include "types/bits.hpp" #include "./types/bits.hpp"
#include "./maths.hpp"
#include "./endian.hpp"
#include <ostream> #include <ostream>
namespace util { namespace util {
template <typename T, unsigned I, unsigned E> template <typename T, unsigned I, unsigned E>
class fixed { class [[gnu::packed]] fixed {
public: public:
typedef typename std::conditional< static_assert (I > 0);
std::is_signed<T>::value, static_assert (E > 0);
typename bits_type<I+E>::sint, static_assert ((I + E) % 8 == 0);
typename bits_type<I+E>::uint
>::type native_t;
typedef native_t integer_t; using sint_t = typename bits_type<I+E>::sint;
using uint_t = typename bits_type<I+E>::uint;
explicit fixed (double); using native_type = typename std::conditional<
explicit fixed (float); std::is_signed<T>::value,
explicit fixed (native_t); sint_t, uint_t
>::type;
double to_double (void) const; using integer_type = typename std::conditional<
float to_float (void) const; std::is_signed<T>::value,
integer_t to_integer (void) const; typename bits_type<divup (I, 8u) * 8u>::sint,
native_t to_native (void) const; typename bits_type<divup (I, 8u) * 8u>::uint
>::type;
static fixed<T,I,E> from_native (native_t); explicit fixed (double);
static integer_t to_integer (native_t); explicit fixed (float);
fixed<T,I,E>& operator +=(const fixed<T,I,E>); double to_double (void) const;
fixed<T,I,E>& operator -=(const fixed<T,I,E>); float to_float (void) const;
fixed<T,I,E>& operator *=(const fixed<T,I,E>); integer_type to_integer (void) const;
fixed<T,I,E>& operator /=(const fixed<T,I,E>); native_type to_native (void) const;
fixed<T,I,E> operator +(const fixed<T,I,E>) const; static fixed<T,I,E> from_native (native_type);
fixed<T,I,E> operator -(const fixed<T,I,E>) const; static fixed<T,I,E> from_integer (integer_type);
fixed<T,I,E> operator *(const fixed<T,I,E>) const;
fixed<T,I,E> operator /(const fixed<T,I,E>) const;
fixed<T,I,E>& operator +=(integer_t); static integer_type to_integer (native_type);
fixed<T,I,E>& operator -=(integer_t);
fixed<T,I,E>& operator *=(integer_t);
fixed<T,I,E>& operator /=(integer_t);
fixed<T,I,E> operator +(integer_t) const; fixed<T,I,E>& operator +=(const fixed<T,I,E>);
fixed<T,I,E> operator -(integer_t) const; fixed<T,I,E>& operator -=(const fixed<T,I,E>);
fixed<T,I,E> operator *(integer_t) const; fixed<T,I,E>& operator *=(const fixed<T,I,E>);
fixed<T,I,E> operator /(integer_t) const; fixed<T,I,E>& operator /=(const fixed<T,I,E>);
private: fixed<T,I,E> operator +(const fixed<T,I,E>) const;
fixed () = default; fixed<T,I,E> operator -(const fixed<T,I,E>) const;
fixed<T,I,E> operator *(const fixed<T,I,E>) const;
fixed<T,I,E> operator /(const fixed<T,I,E>) const;
native_t m_value; fixed<T,I,E>& operator +=(integer_type);
fixed<T,I,E>& operator -=(integer_type);
fixed<T,I,E>& operator *=(integer_type);
fixed<T,I,E>& operator /=(integer_type);
fixed<T,I,E> operator +(integer_type) const;
fixed<T,I,E> operator -(integer_type) const;
fixed<T,I,E> operator *(integer_type) const;
fixed<T,I,E> operator /(integer_type) const;
private:
fixed () = default;
native_type m_value;
}; };
template <typename T, unsigned I, unsigned E>
constexpr
fixed<T,I,E>
bswap (fixed<T,I,E> val)
{
return fixed<T,I,E>::from_native (
bswap (val.to_native ())
);
}
template <typename T, unsigned I, unsigned E> bool operator== (util::fixed<T,I,E>, util::fixed<T,I,E>); template <typename T, unsigned I, unsigned E> bool operator== (util::fixed<T,I,E>, util::fixed<T,I,E>);
template <typename T, unsigned I, unsigned E> bool operator!= (util::fixed<T,I,E>, util::fixed<T,I,E>); template <typename T, unsigned I, unsigned E> bool operator!= (util::fixed<T,I,E>, util::fixed<T,I,E>);
template <typename T, unsigned I, unsigned E> bool operator< (util::fixed<T,I,E>, util::fixed<T,I,E>); template <typename T, unsigned I, unsigned E> bool operator< (util::fixed<T,I,E>, util::fixed<T,I,E>);
template <typename T, unsigned I, unsigned E> bool operator<= (util::fixed<T,I,E>, util::fixed<T,I,E>); template <typename T, unsigned I, unsigned E> bool operator<= (util::fixed<T,I,E>, util::fixed<T,I,E>);
template <typename T, unsigned I, unsigned E> bool operator> (util::fixed<T,I,E>, util::fixed<T,I,E>); template <typename T, unsigned I, unsigned E> bool operator> (util::fixed<T,I,E>, util::fixed<T,I,E>);
template <typename T, unsigned I, unsigned E> bool operator>= (util::fixed<T,I,E>, util::fixed<T,I,E>); template <typename T, unsigned I, unsigned E> bool operator>= (util::fixed<T,I,E>, util::fixed<T,I,E>);
template <typename T, unsigned I, unsigned E> bool operator== (util::fixed<T,I,E>, typename util::fixed<T,I,E>::integer_type);
template <typename T, unsigned I, unsigned E> bool operator!= (util::fixed<T,I,E>, typename util::fixed<T,I,E>::integer_type);
template <typename T, unsigned I, unsigned E> bool operator< (util::fixed<T,I,E>, typename util::fixed<T,I,E>::integer_type);
template <typename T, unsigned I, unsigned E> bool operator<= (util::fixed<T,I,E>, typename util::fixed<T,I,E>::integer_type);
template <typename T, unsigned I, unsigned E> bool operator> (util::fixed<T,I,E>, typename util::fixed<T,I,E>::integer_type);
template <typename T, unsigned I, unsigned E> bool operator>= (util::fixed<T,I,E>, typename util::fixed<T,I,E>::integer_type);
template <typename T, unsigned I, unsigned E> template <typename T, unsigned I, unsigned E>
std::ostream& operator<< (std::ostream&, fixed<T,I,E>); std::ostream& operator<< (std::ostream&, fixed<T,I,E>);

View File

@ -3,15 +3,17 @@
#include "tap.hpp" #include "tap.hpp"
///////////////////////////////////////////////////////////////////////////////
template <typename T, unsigned I, unsigned E> template <typename T, unsigned I, unsigned E>
void void
test_simple (util::TAP::logger &tap) test_simple (util::TAP::logger &tap)
{ {
using fixed_t = util::fixed<T,I,E>; using fixed = util::fixed<T,I,E>;
using integer_t = typename fixed_t::integer_t; using integer = typename fixed::integer_type;
const fixed_t lo {integer_t{0}}; const auto lo = fixed::from_integer (integer {0});
const fixed_t hi {integer_t{1}}; const auto hi = fixed::from_integer (integer {1});
std::ostringstream os; std::ostringstream os;
os << "fixed<" << type_to_string<T> () << ',' << I << ',' << E << '>'; os << "fixed<" << type_to_string<T> () << ',' << I << ',' << E << '>';
@ -32,6 +34,7 @@ test_simple (util::TAP::logger &tap)
} }
///////////////////////////////////////////////////////////////////////////////
int int
main (void) main (void)
{ {