Project

General

Profile

Download (13.4 KB) Statistics
| Branch: | Tag: | Revision:
835f4592 David Sorber
7fa2f28e David Sorber
#ifndef __FIXED_H_
#define __FIXED_H_
835f4592 David Sorber
11ae9ac5 David Sorber
#include <cctype>
835f4592 David Sorber
#include <cmath>
#include <cstdint>
c7e0510c David Sorber
#include <cstdlib>
11ae9ac5 David Sorber
#include <iomanip>
#include <iostream>
835f4592 David Sorber
#include <limits>
11ae9ac5 David Sorber
#include <sstream>
c7e0510c David Sorber
#include <stdexcept>
835f4592 David Sorber
#include <type_traits>

852d0468 David Sorber
#ifdef USE_INT128
#include "int128.h"
#endif

7fa2f28e David Sorber
#if __GNUC__ >= 3
c7e0510c David Sorber
#define __unlikely(cond) __builtin_expect((cond), 0)
#define __likely(cond) __builtin_expect((cond), 1)
7fa2f28e David Sorber
#else
c7e0510c David Sorber
#define __unlikely(cond) (cond)
#define __likely(cond) (cond)
7fa2f28e David Sorber
#endif

852d0468 David Sorber
template<typename T>
constexpr T calculateMax(size_t decimal_digits)
{
T val = 0;
for (uint32_t idx = 0; idx < decimal_digits; ++idx)
{
val *= 10;
val += 9;
}
return val;
}


template<typename IntegerType, typename FractionalType,
typename StrToIntegerTypeFunc,
typename StrToFracTypeFunc>
c7e0510c David Sorber
class fixed
835f4592 David Sorber
{
c7e0510c David Sorber
static_assert(std::is_integral<IntegerType>::value,
"IntegerType must be an integral type");
static_assert(std::is_integral<FractionalType>::value,
"FractionalType must be an integral type");

static_assert(std::is_signed<IntegerType>::value,
"IntegerType must be a signed type");
static_assert(std::is_unsigned<FractionalType>::value,
"FractionalType must be an unsigned type");

835f4592 David Sorber
public:

static constexpr size_t integer_bits = sizeof(IntegerType) * 8;
static constexpr size_t fractional_bits = sizeof(FractionalType) * 8;
c7e0510c David Sorber
static constexpr size_t integer_decimal_digits =
std::floor(std::log10(std::numeric_limits<IntegerType>::max()));
static constexpr size_t fractional_decimal_digits =
std::floor(std::log10(std::numeric_limits<FractionalType>::max()));

852d0468 David Sorber
static constexpr IntegerType MAX_INTEGER_VALUE =
(calculateMax<IntegerType>(integer_decimal_digits));
static constexpr IntegerType MIN_INTEGER_VALUE = 0;
c7e0510c David Sorber
852d0468 David Sorber
static constexpr FractionalType MAX_FRACTIONAL_VALUE =
(calculateMax<FractionalType>(fractional_decimal_digits));
static constexpr FractionalType MIN_FRACTIONAL_VALUE = 0;
c7e0510c David Sorber
11ae9ac5 David Sorber
static const uint64_t SCALE_VALUES[20];
c7e0510c David Sorber
11ae9ac5 David Sorber
// Constructors
835f4592 David Sorber
fixed()
c7e0510c David Sorber
: m_integer(0),
m_fractional(0)
11ae9ac5 David Sorber
{}
c7e0510c David Sorber
11ae9ac5 David Sorber
fixed(IntegerType integerVal)
c7e0510c David Sorber
: m_integer(__checkIntOverflow(integerVal)),
m_fractional(0)
11ae9ac5 David Sorber
{}
c7e0510c David Sorber
835f4592 David Sorber
fixed(IntegerType integerVal, FractionalType fractionalVal)
c7e0510c David Sorber
: m_integer(__checkIntOverflow(integerVal)),
m_fractional(__checkFracOverflow(fractionalVal))
11ae9ac5 David Sorber
{
// Scale the fractional value appropriately
uint32_t idx = 0;
for (; idx < fractional_decimal_digits; ++idx)
{
if (SCALE_VALUES[idx] > m_fractional)
{
break;
}
}
c7e0510c David Sorber
m_fractional = __checkFracOverflow(
m_fractional * SCALE_VALUES[fractional_decimal_digits - idx]);
11ae9ac5 David Sorber
}
c7e0510c David Sorber
835f4592 David Sorber
// Default copy constructor, and assignment operator
c7e0510c David Sorber
fixed(const fixed&) = default;
fixed& operator=(const fixed&) = default;

11ae9ac5 David Sorber
// Reassign value to type
void assign(IntegerType integerVal, FractionalType fractionalVal)
{
m_integer = __checkIntOverflow(integerVal);
// Scale the fractional value appropriately
uint32_t idx = 0;
for (; idx < fractional_decimal_digits; ++idx)
{
if (SCALE_VALUES[idx] > fractionalVal)
{
break;
}
}
c7e0510c David Sorber
m_fractional = __checkFracOverflow(
fractionalVal * SCALE_VALUES[fractional_decimal_digits - idx]);
11ae9ac5 David Sorber
}
c7e0510c David Sorber
11ae9ac5 David Sorber
// Parse value from string input
7fa2f28e David Sorber
uint32_t parse(const char* input)
835f4592 David Sorber
{
11ae9ac5 David Sorber
char* endPtr = nullptr;
852d0468 David Sorber
//~ m_integer = __checkIntOverflow(strtoll(input, &endPtr, 10));
m_integer = __checkIntOverflow(strto_inttype(input, &endPtr, 10));
11ae9ac5 David Sorber
m_fractional = 0;
c7e0510c David Sorber
11ae9ac5 David Sorber
if (std::isdigit(*endPtr))
{
throw std::out_of_range("Integer value is out of range.");
}
c7e0510c David Sorber
11ae9ac5 David Sorber
// If the ending char is a period we can now parse the fractional part
if (*endPtr == '.')
{
char* fracEndPtr = nullptr;
c7e0510c David Sorber
FractionalType fracTemp =
852d0468 David Sorber
//~ __checkFracOverflow(strtoull(endPtr + 1, &fracEndPtr, 10));
__checkFracOverflow(strto_fractype(endPtr + 1, &fracEndPtr, 10));
11ae9ac5 David Sorber
uint32_t fracLen = (fracEndPtr - endPtr) - 1;
c7e0510c David Sorber
11ae9ac5 David Sorber
fracLen = fractional_decimal_digits - fracLen;
c7e0510c David Sorber
11ae9ac5 David Sorber
m_fractional = __checkFracOverflow(fracTemp * SCALE_VALUES[fracLen]);
7fa2f28e David Sorber
endPtr = fracEndPtr;
11ae9ac5 David Sorber
}
c7e0510c David Sorber
// Calculate and return overall length
7fa2f28e David Sorber
return (endPtr - input);
835f4592 David Sorber
}
c7e0510c David Sorber
835f4592 David Sorber
constexpr inline fixed operator-() const noexcept = delete;
11ae9ac5 David Sorber
constexpr inline fixed operator!() const noexcept = delete;
constexpr inline fixed operator~() const noexcept = delete;
835f4592 David Sorber
inline fixed& operator+=(const fixed& y) noexcept = delete;
inline fixed& operator-=(const fixed& y) noexcept = delete;
inline fixed& operator*=(const fixed& y) noexcept = delete;
c7e0510c David Sorber
inline fixed& operator/=(const fixed& y) noexcept = delete;

835f4592 David Sorber
// Comparison operators
852d0468 David Sorber
template<typename I, typename F, typename STI, typename STF>
c7e0510c David Sorber
friend constexpr inline bool operator==(
852d0468 David Sorber
const fixed<I, F, STI, STF>& x, const fixed<I, F, STI, STF>& y) noexcept;
c7e0510c David Sorber
852d0468 David Sorber
template<typename I, typename F, typename STI, typename STF>
c7e0510c David Sorber
friend constexpr inline bool operator!=(
852d0468 David Sorber
const fixed<I, F, STI, STF>& x, const fixed<I, F, STI, STF>& y) noexcept;
c7e0510c David Sorber
852d0468 David Sorber
template<typename I, typename F, typename STI, typename STF>
c7e0510c David Sorber
friend constexpr inline bool operator<(
852d0468 David Sorber
const fixed<I, F, STI, STF>& x, const fixed<I, F, STI, STF>& y) noexcept;
c7e0510c David Sorber
852d0468 David Sorber
template<typename I, typename F, typename STI, typename STF>
c7e0510c David Sorber
friend constexpr inline bool operator>(
852d0468 David Sorber
const fixed<I, F, STI, STF>& x, const fixed<I, F, STI, STF>& y) noexcept;
c7e0510c David Sorber
852d0468 David Sorber
template<typename I, typename F, typename STI, typename STF>
c7e0510c David Sorber
friend constexpr inline bool operator<=(
852d0468 David Sorber
const fixed<I, F, STI, STF>& x, const fixed<I, F, STI, STF>& y) noexcept;
c7e0510c David Sorber
852d0468 David Sorber
template<typename I, typename F, typename STI, typename STF>
c7e0510c David Sorber
friend constexpr inline bool operator>=(
852d0468 David Sorber
const fixed<I, F, STI, STF>& x, const fixed<I, F, STI, STF>& y) noexcept;
c7e0510c David Sorber
11ae9ac5 David Sorber
// Output stream operator
852d0468 David Sorber
template<typename I, typename F, typename STI, typename STF>
c7e0510c David Sorber
friend inline std::ostream& operator<<(
852d0468 David Sorber
std::ostream& os, const fixed<I, F, STI, STF>& rhs);
c7e0510c David Sorber
835f4592 David Sorber
private:

852d0468 David Sorber
static StrToIntegerTypeFunc strto_inttype;
static StrToFracTypeFunc strto_fractype;

11ae9ac5 David Sorber
static inline IntegerType __checkIntOverflow(IntegerType integerVal)
{
7fa2f28e David Sorber
if (__unlikely(integerVal > MAX_INTEGER_VALUE))
11ae9ac5 David Sorber
{
std::ostringstream msg;
msg << "Integer value: " << integerVal << " exceeds maximum "
c7e0510c David Sorber
<< "integer range of type (" << MAX_INTEGER_VALUE << ")!";
11ae9ac5 David Sorber
throw std::out_of_range(msg.str());
}
return integerVal;
}
c7e0510c David Sorber
11ae9ac5 David Sorber
static inline FractionalType __checkFracOverflow(FractionalType fractionalVal)
{
7fa2f28e David Sorber
if (__unlikely(fractionalVal > MAX_FRACTIONAL_VALUE))
11ae9ac5 David Sorber
{
std::ostringstream msg;
msg << "Fractional value: " << fractionalVal << " exceeds maximum "
c7e0510c David Sorber
<< "fractional range of type (" << MAX_FRACTIONAL_VALUE << ")!";
11ae9ac5 David Sorber
throw std::out_of_range(msg.str());
}
return fractionalVal;
}

835f4592 David Sorber
IntegerType m_integer;
FractionalType m_fractional;
};

852d0468 David Sorber
// Functor for calling std::strtoll()
struct strtoll_ftor {
inline int64_t operator()(const char* str, char** str_end, int base)
{
return std::strtoll(str, str_end, base);
}
};

// Functor for calling std::strtoull()
struct strtoull_ftor {
inline uint64_t operator()(const char* str, char** str_end, int base)
{
return std::strtoull(str, str_end, base);
}
};

#ifdef USE_INT128

// Functor for calling strtoll_128()
struct strtoll_128_ftor {
inline int64_t operator()(const char* str, char** str_end, int base)
{
//~ return strtoll_128(str, str_end, base);
return strtoll_128_b10opt(str, str_end, base);
}
};

// Functor for calling strtoull_128()
struct strtoull_128_ftor {
inline uint64_t operator()(const char* str, char** str_end, int base)
{
//~ return strtoull_128(str, str_end, base);
return strtoull_128_b10opt(str, str_end, base);
}
};

#endif


11ae9ac5 David Sorber
// Predefined types
852d0468 David Sorber
using fixed_8_8 = fixed<int8_t, uint8_t, strtoll_ftor, strtoull_ftor>;
using fixed_8_16 = fixed<int8_t, uint16_t, strtoll_ftor, strtoull_ftor>;
using fixed_8_32 = fixed<int8_t, uint32_t, strtoll_ftor, strtoull_ftor>;
using fixed_8_64 = fixed<int8_t, uint64_t, strtoll_ftor, strtoull_ftor>;

using fixed_16_8 = fixed<int16_t, uint8_t, strtoll_ftor, strtoull_ftor>;
using fixed_16_16 = fixed<int16_t, uint16_t, strtoll_ftor, strtoull_ftor>;
using fixed_16_32 = fixed<int16_t, uint32_t, strtoll_ftor, strtoull_ftor>;
using fixed_16_64 = fixed<int16_t, uint64_t, strtoll_ftor, strtoull_ftor>;

using fixed_32_8 = fixed<int32_t, uint8_t, strtoll_ftor, strtoull_ftor>;
using fixed_32_16 = fixed<int32_t, uint16_t, strtoll_ftor, strtoull_ftor>;
using fixed_32_32 = fixed<int32_t, uint32_t, strtoll_ftor, strtoull_ftor>;
using fixed_32_64 = fixed<int32_t, uint64_t, strtoll_ftor, strtoull_ftor>;

using fixed_64_8 = fixed<int64_t, uint8_t, strtoll_ftor, strtoull_ftor>;
using fixed_64_16 = fixed<int64_t, uint16_t, strtoll_ftor, strtoull_ftor>;
using fixed_64_32 = fixed<int64_t, uint32_t, strtoll_ftor, strtoull_ftor>;
using fixed_64_64 = fixed<int64_t, uint64_t, strtoll_ftor, strtoull_ftor>;

#ifdef USE_INT128
using fixed_128_128 = fixed<int128_t, uint128_t, strtoll_128_ftor, strtoull_128_ftor>;
#endif
835f4592 David Sorber
11ae9ac5 David Sorber
// Precomputed scale value constants
852d0468 David Sorber
template<typename I, typename F, typename STI, typename STF>
const uint64_t fixed<I, F, STI, STF>::SCALE_VALUES[20] =
11ae9ac5 David Sorber
{
c7e0510c David Sorber
/* 0 */ 1ULL,
/* 1 */ 10ULL,
/* 2 */ 100ULL,
11ae9ac5 David Sorber
/* 3 */ 1000ULL,
/* 4 */ 10000ULL,
/* 5 */ 100000ULL,
/* 6 */ 1000000ULL,
/* 7 */ 10000000ULL,
/* 8 */ 100000000ULL,
/* 9 */ 1000000000ULL,
/* 10 */ 10000000000ULL,
/* 11 */ 100000000000ULL,
/* 12 */ 1000000000000ULL,
/* 13 */ 10000000000000ULL,
/* 14 */ 100000000000000ULL,
/* 15 */ 1000000000000000ULL,
/* 16 */ 10000000000000000ULL,
/* 17 */ 100000000000000000ULL,
/* 18 */ 1000000000000000000ULL,
/* 19 */ 10000000000000000000ULL
};

852d0468 David Sorber
template<typename I, typename F, typename STI, typename STF>
c7e0510c David Sorber
constexpr inline bool operator==(
852d0468 David Sorber
const fixed<I, F, STI, STF>& x, const fixed<I, F, STI, STF>& y) noexcept
835f4592 David Sorber
{
return (x.m_integer == y.m_integer && x.m_fractional == y.m_fractional);
}

852d0468 David Sorber
template<typename I, typename F, typename STI, typename STF>
c7e0510c David Sorber
constexpr inline bool operator!=(
852d0468 David Sorber
const fixed<I, F, STI, STF>& x, const fixed<I, F, STI, STF>& y) noexcept
835f4592 David Sorber
{
11ae9ac5 David Sorber
return (! (x == y));
835f4592 David Sorber
}

852d0468 David Sorber
template<typename I, typename F, typename STI, typename STF>
c7e0510c David Sorber
constexpr inline bool operator<(
852d0468 David Sorber
const fixed<I, F, STI, STF>& x, const fixed<I, F, STI, STF>& y) noexcept
835f4592 David Sorber
{
if (x.m_integer == y.m_integer)
{
return (x.m_fractional < y.m_fractional);
}
else
{
return (x.m_integer < y.m_integer);
}
c7e0510c David Sorber
return false;
835f4592 David Sorber
}

852d0468 David Sorber
template<typename I, typename F, typename STI, typename STF>
c7e0510c David Sorber
constexpr inline bool operator>(
852d0468 David Sorber
const fixed<I, F, STI, STF>& x, const fixed<I, F, STI, STF>& y) noexcept
835f4592 David Sorber
{
if (x.m_integer == y.m_integer)
{
return (x.m_fractional > y.m_fractional);
}
else
{
return (x.m_integer > y.m_integer);
}
c7e0510c David Sorber
return false;
835f4592 David Sorber
}

852d0468 David Sorber
template<typename I, typename F, typename STI, typename STF>
c7e0510c David Sorber
constexpr inline bool operator<=(
852d0468 David Sorber
const fixed<I, F, STI, STF>& x, const fixed<I, F, STI, STF>& y) noexcept
835f4592 David Sorber
{
if (x.m_integer == y.m_integer)
{
return (x.m_fractional <= y.m_fractional);
}
else
{
return (x.m_integer < y.m_integer);
}
c7e0510c David Sorber
return false;
835f4592 David Sorber
}

852d0468 David Sorber
template<typename I, typename F, typename STI, typename STF>
c7e0510c David Sorber
constexpr inline bool operator>=(
852d0468 David Sorber
const fixed<I, F, STI, STF>& x, const fixed<I, F, STI, STF>& y) noexcept
835f4592 David Sorber
{
if (x.m_integer == y.m_integer)
{
11ae9ac5 David Sorber
return (x.m_fractional >= y.m_fractional);
835f4592 David Sorber
}
else
{
return (x.m_integer > y.m_integer);
}
c7e0510c David Sorber
835f4592 David Sorber
return false;
}

11ae9ac5 David Sorber
// Addition -- not yet supported
852d0468 David Sorber
template<typename I, typename F, typename STI, typename STF>
constexpr inline fixed<I, F, STI, STF> operator+(
const fixed<I, F, STI, STF>& x, const fixed<I, F, STI, STF>& y) noexcept = delete;
835f4592 David Sorber
11ae9ac5 David Sorber
// Subtraction -- not yet supported
852d0468 David Sorber
template<typename I, typename F, typename STI, typename STF>
constexpr inline fixed<I, F, STI, STF> operator-(
const fixed<I, F, STI, STF>& x, const fixed<I, F, STI, STF>& y) noexcept = delete;
835f4592 David Sorber
// Multiplication
852d0468 David Sorber
template<typename I, typename F, typename STI, typename STF>
constexpr inline fixed<I, F, STI, STF> operator*(
const fixed<I, F, STI, STF>& x, const fixed<I, F, STI, STF>& y) noexcept = delete;
835f4592 David Sorber
11ae9ac5 David Sorber
// Division -- not yet supported
852d0468 David Sorber
template<typename I, typename F, typename STI, typename STF>
constexpr inline fixed<I, F, STI, STF> operator/(
const fixed<I, F, STI, STF>& x, const fixed<I, F, STI, STF>& y) noexcept = delete;
835f4592 David Sorber
11ae9ac5 David Sorber
// Stream output
852d0468 David Sorber
template<typename I, typename F, typename STI, typename STF>
inline std::ostream& operator<<(std::ostream& os, const fixed<I, F, STI, STF>& rhs)
11ae9ac5 David Sorber
{
c7e0510c David Sorber
return os << std::fixed << rhs.m_integer << "."
852d0468 David Sorber
<< std::setw(fixed<I, F, STI, STF>::fractional_decimal_digits)
c7e0510c David Sorber
<< std::setfill('0') << rhs.m_fractional;
11ae9ac5 David Sorber
}

c7e0510c David Sorber
#endif // FIXED_H_