works perfectly, fully tested
This commit is contained in:
177
src/matrix.hxx
177
src/matrix.hxx
@@ -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;
|
||||
}
|
||||
|
Reference in New Issue
Block a user