Хабр Курсы для всех
РЕКЛАМА
Практикум, Хекслет, SkyPro, авторские курсы — собрали всех и попросили скидки. Осталось выбрать!
<h4> для заголовков верхнего уровня (4, 5, 6), и <h5> для заголовков вложенного (5.1, 5.2, ..., 5.7) уровня. Перед публикацией я посмотрел статью на «обычном» Firefox и Chrome, а также на Firefox с темой HabraDarkAges и не заметил, что текст визуально «рассыпается». В последнем случае, заголовки даже были выделены отдельным цветом, что на мой взгляд, удобно.Есть два способа это сделать:Справедливости ради, есть ещё третий способ: специализировать шаблон
mat для квадратных матриц и добавить в эту специализация характерные только для таких матриц методы.mat<DimRows,DimCols,number_t> invert_transpose(const mat<DimRows,DimCols,number_t>& A)
{
mat<DimRows,DimCols,number_t> PowMat[DimRows+1];
// Вычисляем степени матриц
PowMat[0] = identity();
PowMat[1] = A;
for (size_t i=2; i <= DimRows; i++)
{
PowMat[i] = PowMat[i-1] * A;
}
number_t s[DimRows], p[DimRows];
for (size_t i = 0; i < DimRows; i++)
{
// Вычисляем следы матриц (суммы диагональных элементов)
s[i] = 0;
for(size_t j = DimRows; j--; )
s[i] += PowMat[i+1][j][j];
// Определяем коэффициенты характеристического уравнения матрицы A
p[i] = s[i];
for(size_t j = 1; j < i; j++)
p[i] -= p[j-1] * s[i-j];
p[i] /= i + 1;
}
// Рассчитываем обратную матрицу по следствию из теоремы Гамильтона-Кэли
mat<DimRows,DimCols,number_t> result = PowMat[DimRows - 1];
for(size_t i = 0; i < DimRows - 1; i++)
result -= p[i] * PowMat[DimRows - i - 2];
return result/p[DimRows - 1];
}
[ 1 4 9 ]
[ ]
(%o4) [ 2 9 7 ]
[ ]
[ 4 3 8 ]
(%i3) float(transpose(invert(matrix([1,4,9],[2,9,7],[4,3,8]))));
[ - 0.2982456140350877 - 0.07017543859649122 0.1754385964912281 ]
[ ]
(%o3) [ 0.02923976608187134 0.1637426900584795 - 0.07602339181286549 ]
[ ]
[ 0.3099415204678362 - 0.06432748538011696 - 0.005847953216374269 ]
-0.298246 -0.0701754 0.175439
0.0292398 0.163743 -0.0760234
0.309942 -0.0643275 -0.00584795
0.352381 0.015873 0.168254
-0.0380952 0.603175 -0.0349206
0.0952381 -0.0412698 0.511111
template<size_t DimRows,size_t DimCols,typename T>
mat<DimRows,DimRows,T> operator-(
const mat<DimRows,DimCols,T>& lhs,
const mat<DimRows,DimCols,T>& rhs
)
{
mat<DimRows,DimCols,T> ret;
for(size_t i=DimCols;i--;)
{
ret[i]=lhs[i]-rhs[i];
}
return(ret);
}
template<size_t DimRows,size_t DimCols,typename T> mat<DimCols,DimRows,T>
operator*(
mat<DimRows,DimCols,T> lhs,
const T& rhs
)
{
for (size_t i=DimRows; i--;)
{
lhs[i]=lhs[i]*rhs;
}
return lhs;
}
mat<DimRows,DimCols,number_t> invert_transpose(const mat<DimRows,DimCols,number_t>& A)
{
mat<DimRows,DimCols,number_t> PowMat[DimRows+1];
// Вычисляем степени матрицы
PowMat[0] = identity();
PowMat[1] = A;
for (size_t i=2; i <= DimRows; i++)
{
PowMat[i] = PowMat[i-1] * A;
}
number_t s[DimRows], p[DimRows];
for (size_t i = 0; i < DimRows; i++)
{
// Вычисляем следы матриц (суммы диагональных элементов)
s[i] = 0;
for(size_t j = DimRows; j--; )
s[i] += PowMat[i+1][j][j];
// Определяем коэффициенты характеристического уравнения матрицы A
p[i] = s[i];
for(size_t j = 1; j <= i; j++)
p[i] -= p[j-1] * s[i-j];
p[i] /= i + 1;
}
// Рассчитываем обратную матрицу по следствию из теоремы Гамильтона-Кэли
mat<DimRows,DimCols,number_t> result = PowMat[DimRows - 1];
for(size_t i = 0; i < DimRows - 1; i++)
result -= p[i] * PowMat[DimRows - i - 2];
return result/p[DimRows - 1];
}
////////С союзной матрицей:
-0.298246 -0.0701754 0.175439
0.0292398 0.163743 -0.0760234
0.309942 -0.0643275 -0.00584795
////////По теореме Кэли-Гамильтона
-0.298246 0.0292398 0.309942
-0.0701754 0.163743 -0.0643275
0.175439 -0.0760234 -0.00584795
Source
2.00000000 4.00000000 9.00000000 2.00000000
2.00000000 9.00000000 7.00000000 100000.00000000
4.00000000 3.00000000 8.00000000 0.00000100
4000.00000000 6633.00000000 995522.00000000 1.13000000
With Cofactors
-0.29927686 0.00000599 0.40014544 -0.00000051
0.40298930 -0.00000806 -0.19945022 -0.00000204
-0.00148256 0.00000003 -0.00027888 0.00000102
-0.00003018 0.00001000 0.00000997 0.00000000
With Cayley–Hamilton theorem
-0.30498824 0.00000610 0.40778178 -0.00000052
0.41067991 -0.00000824 -0.20325670 -0.00000872
-0.00151085 0.00000003 -0.00028420 0.00000104
-0.00003080 0.00001036 0.00000000 0.00000000
Source
2.00000000 4.00000000 9.00000000 2.00000000
2.00000000 9.00000000 7.00000000 100000.00000000
4.00000000 3.00000000 8.00000000 0.00000100
4000.00000000 6633.00000000 995522.00000000 1.13000000
With Cofactors
-0.29927683 0.00000599 0.40014542 -0.00000051
0.40298926 -0.00000806 -0.19945022 -0.00000204
-0.00148256 0.00000003 -0.00027888 0.00000102
-0.00003018 0.00001000 0.00000997 0.00000000
With Cayley–Hamilton theorem
-0.29927683 0.00000599 0.40014542 -0.00000051
0.40298926 -0.00000806 -0.19945022 -0.00000204
-0.00148256 0.00000003 -0.00027888 0.00000102
-0.00003018 0.00001000 0.00000997 0.00000000
[ - 2.992768282b-1 5.985538325b-6 4.001454189b-1 - 5.099975655b-7 ]
[ ]
[ 4.029892624b-1 - 8.059760198b-6 - 1.994502193b-1 - 2.04038202b-6 ]
[ ]
[ - 1.482559332b-3 2.963966182b-8 - 2.788771941b-4 1.02014204b-6 ]
[ ]
[ - 3.01797179b-5 1.000060359b-5 9.967132764b-6 1.224243903b-10 ]
for(size_t i=0;i<1000000;i++)
{
alpha=alpha.invert_transpose();
}
2.00000000 4.00000000 9.00000000 2.00000000
2.00000000 9.00000000 7.00000000 100000.00000000
4.00000000 3.00000000 8.00000000 0.00000100
4000.00000000 6633.00000000 995522.00000000 1.13000000
390 308 микросекунд спустя ----------------------------
2.00000000 4.00000000 9.00000000 2.00000000
2.00000000 9.00000000 7.00000000 99999.99999999
4.00000000 3.00000000 8.00000000 0.00000100
4000.00000000 6633.00000000 995521.99999991 1.13000000
2.00000000 4.00000000 9.00000000 2.00000000
2.00000000 9.00000000 7.00000000 100000.00000000
4.00000000 3.00000000 8.00000000 0.00000100
4000.00000000 6633.00000000 995522.00000000 1.13000000
1 291 526 микросекунд спустя----------------------
1.99916579 3.99984523 8.99719176 1.99992263
2.00265273 9.00052080 7.00307486 99996.12998843
3.99982965 2.99988385 8.00050879 0.00000103
3999.84513206 6632.74319101 995483.45650841 1.13082955
constexpr вовсе не гарантирует, что лентяй-компилятор вычислит ее значение во время компиляции. Гарантию дает только использование std::integral_constant:cout<<std::integral_constant<int, g(0)>::value;
return std::move ( type(lhs.x + rhs.x, lhs.y + rhs.y) );
constexpr показывает что счисление возможно провести на этапе компиляции.
-А результат вычисления constexpr-функции я куда складировать буду? Вот переменную мне объявите, я в нее все сложу и в секцию статических данных выполняемого файла сохраню.
#include <iostream>
using namespace std;
constexpr unsigned int fact(unsigned int in)
{
return in==0
?
1
:
in*fact(in-1);
}
int main()
{
cout << fact(8) <<'\n';
return 0;
}
g++ test.cpp -std=c++11 -O2 -S -o out.s
main:
.LFB3682:
.cfi_startproc
movl $1, %esi
movl $8, %eax
.p2align 4,,10
.p2align 3
.L3:
imull %eax, %esi ;заинлайненное вычисление факториала.
subl $1, %eax ;GCC - умница, развернул рекурсию
jne .L3 ;
subq $24, %rsp
.cfi_def_cfa_offset 32
movl $_ZSt4cout, %edi
call _ZNSo9_M_insertImEERSoT_
leaq 15(%rsp), %rsi
g++ test.cpp -std=c++11 -O3 -S -o out.s
.cfi_startproc
subq $24, %rsp
.cfi_def_cfa_offset 32
movl $40320, %esi ;все честно, 40320 - это факториал 8
movl $_ZSt4cout, %edi
call _ZNSo9_M_insertImEERSoT_
leaq 15(%rsp), %rsi
Maxima 5.35.1 http://maxima.sourceforge.net
using Lisp CLISP 2.49 (2010-07-07)
Distributed under the GNU Public License. See the file COPYING.
Dedicated to the memory of William Schelter.
The function bug_report() provides bug reporting information.
(%i1) 8!;
(%o1) 40320
(%i2)
std::integral_constant.g++ test.cpp -std=c++11 -O0 -g -S -o out.s
cout << std::integral_constant<unsigned int,fact(8)>::value;
main:
.LFB3639:
.file 1 "test.cpp"
.loc 1 14 0
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
.loc 1 16 0
movl $40320, %esi ;ага, вот эта константа
movl $_ZSt4cout, %edi
call _ZNSolsEj
movl $10, %esi
movq %rax, %rdiСпасибо, за меня это сделает даже О1 оптимизация
constexpr int det=...
В любом режиме оптимизации считает в compile-time, как и положено по стандарту.Честно говоря, я не уверен, что стандарт где-то обязывает так делать. В конце концов, у нас есть правило «as-if», а поскольку программы с вычислением выражения в compile-time и в runtime имеют одно и то же наблюдаемое поведение, то они обе корректны. На практике, конечно, понятно, что когда мы используем выражение как параметр шаблона, то компилятор его посчитает во время компиляции, просто чтобы проверить, что не будет ошибки компиляции, дать имя этому шаблону и т.д. Тут было лучше какую-нибудь опцию компилятора иметь, которая говорила бы ему «считай все
constexpr в compile-time», но для gcc в документации я такой не нашел.constexpr, например:int non_constexpr() { return 1; }
constexpr int f(bool b)
{
return b ? 0 : non_constexpr();
}
constexpr int x = f(true); // OK
constexpr int y = f(false); // Compilation error
static_assert()), поэтому, возможно, компилятору тупо проще вычислить значение сразу, чем проводить анализ, а будет ли оно нам нужно, или же сохранять какие-то данные для ленивого вычисления.
Краткий курс компьютерной графики: пишем упрощённый OpenGL своими руками, статья 3.14 из 6