Имеет ли смысл, что умножение матриц в стиле C (3 цикла) быстрее, чем собственное?

#c #c #eigen

#c #c #eigen

Вопрос:

Я читаю некоторые учебники по программированию на C, чтобы освежить их, и одна из главных причин, по которой мне лично нравился C , а не C (для моего типа программ), — это собственная линейная алгебра. Итак, сегодня я просто провел простой тест умножения матриц 10×10 и измерил время, и, что удивительно, по крайней мере, для меня, было показано, что стиль C работает довольно быстрее. В режиме выпуска я усредняю <1 мс для C и ~ 12 мс для собственного

Имеет ли смысл, что это так, и если да (или нет), почему? Я ни в коем случае не дискредитирую Eigen, все еще моя лучшая библиотека линейной алгебры, и она предоставляет множество других функций. И, как заядлый пользователь Eigen, есть ли что-то, что можно сделать для повышения производительности в sitatutions, подобных показанному ниже.

 // function to multiply two matrices
void multiplyMatrices(int first[][10],
                      int second[][10],
                      int result[][10],
                      int r1, int c1, int r2, int c2) {

   // Multiplying first and second matrices and storing it in result
   for (int i = 0; i < r1;   i) {
      for (int j = 0; j < c2;   j) {
        // Init matrix
        result[i][j] = 0;
         for (int k = 0; k < c1;   k) {
            result[i][j]  = first[i][k] * second[k][j];
         }
      }
   }
}

int main() {

  int first[10][10], second[10][10], result[10][10];
  // Initializing elements to something arbitrary
  for (int i = 0; i < 10; i  ) {
    for (int j = 0; j < 10; j  ) {
      first[i][j] = i * j;
      second[i][j] = (i   3) * j;
    }
  }
  // multiply two matrices, only time the multiplication
  auto t1 = std::chrono::high_resolution_clock::now();
  multiplyMatrices(first, second, result, 10, 10, 10, 10);
  auto t2 = std::chrono::high_resolution_clock::now();

  auto duration = std::chrono::duration_cast<std::chrono::microseconds>( t2 - t1 ).count();

  std::cout << "C style: " << duration << std::endl;
  // Initialize the matrices to a fixed size
  Eigen::Matrix<int, 10, 10> f1(10, 10);
  Eigen::Matrix<int, 10, 10> f2(10, 10);
  Eigen::Matrix<int, 10, 10> r(10, 10);
  // Same initialization values as C style
  for (int i = 0; i < 10; i  ) {
    for (int j = 0; j < 10; j  ) {
      f1(i, j) = i * j;
      f2(i, j) = (i   3) * j;
    }
  }
  // Only time the multiplication
  t1 = std::chrono::high_resolution_clock::now();
  r = f1 * f2;
  t2 = std::chrono::high_resolution_clock::now();
  duration = std::chrono::duration_cast<std::chrono::microseconds>( t2 - t1 ).count();

  std::cout << "Eigen: " << duration << std::endl;
  

Комментарии:

1. Попробуйте поместить случайные значения в матрицы. То, как вы инициализируете матрицы, компилятор может вычислить результат и пропустить все умножение во время выполнения.

2. Вы смотрели на asm, чтобы увидеть, не полностью ли он встроен в первый код? (так что никаких вычислений вообще).

3. @Barmar Я снова запустил его, инициализируя rand() для всех матриц, и получил аналогичные результаты, C ~ 1 мс, а собственный немного медленнее ~ 20 мс

4. Согласно некоторым быстрым проверкам, собственное умножение выполняется примерно вдвое быстрее, а multiplyMatrices не в 12-20 раз медленнее. этот тестовый пример теперь выполняется 100 раз . (это не научные результаты). Вы рассчитываете время с оптимизацией?

5. в этом вопросе нет ничего о C, не помечайте без разбора