#ifndef FIXEDPOINT_H
#define FIXEDPOINT_H
//http://e...content-available-to-author-only...a.org/wiki/fixedb-point_arithmetic
//fixedb uses a specified number of bits for the integer part, and an underlying type.
// if you want a specific number of bits (7) for the fractional part, use
// "BitsIn<unsigned>::Size-7" for the integer part
//fixed uses a specified number as the denominator for the fractional part
//fixedb is faster, but fixed gives a bigger range if the fractional part isn't
// multiples of powers of two, and rounds at more predictable places.
//fixedb will round to the closest 128th of a dollar instead of the 100th.
//floating point only used as parameters to constructors (if desired) and in stream output
//I intend to get accurate output later, eventually
#include <cassert>
#include <iomanip>
#include <iostream>
#include <climits>
#include <limits>
#include <locale>
#include <sstream>
#include <type_traits>
#ifndef NFIXEDPOINTBOUNDS //both NFIXEDPOINTBOUNDS and NDEBUG must be defined to get these asserts
#define BOUNDASSERT(x)
#else
#define BOUNDASSERT(x) assert(x)
#endif
//compile time logarithms
template<unsigned long long num, unsigned long long base> struct ctlog { enum {value = ctlog<num/base, base>::value+1}; };
template<unsigned long long base> struct ctlog<0, base> { enum {value = 0}; };
//compile time exponents
template<unsigned long long num, unsigned long long exp> struct ctpow { enum {value = num*ctpow<num-1, exp>::value}; };
template<unsigned long long exp> struct ctpow<0, exp> { enum {value = 1}; };
//general case of maxvalue relies on signed rollover which is Undefined Behavior. Please specialize
template<class underlying, underlying one=1, bool biggerone=true> struct maxvalue { static const underlying value = maxvalue<underlying, one*2, (one*2>1)>::value; };
template<class underlying, underlying one> struct maxvalue<underlying, one, false> { static const underlying value = one-underlying(1); };
template<long long one> struct maxvalue<long long, one, true> { static const long long value = LLONG_MAX; };
template<unsigned long long one> struct maxvalue<unsigned long long, one, true> { static const unsigned long long value = ULLONG_MAX; };
template<long one> struct maxvalue<long, one, true> { static const long value = LONG_MAX; };
template<unsigned long one> struct maxvalue<unsigned long, one, true> { static const unsigned long value = ULONG_MAX; };
template<int one> struct maxvalue<int, one, true> { static const int value = INT_MAX; };
template<unsigned one> struct maxvalue<unsigned, one, true> { static const unsigned value = UINT_MAX; };
template<short one> struct maxvalue<short, one, true> { static const short value = SHRT_MAX; };
template<unsigned short one> struct maxvalue<unsigned short, one, true> { static const unsigned short value = USHRT_MAX; };
template<char one> struct maxvalue<char, one, true> { static const char value = CHAR_MAX; };
template<signed char one> struct maxvalue<signed char, one, true> { static const signed char value = SCHAR_MAX; };
template<unsigned char one> struct maxvalue<unsigned char, one, true> { static const unsigned char value = UCHAR_MAX; };
//used so I can pass values and integeral_const to the same function
template<class underlying>
struct carrier {
underlying value;
carrier(underlying v) :value(v) {}
operator underlying() {return value;}
};
// I KNOW I KNOW SHUT UP ALREADY COMPILER
#pragma warning(push)
#pragma warning(disable:4100) //warning C4100: 'times' : unreferenced formal parameter
#pragma warning(disable:4127) //warning C4127: conditional expression is constant
#pragma warning(disable:4146) //warning C4146: unary minus operator applied to unsigned type, result still unsigned
#pragma warning(disable:4365) //warning C4365: 'initializing' : conversion from [STUFF] to 'const ulhstype', signed/unsigned mismatch
#pragma warning(disable:4514) //warning C4514: [STUFF] : unreferenced inline function has been removed
#pragma warning(disable:4710) //warning C4710: [STUFF] : function not inlined (this pragma doesn't work)
#pragma warning(disable:4723) //warning C4723: potential divide by 0
#pragma warning(disable:4724) //warning C4724: potential mod by 0
#pragma GCC diagnostic ignored "-Wtype-limits"
//multiplication
//ignores signs, lhstype must be unsigned
template<class lhstype, class timestype>
std::pair<lhstype, lhstype> longmultiply(lhstype lhs, timestype times) {
static const lhstype bits = ctlog<maxvalue<lhstype>::value, 2>::value;
static const lhstype half = bits/2+bits%2;
static const lhstype mask = lhstype(1<<half)-1;
const lhstype umul((lhstype)(times.value>=0?times.value:-times.value));
// a b P1
// * c d
// ----------------
// e(a*d) f(b*d) P2
// g(a*c) h(b*c)
// -------------------------
// i j k l P3
// m n P4
const lhstype a(lhs>>half); //P1
const lhstype b(lhs&mask);
const lhstype c(umul>>half);
const lhstype d(umul&mask);
const lhstype e(a*d); //P2
const lhstype f(b*d);
const lhstype g(a*c);
const lhstype h(b*c);
const lhstype l(f&mask); //P3
const lhstype k((e&mask) + (h&mask) + (f>>half));
const lhstype j((g&mask) + (e>>half) + (h>>half) + (k>>half));
const lhstype i((g>>half) + (j>>half));
const lhstype m(((i&mask)<<half) | (j&mask)); //P4
const lhstype n(((k&mask)<<half) | l);
return std::pair<lhstype, lhstype>(m, n);
}
//mulitiplication specializations are to be preferred
template<class timestype>
std::pair<unsigned int, unsigned int> longmultiply(unsigned int lhs, timestype times) {
static_assert(sizeof(unsigned long long)>=sizeof(unsigned int)*2, "invalid assumption, comment out this overload");
typedef unsigned long long unsignedlonglong; //Because GCC is stupid with function-style casts
static const unsigned long long bits = CHAR_BIT*sizeof(unsigned int);
unsigned long long r = unsignedlonglong(lhs) * unsignedlonglong(times.value);
return std::pair<unsigned int, unsigned int>(r>>bits, r&((1ull<<bits)-1ull));
}
template<class timestype>
std::pair<unsigned short, unsigned short> longmultiply(unsigned short lhs, timestype times) {
static_assert(sizeof(unsigned int)>=sizeof(unsigned short)*2, "invalid assumption, comment out this overload");
static const unsigned bits = CHAR_BIT*sizeof(unsigned short);
unsigned int r = unsigned(lhs) * unsigned(times.value);
return std::pair<unsigned short, unsigned short>(r>>bits, r&((1<<bits)-1));
}
template<class timestype>
std::pair<unsigned char, unsigned char> longmultiply(unsigned char lhs, timestype times) {
static_assert(sizeof(unsigned int)>=sizeof(unsigned char)*2, "invalid assumption, comment out this overload");
static const unsigned bits = CHAR_BIT;
unsigned int r = unsigned(lhs) * unsigned(times.value);
return std::pair<unsigned char, unsigned char>(r>>bits, r&((1<<bits)-1));
}
//division
//ignores signs, lhstype must be unsigned
template<class lhstype, class dividetype>
lhstype longdivision(std::pair<lhstype, lhstype> lhs, dividetype divide) {
static const lhstype max = maxvalue<lhstype>::value;
static const lhstype bits = ctlog<maxvalue<lhstype>::value, 2>::value;
static const lhstype maxbits = max ^ (max>>2); // C000 0000
const lhstype udiv(divide.value>=0?divide.value:-divide.value);
BOUNDASSERT(lhs.first<udiv); //OVERFLOW
lhstype result = 0;
for(;;) {
if (lhs.first == 0)
return lhs.second/udiv+result;
lhstype c = 0;
int shift = 0;
for(; ; shift+=2) {
c = (lhs.first<<shift) | (shift?lhs.second>>(bits-shift):0);
if (c&maxbits || shift==bits-2)
break;
}
lhstype d = 0;
if (udiv <= c) {
d = (c/udiv);
if (shift>0) // *= (max>>shift)+1 should result in *= 1, so...
d *= (max>>shift)+1;
} else if (shift<bits-2) {
shift += 2;
d = (c/(udiv/4));
d *= (max>>shift)+1;
assert(d>1);
d -= 1; //sometimes it's one high?
} else {
d = 1;
}
assert(d>0);
const std::pair<lhstype, lhstype> e(longmultiply(d, divide));
assert((lhs.first > e.first) || (lhs.first==e.first && lhs.second>=e.second));
result += d;
if (e.second > lhs.second)
lhs.first -= e.first+1;
else
lhs.first -= e.first;
lhs.second -= e.second;
}
}
//division specializations are to be preferred
template<class dividetype>
unsigned int longdivision(std::pair<unsigned int, unsigned int> lhs, dividetype divide) {
static_assert(sizeof(unsigned long long)>=sizeof(unsigned int)*2, "invalid assumption, comment out this overload");
static const unsigned bits = CHAR_BIT*sizeof(unsigned int);
typedef unsigned long long unsignedlonglong; //Because GCC is stupid with function-style casts
unsigned long long t = unsignedlonglong(lhs.first) << bits | unsignedlonglong(lhs.second);
return unsigned(t/divide.value);
}
template<class dividetype>
unsigned short longdivision(std::pair<unsigned short, unsigned short> lhs, dividetype divide) {
static_assert(sizeof(unsigned int)>=sizeof(unsigned short)*2, "invalid assumption, comment out this overload");
static const unsigned bits = CHAR_BIT*sizeof(unsigned short);
unsigned int t = unsigned(lhs.first) << bits | unsigned(lhs.second);
typedef unsigned short unsignedshort; //Because GCC is stupid with function-style casts
return unsignedshort(t/divide.value);
}
template<class dividetype>
unsigned char longdivision(std::pair<unsigned char, unsigned char> lhs, dividetype divide) {
static_assert(sizeof(unsigned int)>=sizeof(unsigned char)*2, "invalid assumption, comment out this overload");
static const unsigned bits = CHAR_BIT*sizeof(unsigned char);
unsigned int t = unsigned(lhs.first) << bits | unsigned(lhs.second);
typedef unsigned char unsignedchar; //Because GCC is stupid with function-style casts
return unsignedchar(t/divide.value);
}
//do a multiplication and division
template<class lhstype, class timestype, class dividetype>
lhstype muldiv(lhstype lhs, timestype times, dividetype divide) {
typedef typename std::make_unsigned<lhstype>::type ulhstype;
const bool neg = (((lhs<0)!=(times.value<0))!=(divide.value<0));
const std::pair<ulhstype, ulhstype> a = longmultiply<ulhstype, timestype>((ulhstype)(lhs>=0?lhs:-lhs), times);
const lhstype b = (lhstype)longdivision(a, divide);
return (neg ? -b : b);
}
// base must be less than one tenth of the maximum value
//base 16384 is:
// INT_MAX/16384 = 262143.999938965 maximum value
// INT_MIN/16384 = 0 minimum value
// lg(16384, 2) = 14 binary digits after point
// 32-lg(16384, 2) = 18 binary digits above point
// 14/3.322 = 4.21 decimal digits after point
// 18/3.322 = 5.41 decimal digits above point (these should add to near 9.62)
template<class base = std::integral_constant<unsigned, 16384> >
class fixedp
{
static_assert(base::value>0, "base must be greater than zero!");
public:
typedef typename base::value_type underlying;
static const underlying fract = base::value;
static const underlying max_value = maxvalue<underlying>::value;
static const underlying min_value = std::numeric_limits<underlying>::is_signed ? -maxvalue<underlying>::value-1 : 0;
inline fixedp() :data(0) {}
inline fixedp(const fixedp& rhs) :data(rhs.data) {}
inline fixedp(underlying rhs) : data(rhs*fract) {BOUNDASSERT(rhs.data<=max_value/fract);}
#ifndef NO_HAS_DOUBLE
inline fixedp(double rhs) : data(underlying(rhs*fract+(1.0/fract/2.0))) {BOUNDASSERT(rhs<=max_value/fract && rhs>=min_value/fract);}
#endif
//second parameter ignored, used to signify that no math is required
inline fixedp(underlying numerator, underlying) : data(numerator) {}
template<class rhsbase>
inline fixedp(const fixedp<rhsbase>& rhs) {assign<rhsbase, rhsbase::value/fract, rhsbase::value%fract, fract/rhsbase::value, fract%rhsbase::value>::asn(*this, rhs);}
inline ~fixedp() {}
inline fixedp& operator=(const fixedp& rhs) { data = rhs.data; return *this; }
inline fixedp operator+(const fixedp& rhs) const { BOUNDASSERT((data>=0)?(max_value-data>=rhs.data):(rhs.data<min_value-data)); return fixedp(data+rhs.data,1); }
inline fixedp& operator+=(const fixedp& rhs) { BOUNDASSERT((data>=0)?(max_value-data>=rhs.data):(rhs.data<min_value-data)); data += rhs.data; return *this; }
inline fixedp operator-(const fixedp& rhs) const { BOUNDASSERT(((data<0)==(rhs.data<0)) && (data>=0)?(max_value-data>=rhs.data):(min_value-data<rhs.data)); return fixedp(data-rhs.data,1); }
inline fixedp& operator-=(const fixedp& rhs) { BOUNDASSERT(((data<0)==(rhs.data<0)) && (data>=0)?(max_value-data>=rhs.data):(min_value-data<rhs.data)); data -= rhs.data; return *this; }
inline fixedp operator*(underlying rhs) const { BOUNDASSERT(max_value/rhs.value>=data); return fixedp(data*rhs,1); }
inline fixedp& operator*=(underlying rhs) { BOUNDASSERT(max_value/rhs.value>=data); data *= rhs; return *this; }
inline fixedp operator*(const fixedp& rhs) const { return fixedp(muldiv(data, carrier<underlying>(rhs.data), base()), 1); }
inline fixedp& operator*=(const fixedp& rhs) { data = muldiv(data, carrier<underlying>(rhs.data), base()); return *this;}
inline fixedp operator/(underlying rhs) const {return fixedp(data/rhs,1); }
inline fixedp& operator/=(underlying rhs) { data /= rhs; return *this; }
inline fixedp operator/(const fixedp& rhs) const {return fixedp(muldiv(data, base(), carrier<underlying>(rhs.data)), 1); }
inline fixedp& operator/=(const fixedp& rhs) {data = muldiv(data, base(), carrier<underlying>(rhs.data)); return *this;}
inline fixedp operator+() const { return fixedp(+data,1); }
inline fixedp operator-() const { return fixedp(-data,1); }
inline fixedp& operator++() { BOUNDASSERT(max_value-fract>=data); data+=fract; return *this; }
inline fixedp operator++(int) const { BOUNDASSERT(max_value-fract>=data); return fixedp(data+fract,1); }
inline fixedp& operator--() { BOUNDASSERT(min_value+fract<=data); data-=fract; return *this; }
inline fixedp operator--(int) const { BOUNDASSERT(min_value+fract<=data); return fixedp(data-fract,1); }
inline bool operator==(const fixedp& rhs) const { return data==rhs.data; }
inline bool operator!=(const fixedp& rhs) const { return data!=rhs.data; }
inline bool operator>(const fixedp& rhs) const { return data>rhs.data; }
inline bool operator>=(const fixedp& rhs) const { return data>=rhs.data; }
inline bool operator<=(const fixedp& rhs) const { return data<=rhs.data; }
inline bool operator<(const fixedp& rhs) const { return data<rhs.data; }
inline bool operator!() const { return !data; }
inline fixedp operator~() const { return fixedp(~data,1); }
inline fixedp operator&(const fixedp& rhs) const { return fixedp(data&rhs.data,1); }
inline fixedp& operator&=(const fixedp& rhs) { data &= rhs.data; return *this; }
inline fixedp operator|(const fixedp& rhs) const { return fixedp(data|rhs.data,1); }
inline fixedp& operator|=(const fixedp& rhs) { data |= rhs.data; return *this; }
inline fixedp operator^(const fixedp& rhs) const { return fixedp(data^rhs.data,1); }
inline fixedp& operator^=(const fixedp& rhs) { data ^= rhs.data; return *this; }
inline fixedp operator<<(underlying rhs) const { BOUNDASSERT(rhs<CHAR_BIT*sizeof(underlying));BOUNDASSERT(max_value/(1<<rhs)>=data); return fixedp(data<<rhs,1); }
inline fixedp& operator<<=(underlying rhs) { BOUNDASSERT(rhs<CHAR_BIT*sizeof(underlying));BOUNDASSERT(max_value/(1<<rhs)>=data); data <<= rhs; return *this; }
inline fixedp operator>>(underlying rhs) const { BOUNDASSERT(rhs<CHAR_BIT*sizeof(underlying)); return fixedp(data>>rhs,1); }
inline fixedp& operator>>=(underlying rhs) { BOUNDASSERT(rhs<CHAR_BIT*sizeof(underlying)); data >>= rhs; return *this; }
//converts this type to any other type
template<typename convtype> convtype convert() const { return ((convtype)data)/((convtype)fract); }
//gets the internal data
inline underlying get_data() const {return data;}
//not the best IO (actually it's pretty bad), but it works
template <class e, class t> friend std::basic_ostream<e,t>& operator<<(std::basic_ostream<e,t>& out, const fixedp& rhs) {
out << rhs.data/fract;
underlying left = (rhs.data%fract)*(rhs.data<0?-1:1);
if (left!=0 || out.flags()&std::ios_base::showpoint) {
out << '.';
std::streamsize digits = out.precision();
do {
if (fract < max_value/2) {
left*=10;
out << char(left/fract+'0');
left = left%fract;
} else {
underlying t = left/(fract/10);
out << char(t+'0');
left = left%(fract/10)*10;
}
} while(--digits>0 && left!=0);
}
return out;
}
//not the best IO (actually it's pretty bad), but it works
template <class e, class t> friend std::basic_istream<e,t>& operator>>(std::basic_istream<e,t>& in, fixedp& rhs) {
underlying s;
in >> s;
if (max_value/fract < s)
in.setstate(std::basic_ios<e,t>::badbit | std::basic_ios<e,t>::failbit);
else
rhs.data = s*fract;
e next = e(in.peek());
if (in && next=='.') {
in.ignore(1);
s=0;
underlying pow10=1;
for(next=e(in.peek()); in && std::isdigit(next, in.getloc()); next=e(in.peek())) {
if (pow10>max_value/10) break;
if (pow10>fract) break;
s = s*(underlying)10+(underlying)(next-'0');
pow10 *= (underlying)10;
in.ignore(1);
}
rhs.data += muldiv(s, base(), carrier<underlying>(pow10)); //2677726520
if (in && std::isdigit(next, in.getloc()) && next>='5')
rhs.data += 1;
for(; in && std::isdigit(next, in.getloc()); next=e(in.peek()))
in.ignore(1);
}
return in;
}
protected:
//used for converting a fixedpoint of one base to another
template<class rhsbase> friend class fixedp;
underlying data;
template<class rhsbase, underlying div1, underlying mod1, underlying div2, underlying mod2>
struct assign { static inline void asn(fixedp& left, fixedp<rhsbase> rhs) {left.data = muldiv(rhs.data, rhsbase::value, base::value);} };
template<class rhsbase, underlying mod1, underlying div2>
struct assign<rhsbase, 0, mod1, div2, 0> { static inline void asn(fixedp& left, fixedp<rhsbase> rhs) {left.data = rhs.data/div2;} };
template<class rhsbase, underlying div1, underlying mod2>
struct assign<rhsbase, div1, 0, 0, mod2> { static inline void asn(fixedp& left, fixedp<rhsbase> rhs) {left.data = rhs.data*div1;} };
template<class rhsbase>
struct assign<rhsbase,1,0,1,0> { static inline void asn(fixedp& left, fixedp<rhsbase> rhs) {left.data = rhs.data;} };
};
#pragma warning(pop)
// // I would love to specialize this, but I heard I can't. Commented out for now.
//namespace std {
// template<class base>
// class numeric_limits<fixedp<base> > {
// typedef typename base::value_type underlying;
// typedef fixedp<base> myt;
// public:
// //static myt denorm_min( ) throw() {return myt(1,1);}
// static const int digits = numeric_limits<underlying>::digits;
// static const int digits10 = numeric_limits<underlying>::digits10;
// static myt epsilon() throw() {return myt(1,1);}
// static const float_denorm_style has_denorm = denorm_absent;
// static const bool has_denorm_loss = false;
// static const bool has_infinity = false;
// static const bool has_quiet_NaN = false;
// static const bool has_signaling_NaN = false;
// //static myt infinity() throw() {return myt(numeric_limits<underlying>::infinity,1);}
// static const bool is_bounded = true;
// static const bool is_exact = true;
// static const bool is_iec559 = false;
// static const bool is_integer = false;
// static const bool is_modulo = true;
// static const bool is_signed = numeric_limits<underlying>::is_signed;
// static const bool is_specialized = true;
// static myt lowest() throw() {return myt(numeric_limits<underlying>::lowest(),1);}
// static myt max() throw() {return myt(numeric_limits<underlying>::max(),1);}
// static const int max_digits10 = numeric_limits<underlying>::max_digits10+2;
// static const int max_exponent = numeric_limits<underlying>::max_exponent/base::value;
// static const int max_exponent10 = numeric_limits<underlying>::max_exponent10/base::value;
// static myt min() throw() {return myt(numeric_limits<underlying>::min(),1);}
// static const int min_exponent = numeric_limits<underlying>::min_exponent/base::value;
// static const int min_exponent10 = numeric_limits<underlying>::min_exponent10/base::value;
// //static Type quiet_NaN( ) throw() {return max();}
// static const int radix = 2;
// static myt round_error() throw() {return myt(1,1);}
// static const float_round_style round_style = numeric_limits<underlying>::round_style;
// //static myt signaling_NaN() throw() {return max();}
// static const bool tinyness_before = false;
// static const bool traps = false;
// };
//
// template<class base> struct is_arithmetic<fixedp<base>> : true_type {}
// template<class base> struct is_scalar<fixedp<base>> : true_type {}
// template<class base> struct is_signed<fixedp<base>> : is_signed<base::value_type>::value_type {}
// template<class base> struct is_unsigned<fixedp<base>> : is_unsigned<base::value_type>::value_type {}
// template<class <class, class> base, class underlying, underlying fract>
// struct make_signed<fixedp<base<underlying, fract>>> {typename fixed<base<make_signed<base::value_type>::type, base::value> type;}
// template<class <class, class> base, class underlying, underlying fract>
// struct make_unsigned<fixedp<base<underlying, fract>>> {typename fixed<base<make_unsigned<base::value_type>::type, base::value> type;}
//}
#endif //FIXEDPOINT_H
#include <cassert>
#include <iostream>
#include <sstream>
#include <ctime>
#include <vector>
static const unsigned data_size = 50000;
#ifdef _DEBUG
#define NFIXEDPOINTBOUNDS 1
static const unsigned max_test = 100000;
#else
static const unsigned max_test = 1000000;
#endif
bool accuracy() {
typedef fixedp<std::integral_constant<unsigned int, 2>> tinydenom;
typedef fixedp<std::integral_constant<int, INT_MAX>> signedpercent; //2147483647
typedef fixedp<std::integral_constant<unsigned int, UINT_MAX>> unsignedpercent; //4294967295
{
std::cout << "unsignedpercent a = .1234567890" << std::endl;
unsignedpercent a = .1234567890; //theory 0.1234567890
assert(a.get_data() == 530242871u); //actual 0.12345678894780576229095458984375
std::cout << "unsignedpercent b = 1.0" << std::endl;
unsignedpercent b = 1.0; //theory 1
assert(b.get_data() == 4294967295u); //actual 1.0
std::cout << "unsignedpercent c = a*b" << std::endl;
unsignedpercent c = a*b; //theory 0.1234567890
assert(c.get_data() == 530242871u); //actual 0.12345678894780576229095458984375
std::cout << "unsignedpercent d = .5" << std::endl;
unsignedpercent d = .5; //theory 0.5
assert(d.get_data() == 2147483647u); //actual 0.49999999988358467814596013122843
std::cout << "unsignedpercent e = d*d" << std::endl;
unsignedpercent e = d*d; //theory 0.25
assert(e.get_data() == 1073741823u); //actual 0.24999999982537701721894019684264
std::cout << "unsignedpercent f = a*a" << std::endl;
unsignedpercent f = a*a; //theory 0.015241578750190521
assert(f.get_data() == 65462082); //actual 0.015241578690531099841587967202437
}
{
std::cout << "signedpercent a = .1234567890" << std::endl;
signedpercent a = .1234567890; //theory .1234567890
assert(a.get_data() == 265121435); //actual 0.12345678877246416582375027510512
std::cout << "signedpercent b = 1.0" << std::endl;
signedpercent b = 1.0; //theory 1.0
assert(b.get_data() == 2147483647); //actual 1.0
std::cout << "signedpercent c = a*b" << std::endl;
signedpercent c = a*b; //theory 0.1234567890 (mul=07E6B74D 70329165, t=0FCD6E9B)
assert(c.get_data() == 265121435); //actual 0.12345678877246416582375027510512
std::cout << "signedpercent d = .5" << std::endl;
signedpercent d = .5; //theory 0.5
assert(d.get_data() == 1073741823); //actual 0.49999999976716935623771015379471
std::cout << "signedpercent e = d*d" << std::endl;
signedpercent e = d*d; //theory 0.25
assert(e.get_data() == 536870911); //actual 0.24999999965075403435656523069207
std::cout << "signedpercent f = -.5" << std::endl;
signedpercent f = -.5; //theory -0.5
assert(f.get_data() == -1073741823); //actual -0.49999999976716935623771015379471
std::cout << "signedpercent g = e*f" << std::endl;
signedpercent g = e*f; //theory -0.125
assert(g.get_data() == -268435455); //actual -0.12499999959254637341599276914075
std::cout << "signedpercent h = a*a" << std::endl;
signedpercent h = a*a; //theory 0.015241578750190521
assert(h.get_data() == 32731040); //actual 0.015241578228418518895478229455407
}
{
std::cout << "tinydenom k = .5" << std::endl;
tinydenom k = .5; //theory 0.5
assert(k.get_data() == 1); //actual 0.5
std::cout << "tinydenom l = k*k" << std::endl;
tinydenom l = k*k; //theory 0.25
assert(l.get_data() == 0); //actual 0.0
std::cout << "tinydenom m = 2147483646u" << std::endl;
tinydenom m = 2147483646u; //theory 2147483646.0
assert(m.get_data() == 4294967292u); //actual 2147483646.0
std::cout << "tinydenom n = k*m" << std::endl;
tinydenom n = k*m; //theory 1073741823
assert(n.get_data() == 2147483646u); //actual 1073741823.0
}
std::stringstream ss;
std::string t;
//float f(0);
tinydenom td(0u);
signedpercent sp(0);
unsignedpercent up(0u);
ss.clear();
ss << "2147483647.1234567890";
std::cout << "ss >> td\n";
ss >> td;
assert(td.get_data() == 4294967294u); //4294967295u => 2147483647
ss.clear();
ss << td;
std::cout << "ss << td\n";
ss >> t;
assert(t=="2147483647");
ss.clear();
ss << "0.1234567890";
ss >> sp;
assert(sp.get_data() == 265121435); //265121435 => 0.12345678877246416582375027510512
ss.clear();
ss << std::setprecision(9) << sp;
ss >> t;
assert(t=="0.123456789");
ss.clear();
ss << "0.1234567890";
std::cout << "ss >> up\n";
ss >> up;
assert(up.get_data() == 530242871u); // 530242871u => 0.12345678897655028593180474963314
ss.clear();
std::cout << "ss << up\n";
ss << std::setprecision(9) << up;
ss >> t;
assert(t=="0.123456789");
return true;
}
template<class Type, class integer>
void Speed(const char* name)
{
clock_t start, stop;
Type total;
std::cout << "timing " << name << std::endl;
srand(0);
std::vector<Type> data(data_size);
for(unsigned int i=0; i<data_size; ++i)
data[i] += Type(double(rand())/128.0+1.0);
std::cout << "= ";
total=integer(0);
start = clock();
for(unsigned i=0; i<max_test; ++i)
total += data[i%data_size];
stop = clock();
std::cout << double(stop-start)/CLOCKS_PER_SEC << '\t' << total << std::endl;
std::cout << "+ ";
total=integer(0);
start = clock();
for(unsigned i=0; i<max_test; ++i)
total += data[i%data_size] + data[i*2%data_size];
stop = clock();
std::cout << double(stop-start)/CLOCKS_PER_SEC << '\t' << total << std::endl;
std::cout << "* ";
total=integer(0);
start = clock();
for(unsigned i=0; i<max_test; ++i)
total += data[i%data_size] * data[i*2%data_size];
stop = clock();
std::cout << double(stop-start)/CLOCKS_PER_SEC << '\t' << total << std::endl;
std::cout << "/ ";
total=integer(0);
start = clock();
for(unsigned i=0; i<max_test; ++i)
total += data[i%data_size] / data[i*2%data_size];
stop = clock();
std::cout << double(stop-start)/CLOCKS_PER_SEC << '\t' << total << std::endl;
}
int main() {
typedef fixedp<std::integral_constant<char, 2>> smdenom;
typedef fixedp<std::integral_constant<unsigned int, 11047>> prime;
typedef fixedp<std::integral_constant<int, 65536>> pow2;
typedef fixedp<std::integral_constant<int, 1000>> notpow2;
typedef fixedp<std::integral_constant<unsigned int, 429496729>> bigdenom; //0x19999999
typedef fixedp<std::integral_constant<short, 16>> slow2; //0x19999999
typedef fixedp<std::integral_constant<short, 19>> slown2; //0x19999999
const bigdenom verify0(822083583, 1); //0822083583 0x30FFFFFF 1.9140625003456079871565215110171
const bigdenom verify1(822083583, 1); //0822083583 0x30FFFFFF 1.9140625003456079871565215110171
const bigdenom verify2 = verify0*verify1; //1573519358 0x5DC9FFFE 3.6636352543676764532472143693555
const bigdenom verify3 = verify2/verify1; //0822083582 0x30FFFFFE 1.9140624980173015473652186999543
std::cout << "0x822083583*0x822083583 = 3.663635254 = " << verify2 << std::endl;
std::cout << "0x822083583/0x822083583 = 1.914062498 = " << verify3 << std::endl;
std::cout << "UINT_MAX = " << UINT_MAX << " = " << ((unsigned)(UINT_MAX*1.0)) << std::endl;
std::cout << "INT_MAX = " << INT_MAX << " = " << maxvalue<int>::value << std::endl;
std::cout << "signed bits = " << "31 = " << ctlog<maxvalue<int>::value, 2>::value << std::endl;
std::cout << "half signed bits = " << "16 = " << ctlog<maxvalue<int>::value, 2>::value/2+ctlog<maxvalue<int>::value, 2>::value%2 << std::endl;
assert(accuracy());
Speed<double, int>("double");
Speed<float, int>("float");
Speed<pow2, int>("int pow2");
Speed<notpow2, int>("int not2");
Speed<slow2, short>("short pow2");
Speed<slown2, short>("short not2");
return 0;
}