fixed: add signed supported
This commit is contained in:
parent
a218774bc0
commit
81ccdcf8ef
183
fixed.cpp
183
fixed.cpp
@ -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;
|
||||||
}
|
}
|
||||||
@ -99,9 +99,9 @@ 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; \
|
||||||
@ -112,11 +112,13 @@ 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)
|
||||||
|
70
fixed.hpp
70
fixed.hpp
@ -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
|
||||||
|
@ -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> ();
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user