Отмена слияния с мерзавцем так легка, Вы не должны даже волноваться о пробном прогоне:
$ git pull $REMOTE $BRANCH
# uh oh, that wasn't right
$ git reset --hard ORIG_HEAD
# all is right with the world
РЕДАКТИРОВАНИЕ: Как отмечено в комментариях ниже, если у Вас есть изменения в Вашем рабочем каталоге или районе сосредоточения войск, Вы, вероятно, захотите спрятать их прежде, чем сделать вышеупомянутое (иначе, они исчезнут после git reset
выше)
Во-первых, существуют более эффективные алгоритмы для умножения матриц, чем тот, который вы используете.
Во-вторых, ваш процессор может выполнять гораздо больше, чем одну инструкцию за раз.
Ваш ЦП выполняет 3-4 инструкции за цикл, и если используются блоки SIMD, каждая инструкция обрабатывает 4 числа с плавающей запятой или 2 двойных. (конечно, это число тоже неточно, поскольку ЦП обычно может обрабатывать только одну инструкцию SIMD за цикл)
В-третьих, ваш код далек от оптимального:
Я не знаю конкретно о реализации BLAS, но есть более эффективные алгоритмы для умножения матриц, которые имеют сложность выше O (n3). Хорошо известным является Алгоритм Штрассена
Это реальная скорость. Для примера того, что можно сделать с помощью ассемблера SIMD поверх кода C ++, см. Пример Матричные функции iPhone - они были более чем в 8 раз быстрее, чем версия C, и даже не «оптимизированная» сборка - нет конвейерная обработка еще и есть ненужные операции со стеком.
Также ваш код не « ограничивает правильное » - как компилятор узнает, что когда он изменяет C, он не изменяет A и B?
По многим причинам.
Во-первых, компиляторы Фортрана сильно оптимизированы, и язык позволяет им быть такими. C и C ++ очень свободны с точки зрения обработки массивов (например, в случае указателей, относящихся к одной и той же области памяти). Это означает, что компилятор не может заранее знать, что делать, и вынужден создавать общий код. В Фортране ваши случаи более упрощены, и компилятор лучше контролирует происходящее, что позволяет ему оптимизировать больше (например, с использованием регистров).
Другое дело, что Fortran хранит данные по столбцам, а C хранит данные по строкам. Я не проверял ваш код, но будьте осторожны с тем, как вы выполняете продукт. В C вы должны сканировать по строкам: таким образом вы сканируете свой массив по непрерывной памяти, уменьшая промахи кеша. Промахи в кэше - это первая причина неэффективности.
В-третьих, это зависит от используемой вами реализации blas. Некоторые реализации могут быть написаны на ассемблере и оптимизированы для конкретного процессора, который вы используете. Версия netlib написана на fortran 77.
Кроме того, вы выполняете множество операций, большинство из которых повторяются и избыточны. Все эти умножения для получения индекса пагубно сказываются на производительности. Я действительно не знаю, как это делается в BLAS, но есть много уловок для предотвращения дорогостоящих операций.
Например, вы можете переделать свой код таким образом
template<class ValT>
void mmult(const ValT* A, int ADim1, int ADim2, const ValT* B, int BDim1, int BDim2, ValT* C)
{
if ( ADim2!=BDim1 ) throw std::runtime_error("Error sizes off");
memset((void*)C,0,sizeof(ValT)*ADim1*BDim2);
int cc2,cc1,cr1, a1,a2,a3;
for ( cc2=0 ; cc2<BDim2 ; ++cc2 ) {
a1 = cc2*ADim2;
a3 = cc2*BDim1
for ( cc1=0 ; cc1<ADim2 ; ++cc1 ) {
a2=cc1*ADim1;
ValT b = B[a3+cc1];
for ( cr1=0 ; cr1<ADim1 ; ++cr1 ) {
C[a1+cr1] += A[a2+cr1]*b;
}
}
}
}
Попробуйте, я уверен, вы сэкономите что-то.
На ваш вопрос №1 причина в том, что умножение матриц масштабируется как O (n ^ 3), если вы используете тривиальный алгоритм. Есть алгоритмы, которые масштабируются намного лучше .
Некоторые реализации могут быть написаны на ассемблере и оптимизированы для конкретного процессора, который вы используете. Версия netlib написана на fortran 77.Кроме того, вы выполняете множество операций, большинство из которых повторяются и избыточны. Все эти умножения для получения индекса пагубно сказываются на производительности. Я действительно не знаю, как это делается в BLAS, но есть много уловок для предотвращения дорогостоящих операций.
Например, вы можете переделать свой код таким образом
template<class ValT>
void mmult(const ValT* A, int ADim1, int ADim2, const ValT* B, int BDim1, int BDim2, ValT* C)
{
if ( ADim2!=BDim1 ) throw std::runtime_error("Error sizes off");
memset((void*)C,0,sizeof(ValT)*ADim1*BDim2);
int cc2,cc1,cr1, a1,a2,a3;
for ( cc2=0 ; cc2<BDim2 ; ++cc2 ) {
a1 = cc2*ADim2;
a3 = cc2*BDim1
for ( cc1=0 ; cc1<ADim2 ; ++cc1 ) {
a2=cc1*ADim1;
ValT b = B[a3+cc1];
for ( cr1=0 ; cr1<ADim1 ; ++cr1 ) {
C[a1+cr1] += A[a2+cr1]*b;
}
}
}
}
Попробуйте, я уверен, вы сэкономите что-то.
На ваш вопрос №1 причина в том, что умножение матриц масштабируется как O (n ^ 3), если вы используете тривиальный алгоритм. Есть алгоритмы, которые масштабируются намного лучше .
Некоторые реализации могут быть написаны на ассемблере и оптимизированы для конкретного процессора, который вы используете. Версия netlib написана на fortran 77.Кроме того, вы выполняете множество операций, большинство из которых повторяются и избыточны. Все эти умножения для получения индекса пагубно сказываются на производительности. Я действительно не знаю, как это делается в BLAS, но есть много уловок для предотвращения дорогостоящих операций.
Например, вы можете переделать свой код таким образом
template<class ValT>
void mmult(const ValT* A, int ADim1, int ADim2, const ValT* B, int BDim1, int BDim2, ValT* C)
{
if ( ADim2!=BDim1 ) throw std::runtime_error("Error sizes off");
memset((void*)C,0,sizeof(ValT)*ADim1*BDim2);
int cc2,cc1,cr1, a1,a2,a3;
for ( cc2=0 ; cc2<BDim2 ; ++cc2 ) {
a1 = cc2*ADim2;
a3 = cc2*BDim1
for ( cc1=0 ; cc1<ADim2 ; ++cc1 ) {
a2=cc1*ADim1;
ValT b = B[a3+cc1];
for ( cr1=0 ; cr1<ADim1 ; ++cr1 ) {
C[a1+cr1] += A[a2+cr1]*b;
}
}
}
}
Попробуйте, я уверен, вы сэкономите что-то.
На ваш вопрос №1 причина в том, что умножение матриц масштабируется как O (n ^ 3), если вы используете тривиальный алгоритм. Есть алгоритмы, которые масштабируются намного лучше .
вы выполняете множество операций, большинство из которых повторяются и повторяются. Все эти умножения для получения индекса пагубно сказываются на производительности. Я действительно не знаю, как это делается в BLAS, но есть много уловок для предотвращения дорогостоящих операций.Например, вы можете переделать свой код таким образом
template<class ValT>
void mmult(const ValT* A, int ADim1, int ADim2, const ValT* B, int BDim1, int BDim2, ValT* C)
{
if ( ADim2!=BDim1 ) throw std::runtime_error("Error sizes off");
memset((void*)C,0,sizeof(ValT)*ADim1*BDim2);
int cc2,cc1,cr1, a1,a2,a3;
for ( cc2=0 ; cc2<BDim2 ; ++cc2 ) {
a1 = cc2*ADim2;
a3 = cc2*BDim1
for ( cc1=0 ; cc1<ADim2 ; ++cc1 ) {
a2=cc1*ADim1;
ValT b = B[a3+cc1];
for ( cr1=0 ; cr1<ADim1 ; ++cr1 ) {
C[a1+cr1] += A[a2+cr1]*b;
}
}
}
}
Попробуйте, я уверен, вы сэкономите что-то.
На ваш вопрос №1 причина в том, что умножение матриц масштабируется как O (n ^ 3), если вы используете тривиальный алгоритм. Есть алгоритмы, которые масштабируются намного лучше .
вы выполняете много операций, большинство из которых повторяются и повторяются. Все эти умножения для получения индекса пагубно сказываются на производительности. Я действительно не знаю, как это делается в BLAS, но есть много уловок для предотвращения дорогостоящих операций.Например, вы можете переделать свой код таким образом
template<class ValT>
void mmult(const ValT* A, int ADim1, int ADim2, const ValT* B, int BDim1, int BDim2, ValT* C)
{
if ( ADim2!=BDim1 ) throw std::runtime_error("Error sizes off");
memset((void*)C,0,sizeof(ValT)*ADim1*BDim2);
int cc2,cc1,cr1, a1,a2,a3;
for ( cc2=0 ; cc2<BDim2 ; ++cc2 ) {
a1 = cc2*ADim2;
a3 = cc2*BDim1
for ( cc1=0 ; cc1<ADim2 ; ++cc1 ) {
a2=cc1*ADim1;
ValT b = B[a3+cc1];
for ( cr1=0 ; cr1<ADim1 ; ++cr1 ) {
C[a1+cr1] += A[a2+cr1]*b;
}
}
}
}
Попробуйте, я уверен, вы сэкономите что-то.
На ваш вопрос №1 причина в том, что умножение матриц масштабируется как O (n ^ 3), если вы используете тривиальный алгоритм. Есть алгоритмы, которые масштабируются намного лучше .
вы можете переделать свой код таким образомtemplate<class ValT>
void mmult(const ValT* A, int ADim1, int ADim2, const ValT* B, int BDim1, int BDim2, ValT* C)
{
if ( ADim2!=BDim1 ) throw std::runtime_error("Error sizes off");
memset((void*)C,0,sizeof(ValT)*ADim1*BDim2);
int cc2,cc1,cr1, a1,a2,a3;
for ( cc2=0 ; cc2<BDim2 ; ++cc2 ) {
a1 = cc2*ADim2;
a3 = cc2*BDim1
for ( cc1=0 ; cc1<ADim2 ; ++cc1 ) {
a2=cc1*ADim1;
ValT b = B[a3+cc1];
for ( cr1=0 ; cr1<ADim1 ; ++cr1 ) {
C[a1+cr1] += A[a2+cr1]*b;
}
}
}
}
Попробуйте, я уверен, что вы что-то сэкономите.
На ваш вопрос №1 причина в том, что умножение матриц масштабируется как O (n ^ 3), если вы используете тривиальный алгоритм . Есть алгоритмы, которые масштабируются намного лучше .
вы можете переделать свой код таким образомtemplate<class ValT>
void mmult(const ValT* A, int ADim1, int ADim2, const ValT* B, int BDim1, int BDim2, ValT* C)
{
if ( ADim2!=BDim1 ) throw std::runtime_error("Error sizes off");
memset((void*)C,0,sizeof(ValT)*ADim1*BDim2);
int cc2,cc1,cr1, a1,a2,a3;
for ( cc2=0 ; cc2<BDim2 ; ++cc2 ) {
a1 = cc2*ADim2;
a3 = cc2*BDim1
for ( cc1=0 ; cc1<ADim2 ; ++cc1 ) {
a2=cc1*ADim1;
ValT b = B[a3+cc1];
for ( cr1=0 ; cr1<ADim1 ; ++cr1 ) {
C[a1+cr1] += A[a2+cr1]*b;
}
}
}
}
Попробуйте, я уверен, что вы что-то сэкономите.
На ваш вопрос №1 причина в том, что умножение матриц масштабируется как O (n ^ 3), если вы используете тривиальный алгоритм . Есть алгоритмы, которые масштабируются намного лучше .