#include <type_traits>
#include <cctype>
#include <cfloat>
#include <limits>
#include <bitset>
#include <iostream>
#include <iomanip>
#include <SFML/Graphics.hpp>
template <size_t size>
struct Types {
typedef void int_type;
};
template <>
struct Types<4> {
typedef int int_type;
typedef unsigned int uint_type;
};
template <>
struct Types<8> {
typedef __int64 int_type;
typedef unsigned __int64 uint_type;
};
typedef Types<4>::int_type int32;
typedef Types<4>::uint_type uint32;
typedef Types<8>::int_type int64;
typedef Types<8>::uint_type uint64;
template <typename T>
class Float
{
typedef typename Types<sizeof(T)>::uint_type bit_type;
typedef typename T value_type;
static const bit_type bit_count = 8 * sizeof(value_type);
static const bit_type fraction_count = std::numeric_limits<value_type>::digits - 1;
static const bit_type exponent_count = bit_count - 1 - fraction_count;
static const bit_type sign_mask = static_cast<bit_type>(1) << (bit_count - 1);
static const bit_type fraction_mask = ~static_cast<bit_type>(0) >> (exponent_count + 1);
static const bit_type exponent_mask = ~(sign_mask | fraction_mask);
union
{
value_type value;
bit_type bit;
struct {
bit_type fraction : fraction_count;
bit_type exponent : exponent_count;
bit_type sign : 1;
};
};
static bit_type to_biased(bit_type bits) {
return (sign_mask & bits) ? (~bits + 1) : (sign_mask | bits);
}
public:
explicit Float(const T& x) { value = x; }
enum { max_ulps = 4 };
const value_type &data_float() const { return value; }
const bit_type &data_bits() const { return bit; }
bit_type exponent_bits() const { return (exponent | bit); }
bit_type sign_bits() const { return sign; }
bit_type fraction_bits() const { return fraction; }
bool is_infinity()
{
return ((bit & ~sign_mask) == exponent_mask);
}
bool is_nan() const {
bool nan = true;
nan &= (exponent_mask & bit) == exponent_mask;
nan &= (fraction_mask & bit) != static_cast<bit_type>(0);
return nan;
}
static bit_type distance(bit_type bits1, bit_type bits2) {
const bit_type biased1 = to_biased(bits1);
const bit_type biased2 = to_biased(bits2);
return (biased1 >= biased2) ? (biased1 - biased2) : (biased2 - biased1);
}
};
typedef Float<float> Float32;
typedef Float<double> Float64;
template <typename T>
struct is_float : std::false_type {};
template <typename T>
struct is_float<Float<T>> : std::true_type {};
// -- debug prints --
template <typename T> static inline
std::enable_if_t<is_float<T>::value, std::ostream&>
operator<<(std::ostream& os, const T& f)
{
os << std::fixed << std::setprecision(25) << std::left;
os << "float = " << std::setw(10) << std::dec << f.data_float() << "\n";
os << "bits = " << std::setw(10) << std::dec << f.data_bits() << " : 0x"
<< std::setw(10) << std::hex << f.data_bits() << " : "
<< std::setw(32) << std::bitset<32>(f.data_bits()) << "\n";
os << "sign = " << std::setw(10) << std::dec << f.sign_bits() << " : 0x"
<< std::setw(10) << std::hex << f.sign_bits() << " : "
<< std::setw(32) << std::bitset<32>(f.sign_bits()) << "\n";
os << "exponent = " << std::setw(10) << std::dec << f.exponent_bits() << " : 0x"
<< std::setw(10) << std::hex << f.exponent_bits() << " : "
<< std::setw(32) << std::bitset<32>(f.exponent_bits()) << "\n";
os << "fraction = " << std::setw(10) << std::dec << f.fraction_bits() << " : 0x"
<< std::setw(10) << std::hex << f.fraction_bits() << " : "
<< std::setw(32) << std::bitset<32>(f.fraction_bits()) << "\n\n";
os << std::resetiosflags(std::ios_base::fixed | std::ios_base::floatfield) << std::dec;
return os;
}
static inline std::ostream& operator<<(std::ostream& os, const sf::Transform& m)
{
const float* data = m.getMatrix();
os << std::fixed << std::setprecision(5) << std::right;
for (unsigned int c = 0; c < 4; ++c) {
os << "[";
for (unsigned int r = 0; r < 4; ++r) {
os << std::setw(10) << data[c + 4 * r];
}
os << "]\n";
}
os << std::resetiosflags(std::ios_base::fixed | std::ios_base::floatfield);
return os;
}
template <typename T> static inline bool
operator==(const T& m1, const T& m2)
{
const float* data1 = m1.getMatrix();
const float* data2 = m2.getMatrix();
bool result = true;
for (unsigned int i = 0; i < 16; i++) {
result &= almost_equals(data1[i], data2[i]);
}
return result;
}
#define INFINITY_TEST 0
#define NAN_TEST 0
#define SIGN_TEST 0
#define ULPS_TEST 1
template <typename T> static inline
std::enable_if_t<std::is_floating_point<T>::value, bool>
almost_equals(const T& lhs, const T& rhs)
{
Float<T> f1(lhs), f2(rhs);
std::cout << f1 << '\n' << f2 << '\n';
#if INFINITY_TEST
if (f1.is_infinity() || f2.is_infinity())
return f1.data_float() == f2.data_float();
#endif
#if NAN_TEST
if (f1.is_nan() || f2.is_nan()) return false;
#endif
#if SIGN_TEST
if (f1.sign_bits() || f2.sign_bits())
return f1.data_float() == f2.data_float();
#endif
#if ULPS_TEST
return Float<T>::distance(f1.data_bits(), f2.data_bits()) <= Float<T>::max_ulps;
#endif
}
int main()
{
sf::Transform m1(2.0f, 1.0f, 1.0f,
2.0f, 1.0f, 2.0f,
3.0f, 3.0f, 1.0f);
sf::Transform inv = m1.getInverse();
// A *A^-1 = A^-1 * A = I
sf::Transform m2 = m1 * inv;
bool result = (m2 == sf::Transform::Identity);
std::cout << " matrix:\n" <<m1 << '\n'
<< "inverse:\n" << inv << '\n'
<< "m2 = m1 * inv:\n" << m2 << '\n'
<< "identity:\n" << sf::Transform::Identity << '\n'
<< "m2 == indentity : "<< std::boolalpha << result << "!\n";
getchar();
}