Files
2019-06-15 12:51:33 +01:00

215 lines
6.5 KiB
Objective-C

#ifndef FRAMELIB_FIXEDPOINT_H
#define FRAMELIB_FIXEDPOINT_H
#include <stdint.h>
#include <cmath>
#include <limits>
/**
@defgroup FixedPoint Fixed-Point
*/
/**
@struct FL_SP
@ingroup FixedPoint
@brief a minimal class for "super precision" fixed-point calculations where required.
This unsigned type allows for 64 bits of integer precision and 128 bits of fractional precision.
*/
struct FL_SP
{
// Constructors
FL_SP() {}
FL_SP(uint64_t a, uint64_t b, uint64_t c) : mInt(a), mFracHi(b), mFracLo(c) {}
// Get Components
uint64_t intVal() const { return mInt; }
uint64_t fracHiVal() const { return mFracHi; }
uint64_t fracLoVal() const { return mFracLo; }
// Necessary Operations
friend FL_SP qMul(const FL_SP& a, const uint64_t& intVal, const uint64_t& fracVal);
friend FL_SP operator * (const FL_SP& a, const FL_SP& b);
friend FL_SP twoMinus(const FL_SP& b);
private:
uint64_t mInt;
uint64_t mFracHi;
uint64_t mFracLo;
};
/**
@class FL_FP
@ingroup FixedPoint
@brief high-precision unsigned fixed-point numerical format.
This unsigned type allows for 64 bits of integer precision and 64 bits of fractional precision. Basic arithmetic and comparison operators are supported, for this type, and when used in conjunction with double-precision floating-point numbers. The primary purpose of this type is to precisely represent the time in samples in FrameLib.
*/
class FL_FP
{
public:
// Constructors
FL_FP() : mInt(0U), mFrac(0U) {}
FL_FP(uint64_t a, uint64_t b) : mInt(a), mFrac(b) {}
FL_FP(const FL_SP& val);
FL_FP(const double& val);
// Int and Fract
uint64_t intVal() const { return mInt; }
uint64_t fracVal() const { return mFrac; }
// Comparison operators (N.B. - it is faster to avoid branching using bit rather logical operators)
friend bool operator == (const FL_FP& a, const FL_FP& b) { return ((a.mInt == b.mInt) & (a.mFrac == b.mFrac)); }
friend bool operator != (const FL_FP& a, const FL_FP& b) { return !(a == b); }
friend bool operator < (const FL_FP& a, const FL_FP& b) { return ((a.mInt < b.mInt) | ((a.mInt == b.mInt) & (a.mFrac < b.mFrac))); }
friend bool operator > (const FL_FP& a, const FL_FP& b) { return ((a.mInt > b.mInt) | ((a.mInt == b.mInt) & (a.mFrac > b.mFrac))); }
friend bool operator <= (const FL_FP& a, const FL_FP& b) { return !(a > b); }
friend bool operator >= (const FL_FP& a, const FL_FP& b) { return !(a < b); }
// Zero Test
friend bool operator ! ( const FL_FP& b) { return !b.mInt && !b.mFrac; }
// Arithmetic Operators
friend FL_FP operator + (const FL_FP& a, const FL_FP& b);
friend FL_FP operator - (const FL_FP& a, const FL_FP& b);
friend FL_FP operator * (const FL_FP& a, const FL_FP& b);
friend FL_FP operator / (const FL_FP& a, const FL_FP& b);
// Arithmetic Operators with Assignment
FL_FP& operator += (const FL_FP& b)
{
*this = *this + b;
return *this;
}
FL_FP& operator -= (const FL_FP& b)
{
*this = *this - b;
return *this;
}
FL_FP& operator *= (const FL_FP& b)
{
*this = *this * b;
return *this;
}
FL_FP& operator /= (const FL_FP& b)
{
*this = *this / b;
return *this;
}
// Increment / Decrement Operatiors
FL_FP& operator ++ ()
{
if (++mFrac == uint64_t(0U))
++mInt;
return *this;
}
FL_FP operator ++ (int)
{
FL_FP result = *this;
operator++();
return result;
}
FL_FP& operator -- ()
{
if (mFrac-- == uint64_t(0U))
--mInt;
return *this;
}
FL_FP& operator -- (int)
{
FL_FP& result = *this;
operator--();
return result;
}
// Support for operators using doubles
// Conversion
operator double() const { return ((double) mInt) + ((double) mFrac / 18446744073709551616.0); }
FL_FP& operator = (const double& a)
{
*this = FL_FP(a);
return *this;
}
// Comparison
friend bool operator == (const FL_FP& a, const double& b) { return a == FL_FP(b); }
friend bool operator == (const double& a, const FL_FP& b) { return FL_FP(a) == b; }
friend bool operator != (const FL_FP& a, const double& b) { return a != FL_FP(b); }
friend bool operator != (const double& a, const FL_FP& b) { return FL_FP(a) != b; }
friend bool operator < (const FL_FP& a, const double& b) { return a < FL_FP(b); }
friend bool operator < (const double& a, const FL_FP& b) { return FL_FP(a) < b; }
friend bool operator > (const FL_FP& a, const double& b) { return a > FL_FP(b); }
friend bool operator > (const double& a, const FL_FP& b) { return FL_FP(a) > b; }
friend bool operator <= (const FL_FP& a, const double& b) { return a <= FL_FP(b); }
friend bool operator <= (const double& a, const FL_FP& b) { return FL_FP(a) <= b; }
friend bool operator >= (const FL_FP& a, const double& b) { return a >= FL_FP(b); }
friend bool operator >= (const double& a, const FL_FP& b) { return FL_FP(a) >= b; }
// Arithmetic Operators
friend FL_FP operator + (const FL_FP& a, const double& b) { return a + FL_FP(b); }
friend FL_FP operator + (const double& a, const FL_FP& b) { return FL_FP(a) + b; }
friend FL_FP operator - (const FL_FP& a, const double& b) { return a - FL_FP(b); }
friend FL_FP operator - (const double& a, const FL_FP& b) { return FL_FP(a) - b; }
friend FL_FP operator * (const FL_FP& a, const double& b) { return a * FL_FP(b); }
friend FL_FP operator * (const double& a, const FL_FP& b) { return FL_FP(a) * b; }
friend FL_FP operator / (const FL_FP& a, const double& b) { return a / FL_FP(b); }
friend FL_FP operator / (const double& a, const FL_FP& b) { return FL_FP(a) / b; }
// Arithmetic Operators with Assignment
FL_FP& operator += (const double& b) { return operator +=(FL_FP(b)); }
FL_FP& operator -= (const double& b) { return operator -=(FL_FP(b)); }
FL_FP& operator *= (const double& b) { return operator *=(FL_FP(b)); }
FL_FP& operator /= (const double& b) { return operator /=(FL_FP(b)); }
private:
uint64_t mInt;
uint64_t mFrac;
};
#endif