I was trying to calculate random orthogonal matrix of any size and faced a problem that machine error is huge since small sizes of matrix. I check final matrix is orthogonal by Q^T * Q = I
Where Q is calculated orthogonal matrix. For example this operation for 10*10 matrix returns
1.000001421720586184 -0.000000728640227713 0.000001136830463799 -0.000000551609342727 -0.000001177027039965 0.000000334599582398 -0.000000858589995413 0.000000954985769303 0.000032744809653293 -0.000000265053286108 
-0.000000728640227713 1.000000373167701527 -0.000000583888104495 0.000000285028920487 0.000000602479963850 -0.000000171504851561 0.000000439149502041 -0.000000489282575621 -0.000016836862737655 0.000000139458235281 
0.000001136830463799 -0.000000583888104495 1.000000903071175539 -0.000000430043020645 -0.000000944743177025 0.000000267453533747 -0.000000690730534104 0.000000764348989692 0.000025922602192780 -0.000000194784469538 
-0.000000551609342727 0.000000285028920487 -0.000000430043020645 1.000000193583126484 0.000000463290242271 -0.000000129639515781 0.000000340879278672 -0.000000371868992193 -0.000012221761904027 0.000000071060844115 
-0.000001177027039965 0.000000602479963850 -0.000000944743177025 0.000000463290242271 1.000000972303993511 -0.000000277069934225 0.000000708304641621 -0.000000790186119274 -0.000027265457679301 0.000000229727452845 
0.000000334599582398 -0.000000171504851561 0.000000267453533747 -0.000000129639515781 -0.000000277069934225 1.000000078745856667 -0.000000202136378957 0.000000224766235153 0.000007702164180343 -0.000000062098652538 
-0.000000858589995413 0.000000439149502041 -0.000000690730534104 0.000000340879278672 0.000000708304641621 -0.000000202136378957 1.000000515565399593 -0.000000576213323968 -0.000019958173806416 0.000000172131276688 
0.000000954985769303 -0.000000489282575621 0.000000764348989692 -0.000000371868992193 -0.000000790186119274 0.000000224766235153 -0.000000576213323968 1.000000641385961051 0.000022026878760393 -0.000000180133590665 
0.000032744809653293 -0.000016836862737655 0.000025922602192780 -0.000012221761904027 -0.000027265457679301 0.000007702164180343 -0.000019958173806416 0.000022026878760393 1.000742765170839780 -0.000005353869978161 
-0.000000265053286108 0.000000139458235281 -0.000000194784469538 0.000000071060844115 0.000000229727452845 -0.000000062098652538 0.000000172131276688 -0.000000180133590665 -0.000005353869978161 1.000000000000000000
So we can see that matrix is orthogonal but non-diagonal elements have big error Is there any solution of that?
How I calculate n*n orthogonal matrix:
- Take start square orthogonal matrix of size 1 Q = |1|
- Take random vector of dimension 2 y = |rand(), rand()|and norm ity = y/norm(y)
- Construct a Householder reflection with vector y and apply it to matrix Q with number 1 in right corner, so I have orthogonal matrix Q of size 2.
- Repeat while don't have n*n matrix, taking new random y with increased dimension.
Code:
#include <iostream>
#include <map>
#include <iostream>
#include <vector>
#include <iterator>
#include <cmath>
#include <utility>
using namespace std;
template<typename T>
T tolerance = T(1e-3);
template<typename T>
struct Triplet{
    int i;
    int j;
    T b;
};
template<typename T>
T Tabs(T num){
    if(num<T(0)) return -num;
    else return num;
}
template<typename T>
class DOK{
private:
    /*
     * Dictionary of Keys, pair<int, int> is coordinates of non-zero elements,
     * next int is value
     */
    int size_n;
    int size_m;
    map<pair<int, int>, T> dict;
    // int count;
public:
    DOK(vector<Triplet<T>> &matrix, int n, int m){
        this->resize(n, m);
        this->fill(matrix);
    }
    DOK(int n, int m){
        this->resize(n, m);
    }
    ~DOK() = default;
    void fill(vector<Triplet<T>> &matrix){
        //this->count=matrix.size();
        //cout<<"Input your coordinates with value in format \"i j val\" "<<endl;
        for(int k = 0; k < matrix.size(); k++){
            this->insert(matrix[k]);
        }
    }
    void insert(const Triplet<T> &Element){
        if(Element.i >= this->size_n){
            this->size_n = Element.i+1;
        }
        if(Element.j >= this->size_m){
            this->size_m = Element.j+1;
        }
        pair<int, int> coordinates = {Element.i, Element.j};
        this->dict.insert(pair(coordinates, Element.b));
    }
    void resize(int n, int m){
        this->size_n=n;
        this->size_m=m;
    }
    void print() const{
        cout<<endl;
        for(int i = 0; i < this->size_n; i++){
            for(int j = 0; j < this->size_m; j++){
                if(this->dict.find({i, j})!= this->dict.cend()) cout<< this->dict.find(pair(i, j))->second<<" "; else cout<<0<<" ";
            }
            cout<<endl;
        }
    }
    void clearZeros(){
        for(auto i = this->dict.begin(); i!=this->dict.end();){
            if(Tabs(i->second) <=  tolerance<T>){
                i = this->dict.erase(i);
            } else{
                i++;
            }
        }
    }
    [[nodiscard]] pair<int, int> getSize() const{
        return {size_n, size_m};
    }
    DOK<T> transpose(){
        DOK<T> A = DOK<T>(this->size_m, this->size_n);
        for(auto &i: this->dict){
            A.insert({i.first.second, i.first.first, i.second});
        }
        return A;
    }
    DOK<T>& operator-=(const DOK<T>& matrix){
        try{
            if(this->size_n != matrix.size_n || this->size_m != matrix.size_m) throw 1;
            for(auto j: matrix.dict){
                if(this->dict.find(j.first)!=this->dict.cend()) {
                    this->dict[j.first] -= j.second;
                }else{
                    this->dict.insert({j.first, -j.second});
                    //M.count++;
                }
            }
            this->clearZeros();
            return *this;
        }
        catch (int a) {
            cout<<"Sizes of Matrices are different."<<endl;
        }
    }
    DOK<T> operator-(const DOK<T> &matrix) const{
        DOK<T> t = *this;
        return move(t-=matrix);
    }
    DOK<T>& operator*=(const DOK<T> &matrix){
        try {
            if(this->size_m != matrix.size_n) throw 1;
            DOK<T> M = DOK(this->size_n, matrix.size_m);
            for (int i = 0; i < this->size_n; i++) {
                for (int j = 0; j < matrix.size_m; j++) {
                    T a=0;
                    for(int k = 0; k<this->size_m; k++){
                        if(this->dict.find({i,k}) != this->dict.cend() && matrix.dict.find({k, j})!=matrix.dict.cend()){
                            a+=this->dict.find({i,k})->second*matrix.dict.find({k,j})->second;
                            //cout<<a<<endl;
                        }
                    }
                    Triplet<T> m = {i, j, a};
                    M.insert(m);
                }
            }
            this->clearZeros();
            *this=M;
            return *this;
        }
        catch (int a) {
            cout<<"Wrong sizes of matrices to multiplication"<<endl;
        }
    }
    DOK<T> operator*(const DOK<T>& matrix) const{
        DOK<T> t = *this;
        return t*=matrix;
    }
    DOK<T>& operator*=(T& k){
        for(auto i: this->dict){
            this->dict[i.first]*=k;
        }
        this->clearZeros();
        return *this;
    }
    DOK<T> operator*(T& k) const{
        DOK<T> t = *this;
        return move(t*=k);
    }
    DOK<T>& operator*=(const T& k){
        for(auto i: this->dict){
            this->dict[i.first]*=k;
        }
        this->clearZeros();
        return *this;
    }
};
template<typename T>
vector<T> operator*(const DOK<T> &matrix, const vector<T> &x){
    vector<T> result;
    for(int i = 0; i < x.size(); i++){
        T temp = 0;
        for(int j = 0; j < x.size(); j++){
            temp+=matrix(i, j)*x[j];
        }
        result.push_back(temp);
    }
    return move(result);
}
template<typename T>
T operator*(const vector<T> &x, const vector<T> &b) {
    T result = 0;
    for(int i = 0; i < x.size(); i++){
        result+=x[i]*b[i];
    }
}
template<typename T>
vector<T> operator*(const vector<T> &x, const DOK<T> &matrix) {
    vector<T> result;
    for(int i = 0; i < x.size(); i++){
        T temp = 0;
        for(int j = 0; j < x.size(); j++){
            temp+=matrix(j, i)*x[j];
        }
        result.push_back(temp);
    }
    return move(result);
}
template<typename  T>
DOK<T> operator*(T& k, const DOK<T> &matrix){
    return matrix*k;
}
template<typename  T>
DOK<T> operator*(const T& k, const DOK<T> &matrix){
    return matrix*k;
}
template<typename T>
vector<T>& operator*=(const DOK<T> &matrix, const vector<T> &x){
    return matrix*x;
}
template<typename T>
vector<T>& operator*=(const vector<T> &x, const DOK<T> &matrix){
    return x*matrix;
}
template<typename T>
vector<T> operator*(const vector<T> &x, T k){
    vector<T> result = x;
    for(int i = 0; i<x.size(); i++){
        result[i]*=k;
    }
    return result;
}
template<typename T>
vector<T> operator*(T k, const vector<T> &x) {
    return x*k;
}
template<typename  T>
ostream& operator<<(ostream &os, const DOK<T> &matrix) {
    matrix.DOK<T>::print();
    return os;
}
template<typename T>
T norm(const vector<T> x){
    T result = 0;
    for(int i = 0; i < x.size(); i++){
        result+=pow(x[i],2);
    }
    return sqrt(result);
}
template<typename T>
DOK<T> Ortogonal(int n){
    srand(time(NULL));
    vector<Triplet<T>> in = {{0, 0, T(1)}};
    DOK<T> Q = DOK<T>(in, 1, 1);
    DOK<T> E = Q;
    vector<T> y;
    for(int i = 1; i<n; i++){
        y.clear();
        for(int m = 0; m<i+1; m++){
            y.emplace_back(rand());
        }
        y = (1/norm(y))*y;
        DOK<T> Y = DOK<T>(i+1, i+1);
        for(int j = 0; j<i+1; j++){
            for(int k = 0; k<i+1; k++){
                Y.insert({j, k, y[j]*y[k]});
            }
        }
        Q.insert({i, i, T(1)});
        cout<<Q;
        Y*=T(2);
        E.insert({i, i, T(1)});
        Q = (E - Y)*Q;
    }
    return Q;
}
main.cpp:
#include <iostream>
#include "DOK.h"
using namespace std;
int main() {
    DOK<long double> O = Ortogonal<long double>(10);
    cout<<O.transpose()*O;
    return 0;
}
DOK is template class of sparse matrix with all overloaded operators.
 
    