Code:
#include <cmath>
#include <iomanip>
#include <iostream>
#include <limits>
#include <sstream>
#include <string>
typedef unsigned long ui32; // whatever 32 bit type
typedef unsigned long long ui64; // whatever 64 bit type
template
<
typename T
>
struct get_bad_alias
{
};
template <> struct get_bad_alias<float>
{
typedef ui32 type;
};
template <> struct get_bad_alias<double>
{
typedef ui64 type;
};
template
<
typename T
>
bool compare_test
(
T a,
T b,
T r,
T e
)
{
using std::abs;
if(abs(a - b) < e)
{
return(true);
}
T re(0);
if(abs(b) > abs(a))
{
re = abs((a - b) / b);
}
else
{
re = abs((a - b) / a);
}
if(re <= r)
{
return(true);
}
return(false);
}
template
<
typename T
>
std::string fppair
(
const T & a,
const T & b
)
{
std::ostringstream out;
out.setf(std::ios::fixed, std::ios::floatfield);
out.precision(16);
out << '(' << a << ',' << ' ' << b << ')';
return(out.str());
}
template
<
typename T
>
void dump
(
T a,
T b,
T r,
T e
)
{
using std::cout;
T diff(std::numeric_limits<T>::epsilon());
cout << fppair(a, b) << ' ' << compare_test(a + diff, b, r, e) << '\n';
cout << fppair(a, b) << ' ' << compare_test(a, b, r, e) << '\n';
cout << fppair(a, b) << ' ' << compare_test(a - diff, b, r, e) << '\n';
cout << '\n';
}
template
<
typename T
>
void generate_on_a
(
T a,
T b,
T r,
T e
)
{
typedef typename get_bad_alias<T>::type alias;
alias & aliasa(*reinterpret_cast<alias *>(&a));
aliasa -= 2;
dump(a, b, r, e);
++aliasa;
dump(a, b, r, e);
++aliasa;
dump(a, b, r, e);
++aliasa;
dump(a, b, r, e);
++aliasa;
dump(a, b, r, e);
}
template
<
typename T
>
void generate_on_b
(
T a,
T b,
T r,
T e
)
{
typedef typename get_bad_alias<T>::type alias;
alias & aliasb(*reinterpret_cast<alias *>(&b));
aliasb -= 2;
dump(a, b, r, e);
++aliasb;
dump(a, b, r, e);
++aliasb;
dump(a, b, r, e);
++aliasb;
dump(a, b, r, e);
++aliasb;
dump(a, b, r, e);
}
template
<
typename T
>
void generate
(
T a,
T b,
T r,
T e
)
{
generate_on_a(a, b, r, e);
std::cout << "\n\n";
generate_on_b(a, b, r, e);
std::cout << "\n\n\n\n";
}
template
<
typename T
>
void epsilon_test
(
T a,
T b
)
{
generate(a, b, std::numeric_limits<T>::epsilon(), std::numeric_limits<T>::epsilon());
}
int main()
{
std::cout << std::boolalpha;
epsilon_test(+0.250f, +0.250f);
epsilon_test(+0.250f, -0.250f);
epsilon_test(-0.250f, +0.250f);
epsilon_test(-0.250f, -0.250f);
epsilon_test(+0.250, +0.250);
epsilon_test(+0.250, -0.250);
epsilon_test(-0.250, +0.250);
epsilon_test(-0.250, -0.250);
return(0);
}