fixed: add signed supported

This commit is contained in:
Danny Robson 2015-02-06 20:01:26 +11:00
parent a218774bc0
commit 81ccdcf8ef
3 changed files with 130 additions and 159 deletions

195
fixed.cpp
View File

@ -27,8 +27,8 @@ using namespace util;
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// Constructors // Constructors
template <unsigned I, unsigned E> template <typename T, unsigned I, unsigned E>
fixed<I,E>::fixed (uint_t val): fixed<T,I,E>::fixed (native_t val):
m_value (val << E) m_value (val << E)
{ {
static_assert (I > 0, "must use positive integer bits"); static_assert (I > 0, "must use positive integer bits");
@ -41,56 +41,56 @@ fixed<I,E>::fixed (uint_t val):
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// Conversions // Conversions
template <unsigned I, unsigned E> template <typename T, unsigned I, unsigned E>
double double
fixed<I,E>::to_double (void) const fixed<T,I,E>::to_double (void) const
{ {
return static_cast<double> (m_value) / pow (2, E); return static_cast<double> (m_value) / pow (2, E);
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
template <unsigned I, unsigned E> template <typename T, unsigned I, unsigned E>
float float
fixed<I,E>::to_float (void) const fixed<T,I,E>::to_float (void) const
{ {
return static_cast<float> (m_value) / pow (2, E); return static_cast<float> (m_value) / pow (2, E);
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
template <unsigned I, unsigned E> template <typename T, unsigned I, unsigned E>
typename fixed<I,E>::uint_t typename fixed<T,I,E>::native_t
fixed<I,E>::to_integer (void) const fixed<T,I,E>::to_integer (void) const
{ {
return m_value >> E; return m_value >> E;
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
template <unsigned I, unsigned E> template <typename T, unsigned I, unsigned E>
typename fixed<I,E>::uint_t typename fixed<T,I,E>::native_t
fixed<I,E>::to_native (void) const fixed<T,I,E>::to_native (void) const
{ {
return m_value; return m_value;
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
template <unsigned I, unsigned E> template <typename T, unsigned I, unsigned E>
fixed<I,E> fixed<T,I,E>
fixed<I,E>::from_native (uint_t i) fixed<T,I,E>::from_native (native_t i)
{ {
fixed<I,E> v; fixed<T,I,E> v;
v.m_value = i; v.m_value = i;
return v; return v;
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
template <unsigned I, unsigned E> template <typename T, unsigned I, unsigned E>
typename fixed<I,E>::uint_t typename fixed<T,I,E>::native_t
fixed<I,E>::to_integer (uint_t n) fixed<T,I,E>::to_integer (native_t n)
{ {
return n >> E; return n >> E;
} }
@ -98,25 +98,27 @@ fixed<I,E>::to_integer (uint_t n)
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// Fixed operators // Fixed operators
#define SIMPLE_FIXED_REF(OP) \ #define SIMPLE_FIXED_REF(OP) \
template <unsigned I, unsigned E> \ template <typename T, unsigned I, unsigned E> \
util::fixed<I,E>& \ util::fixed<T,I,E>& \
util::fixed<I,E>::operator OP (const fixed<I,E> rhs) \ util::fixed<T,I,E>::operator OP (const fixed<T,I,E> rhs) \
{ \ { \
m_value OP rhs.m_value; \ m_value OP rhs.m_value; \
return *this; \ return *this; \
} }
SIMPLE_FIXED_REF(-=) SIMPLE_FIXED_REF(-=)
SIMPLE_FIXED_REF(+=) SIMPLE_FIXED_REF(+=)
#define SIMPLE_FIXED_LIT(OP) \ #define SIMPLE_FIXED_LIT(OP) \
template <unsigned I, unsigned E> \ template <typename T, unsigned I, unsigned E> \
util::fixed<I,E> \ util::fixed<T,I,E> \
util::fixed<I,E>::operator OP (const fixed<I,E> rhs) const \ util::fixed<T,I,E>::operator OP (const fixed<T,I,E> rhs) const \
{ \ { \
return fixed<I,E> {m_value OP rhs.m_value}; \ fixed<T,I,E> v; \
v.m_value = m_value OP rhs.m_value; \
return v; \
} }
SIMPLE_FIXED_LIT(-) SIMPLE_FIXED_LIT(-)
@ -125,90 +127,44 @@ SIMPLE_FIXED_LIT(+)
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// Integer operators // Integer operators
#define SIMPLE_INTEGER_REF(OP) \
template <unsigned I, unsigned E> template <typename T, unsigned I, unsigned E> \
fixed<I,E>& fixed<T,I,E>& \
fixed<I,E>::operator+= (uint_t val) fixed<T,I,E>::operator OP (native_t val) \
{ { \
m_value += val << E; m_value OP val << E; \
return *this; return *this; \
} }
SIMPLE_INTEGER_REF(+=)
SIMPLE_INTEGER_REF(-=)
SIMPLE_INTEGER_REF(*=)
SIMPLE_INTEGER_REF(/=)
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
template <unsigned I, unsigned E> #define SIMPLE_INTEGER_LIT(OP) \
fixed<I,E>& template <typename T, unsigned I, unsigned E> \
fixed<I,E>::operator-= (uint_t val) fixed<T,I,E> \
{ fixed<T,I,E>::operator OP (native_t val) const \
m_value -= val << E; { \
return *this; return fixed<T,I,E>::from_native (m_value OP val << E); \
} }
SIMPLE_INTEGER_LIT(+)
//----------------------------------------------------------------------------- SIMPLE_INTEGER_LIT(-)
template <unsigned I, unsigned E> SIMPLE_INTEGER_LIT(*)
fixed<I,E>& SIMPLE_INTEGER_LIT(/)
fixed<I,E>::operator*= (uint_t val)
{
m_value *= val;
return *this;
}
//-----------------------------------------------------------------------------
template <unsigned I, unsigned E>
fixed<I,E>&
fixed<I,E>::operator/= (uint_t val)
{
m_value /= val;
return *this;
}
//-----------------------------------------------------------------------------
template <unsigned I, unsigned E>
fixed<I,E>
fixed<I,E>::operator+ (uint_t val) const
{
return fixed<I,E> (m_value + val << E);
}
//-----------------------------------------------------------------------------
template <unsigned I, unsigned E>
fixed<I,E>
fixed<I,E>::operator- (uint_t val) const
{
return fixed<I,E> (m_value - val << E);
}
//-----------------------------------------------------------------------------
template <unsigned I, unsigned E>
fixed<I,E>
fixed<I,E>::operator* (uint_t val) const
{
return fixed<I,E> (m_value * val);
}
//-----------------------------------------------------------------------------
template <unsigned I, unsigned E>
fixed<I,E>
fixed<I,E>::operator /(uint_t val) const
{
return fixed<I,E> (m_value / val);
}
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// logical operators // logical operators
#define LOGIC_OP(OP) \ #define LOGIC_OP(OP) \
template <unsigned I, unsigned E> \ template <typename T, unsigned I, unsigned E> \
bool \ bool \
util::operator OP (util::fixed<I,E> a, \ util::operator OP (util::fixed<T,I,E> a, \
util::fixed<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 (); \
} }
@ -222,9 +178,9 @@ LOGIC_OP(>=)
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// iostream operators // iostream operators
template <unsigned I, unsigned E> template <typename T, unsigned I, unsigned E>
std::ostream& std::ostream&
util::operator<< (std::ostream &os, fixed<I,E> v) util::operator<< (std::ostream &os, fixed<T,I,E> v)
{ {
return os << v.to_double (); return os << v.to_double ();
} }
@ -233,16 +189,21 @@ util::operator<< (std::ostream &os, fixed<I,E> v)
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// Instantiations // Instantiations
#define INSTANTIATE(I,E) \ #define INSTANTIATE(T,I,E) \
template class util::fixed<(I),(E)>; \ template class util::fixed<T,I,E>; \
template std::ostream& util::operator<< (std::ostream&, fixed<(I),(E)>); \ template std::ostream& util::operator<< (std::ostream&, fixed<T,I,E>); \
template bool util::operator== (util::fixed<(I),(E)>, util::fixed<(I),(E)>); \ template bool util::operator== (util::fixed<T,I,E>, util::fixed<T,I,E>); \
template bool util::operator!= (util::fixed<(I),(E)>, util::fixed<(I),(E)>); \ template bool util::operator!= (util::fixed<T,I,E>, util::fixed<T,I,E>); \
template bool util::operator< (util::fixed<(I),(E)>, util::fixed<(I),(E)>); \ template bool util::operator< (util::fixed<T,I,E>, util::fixed<T,I,E>); \
template bool util::operator<= (util::fixed<(I),(E)>, util::fixed<(I),(E)>); \ template bool util::operator<= (util::fixed<T,I,E>, util::fixed<T,I,E>); \
template bool util::operator> (util::fixed<(I),(E)>, util::fixed<(I),(E)>); \ template bool util::operator> (util::fixed<T,I,E>, util::fixed<T,I,E>); \
template bool util::operator>= (util::fixed<(I),(E)>, util::fixed<(I),(E)>); template bool util::operator>= (util::fixed<T,I,E>, util::fixed<T,I,E>);
INSTANTIATE(16,16) template class util::fixed<signed,8,8>;
INSTANTIATE(26, 6)
INSTANTIATE(32,32) INSTANTIATE(signed,16,16)
INSTANTIATE(signed,26, 6)
INSTANTIATE(signed,32,32)
INSTANTIATE(unsigned,16,16)
INSTANTIATE(unsigned,26, 6)
INSTANTIATE(unsigned,32,32)

View File

@ -26,61 +26,67 @@
#include <iostream> #include <iostream>
namespace util { namespace util {
template <unsigned I, unsigned E> template <typename T, unsigned I, unsigned E>
class fixed { class fixed {
public: public:
typedef typename bits_type<I+E>::uint uint_t; typedef typename std::conditional<
std::is_signed<T>::value,
typename bits_type<I+E>::sint,
typename bits_type<I+E>::uint
>::type native_t;
typedef native_t integer_t;
fixed (double); fixed (double);
fixed (float); fixed (float);
fixed (uint_t); fixed (native_t);
double to_double (void) const; double to_double (void) const;
float to_float (void) const; float to_float (void) const;
uint_t to_integer (void) const; integer_t to_integer (void) const;
uint_t to_native (void) const; native_t to_native (void) const;
static fixed<I,E> from_native (uint_t); static fixed<T,I,E> from_native (native_t);
static uint_t to_integer (uint_t); static integer_t to_integer (native_t);
fixed<I,E>& operator +=(const fixed<I,E>); fixed<T,I,E>& operator +=(const fixed<T,I,E>);
fixed<I,E>& operator -=(const fixed<I,E>); fixed<T,I,E>& operator -=(const fixed<T,I,E>);
fixed<I,E>& operator *=(const fixed<I,E>); fixed<T,I,E>& operator *=(const fixed<T,I,E>);
fixed<I,E>& operator /=(const fixed<I,E>); fixed<T,I,E>& operator /=(const fixed<T,I,E>);
fixed<I,E> operator +(const fixed<I,E>) const; fixed<T,I,E> operator +(const fixed<T,I,E>) const;
fixed<I,E> operator -(const fixed<I,E>) const; fixed<T,I,E> operator -(const fixed<T,I,E>) const;
fixed<I,E> operator *(const fixed<I,E>) const; fixed<T,I,E> operator *(const fixed<T,I,E>) const;
fixed<I,E> operator /(const fixed<I,E>) const; fixed<T,I,E> operator /(const fixed<T,I,E>) const;
fixed<I,E>& operator +=(uint_t); fixed<T,I,E>& operator +=(integer_t);
fixed<I,E>& operator -=(uint_t); fixed<T,I,E>& operator -=(integer_t);
fixed<I,E>& operator *=(uint_t); fixed<T,I,E>& operator *=(integer_t);
fixed<I,E>& operator /=(uint_t); fixed<T,I,E>& operator /=(integer_t);
fixed<I,E> operator +(uint_t) const; fixed<T,I,E> operator +(integer_t) const;
fixed<I,E> operator -(uint_t) const; fixed<T,I,E> operator -(integer_t) const;
fixed<I,E> operator *(uint_t) const; fixed<T,I,E> operator *(integer_t) const;
fixed<I,E> operator /(uint_t) const; fixed<T,I,E> operator /(integer_t) const;
private: private:
fixed () = default; fixed () = default;
uint_t m_value; native_t m_value;
}; };
template <unsigned I, unsigned E> bool operator== (util::fixed<I,E>, util::fixed<I,E>); template <typename T, unsigned I, unsigned E> bool operator== (util::fixed<T,I,E>, util::fixed<T,I,E>);
template <unsigned I, unsigned E> bool operator!= (util::fixed<I,E>, util::fixed<I,E>); template <typename T, unsigned I, unsigned E> bool operator!= (util::fixed<T,I,E>, util::fixed<T,I,E>);
template <unsigned I, unsigned E> bool operator< (util::fixed<I,E>, util::fixed<I,E>); template <typename T, unsigned I, unsigned E> bool operator< (util::fixed<T,I,E>, util::fixed<T,I,E>);
template <unsigned I, unsigned E> bool operator<= (util::fixed<I,E>, util::fixed<I,E>); template <typename T, unsigned I, unsigned E> bool operator<= (util::fixed<T,I,E>, util::fixed<T,I,E>);
template <unsigned I, unsigned E> bool operator> (util::fixed<I,E>, util::fixed<I,E>); template <typename T, unsigned I, unsigned E> bool operator> (util::fixed<T,I,E>, util::fixed<T,I,E>);
template <unsigned I, unsigned E> bool operator>= (util::fixed<I,E>, util::fixed<I,E>); template <typename T, unsigned I, unsigned E> bool operator>= (util::fixed<T,I,E>, util::fixed<T,I,E>);
template <unsigned I, unsigned E> template <typename T, unsigned I, unsigned E>
std::ostream& operator<< (std::ostream&, fixed<I,E>); std::ostream& operator<< (std::ostream&, fixed<T,I,E>);
} }
#endif // __UTIL_FIXED_HPP #endif // __UTIL_FIXED_HPP

View File

@ -2,15 +2,15 @@
#include "debug.hpp" #include "debug.hpp"
template <unsigned I, unsigned E> template <typename T, unsigned I, unsigned E>
void void
test_simple (void) test_simple (void)
{ {
using fixed_t = util::fixed<I,E>; using fixed_t = util::fixed<T,I,E>;
using uint_t = typename fixed_t::uint_t; using integer_t = typename fixed_t::integer_t;
const fixed_t lo = uint_t{0}; const fixed_t lo = integer_t{0};
const fixed_t hi = uint_t{1}; const fixed_t hi = integer_t{1};
CHECK_EQ (lo, lo); CHECK_EQ (lo, lo);
CHECK_EQ (hi, hi); CHECK_EQ (hi, hi);
@ -31,7 +31,11 @@ test_simple (void)
int int
main (void) main (void)
{ {
test_simple<16,16> (); test_simple<signed,16,16> ();
test_simple<26, 6> (); test_simple<signed,26, 6> ();
test_simple<32,32> (); test_simple<signed,32,32> ();
test_simple<unsigned,16,16> ();
test_simple<unsigned,26, 6> ();
test_simple<unsigned,32,32> ();
} }