works perfectly, fully tested

This commit is contained in:
Marc Wäckerlin
2016-08-23 13:09:14 +00:00
parent 2f35c1e3a0
commit 740b210135
3 changed files with 329 additions and 49 deletions

View File

@@ -6,27 +6,26 @@
// 45678901234567890123456789012345678901234567890123456789012345678901234567890
#include <iostream>
#include <sstream>
#include <cstring>
#include <cassert>
#include <type_traits>
#include <limits>
#include <cmath>
#include <cfenv>
#include <stdexcept>
#include <functional>
namespace math {
template<typename TYPE>
bool almostEqual(TYPE a, TYPE b) {
if (a<0)
if (b<0) {
a = -a;
b = -b;
} else return a==b; // different signs
else if (b<0) return a==b; // different signs
TYPE diff(abs(a-b));
a = abs(a);
b = abs(b);
a = std::fabs(a);
b = std::fabs(b);
TYPE diff(std::fabs(a-b));
TYPE max(a>b?a:b);
if (max<1) return diff<=std::numeric_limits<TYPE>::epsilon();
return diff<=max*std::numeric_limits<TYPE>::epsilon();
if (max<1) return diff<=1000*std::numeric_limits<TYPE>::epsilon();
return diff<=max*1000*std::numeric_limits<TYPE>::epsilon();
}
template<typename TYPE>
@@ -34,6 +33,11 @@ namespace math {
return a==b;
}
template<>
bool equal(const long double& a, const long double& b) {
return almostEqual(a, b);
}
template<>
bool equal(const double& a, const double& b) {
return almostEqual(a, b);
@@ -158,12 +162,6 @@ template<typename TYPE, typename ARRAY=TYPE*> class MatrixBase {
/// @name operators
///{
MatrixBase& operator=(TYPE oc[]) {
assert(sizeof(oc)==MEM_SIZE);
memcpy(_c, oc, MEM_SIZE);
return *this;
}
MatrixBase& operator=(const MatrixBase& o) {
assert_check(o);
memcpy(_c, o._c, MEM_SIZE);
@@ -212,11 +210,10 @@ template<typename TYPE, typename ARRAY=TYPE*> class MatrixBase {
/// @name special operations
///{
bool similar(const MatrixBase& o, const TYPE& diff) const {
if (!check(o)) return false;
TYPE *to((TYPE*)(_c)+SIZE), *from((TYPE*)(o._c)+SIZE);
while (to>(TYPE*)(_c)) if (abs(*--to - *--from)>diff) return false;
return true;
MatrixBase& apply(std::function<void(TYPE&)> fn) {
TYPE *to((TYPE*)(_c)+SIZE);
while (to>(TYPE*)(_c)) fn(*--to);
return *this;
}
TYPE det() {
@@ -230,6 +227,10 @@ template<typename TYPE, typename ARRAY=TYPE*> class MatrixBase {
/// @see http://www.mathebibel.de/determinante-berechnen-nach-gauss
/// 1. normalize first line to first value
TYPE lambda(at(0, 0));
if (lambda==0) {
feraiseexcept(FE_DIVBYZERO);
throw std::range_error("gauss calculation failed");
}
at(0, 0) = 1;
for (TYPE *p((TYPE*)(_c)+COLUMNS); p>(TYPE*)(_c)+1;) *--p/=lambda;
/// 2. nullify lower triangle
@@ -297,15 +298,34 @@ template<typename TYPE, size_t TROWS=0, size_t TCOLUMNS=0> class Matrix:
/// @name operators
///{
Matrix& operator=(TYPE oc[TROWS][TCOLUMNS]) {
memcpy(Parent::_c, oc, Parent::MEM_SIZE);
Matrix& operator=(const Matrix& o) {
Parent::operator=(o);
return *this;
}
Matrix& operator+=(const Matrix& o) {
Parent::operator+=(o);
return *this;
}
Matrix& operator-=(const Matrix& o) {
Parent::operator-=(o);
return *this;
}
Matrix& operator*=(const TYPE& o) {
Parent::operator*=(o);
return *this;
}
Matrix& operator/=(const TYPE& o) {
Parent::operator/=(o);
return *this;
}
Matrix operator-() const {
Matrix res;
for (TYPE *to((TYPE*)(res._c)+Parent::SIZE); to>(TYPE*)(Parent::_c); --to)
*to = -*to;
Matrix res(*this);
for (TYPE *to((TYPE*)(res._c)+this->SIZE); to>(TYPE*)(res._c); *--to = -*to);
return res;
}
@@ -325,6 +345,11 @@ template<typename TYPE, size_t TROWS=0, size_t TCOLUMNS=0> class Matrix:
/// @name special operations
///{
Matrix& apply(std::function<void(TYPE&)> fn) {
Parent::apply(fn);
return *this;
}
Matrix<TYPE, TCOLUMNS, TROWS> t() const {
Matrix<TYPE, TCOLUMNS, TROWS> res;
for (size_t row(0); row<TROWS; ++row)
@@ -440,10 +465,34 @@ template<typename TYPE> class Matrix<TYPE, 0, 0>: public MatrixBase<TYPE> {
/// @name operators
///{
Matrix& operator=(const Matrix& o) {
Parent::operator=(o);
return *this;
}
Matrix& operator+=(const Matrix& o) {
Parent::operator+=(o);
return *this;
}
Matrix& operator-=(const Matrix& o) {
Parent::operator-=(o);
return *this;
}
Matrix& operator*=(const TYPE& o) {
Parent::operator*=(o);
return *this;
}
Matrix& operator/=(const TYPE& o) {
Parent::operator/=(o);
return *this;
}
Matrix operator-() const {
Matrix res(Parent::COLUMNS, Parent::ROWS);
for (TYPE *to((TYPE*)(res._c)+Parent::SIZE); to>(TYPE*)(Parent::_c); --to)
*to = -*to;
Matrix res(*this);
for (TYPE *to((TYPE*)(res._c)+this->SIZE); to>(TYPE*)(res._c); *--to = -*to);
return res;
}
@@ -462,6 +511,11 @@ template<typename TYPE> class Matrix<TYPE, 0, 0>: public MatrixBase<TYPE> {
///@name special operations
///{
Matrix& apply(std::function<void(TYPE&)> fn) {
Parent::apply(fn);
return *this;
}
Matrix t() const {
Matrix res(this->COLUMNS, this->ROWS);
for (size_t row(0); row<this->ROWS; ++row)
@@ -583,11 +637,60 @@ template<typename TYPE, size_t ROWS, size_t COLUMNS>
}
template<typename TYPE, size_t ROWS, size_t COLUMNS>
std::ostream& operator<<(std::ostream& s, const Matrix<TYPE, ROWS, COLUMNS>& m) {
for (size_t w = 0; w < m.ROWS; ++w) {
for (size_t h = 0; h < m.COLUMNS;++h) {
s<<m[w][h]<<' ';
}
s<<'\n';
}
Matrix<TYPE, ROWS, COLUMNS> operator/(const Matrix<TYPE, ROWS, COLUMNS>& m,
const TYPE& v) {
Matrix<TYPE, ROWS, COLUMNS> res(m);
res /= v;
return res;
}
template<typename TYPE, size_t ROWS, size_t COLUMNS>
Matrix<TYPE, ROWS, COLUMNS> operator/(const TYPE& v,
const Matrix<TYPE, ROWS, COLUMNS>& m) {
Matrix<TYPE, ROWS, COLUMNS> res(m);
res.inv() *= v;
return res;
}
template<typename TYPE, size_t ROWS, size_t COLUMNS>
Matrix<TYPE, ROWS, COLUMNS> operator/(const Matrix<TYPE, ROWS, COLUMNS>& m1,
const Matrix<TYPE, ROWS, COLUMNS>& m2) {
Matrix<TYPE, ROWS, COLUMNS> res(m2);
return m1 * res.inv();
}
template<typename TYPE, size_t ROWS, size_t COLUMNS>
std::ostream& operator<<(std::ostream& s, const Matrix<TYPE, ROWS, COLUMNS>& m) {
s<<'['<<ROWS<<'x'<<COLUMNS<<"]{";
for (size_t row = 0; row < m.ROWS; ++row) {
for (size_t column = 0; column < m.COLUMNS; ++column) {
if (row!=0||column!=0) s<<',';
s<<m(row, column);
}
}
return s<<'}';
}
template<typename TYPE, size_t ROWS, size_t COLUMNS>
std::istream& operator>>(std::istream& in, Matrix<TYPE, ROWS, COLUMNS>& m) {
std::ios_base::failure err("illegal matrix format");
char c(0);
size_t sz(0);
TYPE val(0);
std::string s;
if (!in.get(c) || c!='[') throw err;
if (!std::getline(in, s, 'x') || !(std::stringstream(s)>>sz) || sz!=m.ROWS) throw err;
if (!std::getline(in, s, ']') || !(std::stringstream(s)>>sz) || sz!=m.COLUMNS) throw err;
if (!in.get(c) || c!='{') throw err;
for (size_t row = 0; row < m.ROWS; ++row) {
for (size_t column = 0; column < m.COLUMNS; ++column) {
if (row==m.ROWS-1&&column==m.COLUMNS) {
if (!std::getline(in, s, '}') || !(std::stringstream(s)>>val)) throw err;
} else {
if (!std::getline(in, s, ',') || !(std::stringstream(s)>>val)) throw err;
}
m(row, column) = val;
}
}
return in;
}