LINUX.ORG.RU

[C++][тормоза] matrix template

 ,


0

0

Есть шаблон класса для матрицы, где двумерная матрица реализована как одномерная:

template <class T> class matrix
{
	private:
		size_t Height;
		size_t Width;
		T *Val;
	public:
		T& operator () (size_t i, size_t j)
		{
			return Val[Width*(i-1)+j-1];
		}
	........
}
Не пойму почему скорость доступа к элементам матрицы в 5 раз медленнее по сравнению с:
double *A3 = new double [n*n];
и доступом к элементу в виде:
A3[n*(i-1)+j-1]

★★★★★
Ответ на: комментарий от Absurd

> Типа оно почти как Фортран.

для конкуренции с фортраном придумали restrict

dilmah ★★★★★
()
Ответ на: комментарий от Zodd

>Почему именно использую шаблон - есть матрицы int, double - пытался избежать повтора кода.

Вот когда будет повтор кода тогда и сделаешь новый параметр.

Не совсем понимаю как это сделать. Можно подробней.

matrix[(i << POWER_OF_2) | j]

Absurd ★★★
()

Столько бреда наговорили по такому простому вопросу. «Специалисты», блин.

Reset ★★★★★
()
Ответ на: комментарий от Absurd

> matrix[(i << POWER_OF_2) | j]

имхо, это из разряда советов которые не актульны для современных компиляторов и процессоров. Если у тебя шаблон, тип T = double, то sizeof(T) это константное выражение и компилятор сам способен догадаться как быстро выполнять i * sizeof(double) + j

Другое дело что у ТС там были вычитания единицы, вот они явно лишние.

dilmah ★★★★★
()
Ответ на: комментарий от Love5an

>Вот когда вместо 10 можно будет n, да еще и изменять размер потом, тогда и можно будет о чем-то говорить.

Ну ты и баран со скобками в голове :) хоть на секунду воображение включи. Это реализуется за 5 сек. man realloc.

imhotep
()
Ответ на: комментарий от dilmah

>имхо, это из разряда советов которые не актульны для современных компиляторов и процессоров.

Особо обожествлять компилятор, я думаю, не стоит. Когда я этим занимался в листингах были честные mul и add. Замена дала shl и and. Хотя хз, может оно все и по одному такту теперь.

Absurd ★★★
()
Ответ на: комментарий от imhotep

> Ну ты и баран со скобками в голове :) хоть на секунду воображение включи. Это реализуется за 5 сек. man realloc.

Ты сам понял, что несёшь? Если да, то давай пример кода.

anonymous
()
Ответ на: комментарий от anonymous

>давай пример кода.

anonymous (*)


Ты никто и звать тебя никак - вот и вали нахер.

imhotep
()
Ответ на: комментарий от imhotep

Кто тут баран? Ты вообще врубаешься в то, что я пишу? Во-первых, в C++ realloc по факту нет. Там есть new, но нету renew. Во-вторых, реализуй-ка такое «за 5 сек»:

(defun f(m n new-m new-n)
  (let ((a (make-array `(,m ,n) :element-type '(signed-byte 32)
                                :adjustable t)))
    (dotimes (i (array-total-size a))
      (setf (row-major-aref a i) (1+ i)))
    (sb-kernel:with-array-data ((data a) (s) (e))
      (declare (ignore s e))
      (cffi:foreign-funcall "print_matrix"
                            :pointer (sb-sys:vector-sap data)
                            :int m
                            :int n))
    (adjust-array a `(,new-m ,new-n) :initial-element 7)
    (sb-kernel:with-array-data ((data a) (s) (e))
      (declare (ignore s e))
      (cffi:foreign-funcall "print_matrix"
                            :pointer (sb-sys:vector-sap data)
                            :int new-m
                            :int new-n)))
  T)
чтобы было понятно, что это именно массив, даже вывод через сишку сделал
void print_matrix(int *a, int m, int n)
{
        printf("\nA matrix. M = %d N = %d:\n", m, n);
        for(int i = 0; i<m; ++i)
        {
                for(int j = 0; j<n; ++j)
                        printf("%d ", a[i*n+j]);
                puts("");
        }
        puts("");
}
Вывод при (f 3 3 7 8):
A matrix. M = 3 N = 3:
1 2 3
4 5 6
7 8 9


A matrix. M = 7 N = 8:
1 2 3 7 7 7 7 7
4 5 6 7 7 7 7 7
7 8 9 7 7 7 7 7
7 7 7 7 7 7 7 7
7 7 7 7 7 7 7 7
7 7 7 7 7 7 7 7
7 7 7 7 7 7 7 7


Love5an
()
Ответ на: комментарий от Love5an

для наглядности стоит даже, наверное

(dotimes (i (array-total-size a)) 
  (setf (row-major-aref a i) (1+ i))) 
заменить на
(dotimes (i m)
  (dotimes (j n)
    (setf (aref a i j) (+ (* i n) j 1))))

Love5an
()
Ответ на: комментарий от Love5an
#include <stdio.h>
#include <stdlib.h>

int **realloc_matrix(int **a, int ox, int oy, int x, int y, int f)
{
    int i, j;

    int **m = (int **)realloc(a, sizeof(int *) * x);
    if (a == NULL) 
        m[0] = NULL;
    int *n = (int *)realloc(m[0], sizeof(int) * x * y);

    for (i= 0; i< x; i++)
        m[i] = n + i*y;

    for (i = x-1; i >= 0 ; i--) 
        for (j = y-1; j >= 0; j--) {
			if ((i < ox) && (j < oy))
                m[i][j] = m[(i*ox + j)/y][(i*ox + j)%y];
			else
                m[i][j] = f;
		}

    return m;
}

void print_matrix(int **a, int m, int n) 
{ 
    int i, j;
	
    printf("\nA matrix. M = %d N = %d:\n", m, n); 
    for(i = 0; i<m; ++i) 
    { 
        for(j = 0; j<n; ++j) 
            printf("%d ", a[i][j]); 
        puts(""); 
    } 
    puts(""); 
}

int main()
{
    int **a = NULL, *b, i;

    a = realloc_matrix(a, 0, 0, 3, 3, 1);
    print_matrix(a, 3, 3);

    b = a[0];
    for (i= 0; i< 3*3; i++)                                                                          
        b[i] = i + 1; 
    print_matrix(a, 3, 3);
	
    a = realloc_matrix(a, 3, 3, 7, 8, 7);
    print_matrix(a, 7, 8);

    return 0;
}
A matrix. M = 3 N = 3:
1 1 1 
1 1 1 
1 1 1 


A matrix. M = 3 N = 3:
1 2 3 
4 5 6 
7 8 9 


A matrix. M = 7 N = 8:
1 2 3 7 7 7 7 7 
4 5 6 7 7 7 7 7 
7 8 9 7 7 7 7 7 
7 7 7 7 7 7 7 7 
7 7 7 7 7 7 7 7 
7 7 7 7 7 7 7 7 
7 7 7 7 7 7 7 7 

Так достаточно динамично ?

imhotep
()
Ответ на: комментарий от imhotep

Это не матрицы, это говно.
И вообще, говнокод адовый. За такую организацию массивов надо руки отрывать.


Ну и это, на массивы больших размерностей будешь такой же ad-hoc говнокод писать? в лиспе-то работается с любыми размерностями вообще.

И, прошло 2 часа. Это ты столько думал как вот это говно родить?

Love5an
()
Ответ на: комментарий от Love5an

Кстати, типичный пример C++ головного мозга. Якобы лоулевел, все под контролем, все можно красиво и эффективно сделать; а в итоге - тонны жуткого говнокода, оверхед у которого как по памяти, так и по производительности на порядок выше лисповского.

Love5an
()
Ответ на: комментарий от Love5an

Ты идиот - цель была многомерный динамический массив типа говнолиспового. Нормальные массивы я бы так не стал организовывать.

imhotep
()
Ответ на: комментарий от imhotep

Говно это то, что у тебя в голове, а не лисп :)
Идиот ты, я тебе даже наглядно на сишке продемонстрировал, как хранятся элементы в массивах в sbcl. А ты какое-то невнятное говно сделал.
Нормальные массивы в сях и плюсах сделать просто нельзя. Ну т.е. можно, тьюринг-полнота же, но затраты как правило того не стоят, да и, что главное, интерфейс прикрутить нормальный мало возможно, поэтому обходятся обычно всяким говном вроде std::vector.

Love5an
()
Ответ на: комментарий от Love5an

>я тебе даже наглядно на сишке продемонстрировал, как хранятся элементы в массивах в sbcl. А ты какое-то невнятное говно сделал.

Если ты не заметил - у меня они точно также лежат, разуй глаза. Можешь проверить на своем говнопринте.

print_matrix(&a[0][0], 3, 3);

imhotep
()

Вот тут даже оптимизация не помогает.

matrix<T>& operator = (matrix<T> &m)
{
	memcpy(this->Val,m.Val,Height*Width*sizeof(T));
	return *this;
}
И вызываю так:
A=B;
Вроде делаю то же самое, а скорость в два раза медленней чем
memcpy(A,B,n*n*sizeof(A3));

Zodd ★★★★★
() автор топика
Ответ на: комментарий от Love5an

>оверхед у которого как по памяти, так и по производительности на порядок выше лисповского.

Чего ты несешь - какой оверхед ? Твой говнолисп сделает тоже самое с динамическим массивом, потому что по-другому не получится с линейной памятью чтобы после изменения размерности сохранить структуру исходного массива.

imhotep
()
Ответ на: комментарий от imhotep

Я как бы код читать умею, в отличие от некоторых.

Вот это что за говно? За это говно надо руки отрывать.

    int **m = (int **)realloc(a, sizeof(int *) * x); 
    if (a == NULL)  
        m[0] = NULL
 
    for (i= 0; i< x; i++) 
        m[i] = n + i*y; 

Love5an
()
Ответ на: комментарий от imhotep

Говно это язык, на котором ты пишешь, ну и то, что у тебя в голове, еще раз. С какого хера ты вообразил, что знаешь как работает механизм adjust-array в sbcl?

Love5an
()
Ответ на: комментарий от Love5an

И чего тебе тут не нравится ? Там проверяется - выделяется память вновь что равносильно malloc или уже есть выделенная память. Цикл - индексируется массив указателей - на этапе компиляции неизвестна заранее размерность поэтому сгенерировать нормальную адресацию невозможно.

imhotep
()
Ответ на: комментарий от Love5an

>С какого хера ты вообразил, что знаешь как работает механизм adjust-array в sbcl?

Мне не нужно это знать - я знаю как устроена память. Для примера: изначально был кусок 10 байт [2][5] чтобы получить [3][5] 15 байт и сохранить структуру и при этом чтобы элементы лежали линейно в соответствии с новой размерностью тебе нужно полюбому менять местами ячейки памяти - хоть усрись. Возможно там сначала выделяется новый кусок через malloc а потом в соответствии с исходным массивом копируются значения и после этого разрушаентся старая память. Я не ставил целью наиболее эффективно что-то сделать.

imhotep
()
Ответ на: комментарий от Love5an

Этот оверхед - чтобы использовать скобочки - чтобы это был многомерный массив а не работа с указателями и адресацией, ты же этого добивался ?

imhotep
()
Ответ на: комментарий от imhotep

[2][5] --> [3][5] неудачный пример - тут как раз ничего менять не нужно - достаточно в конец дописать :) А вот хотя бы [2][5] --> [2][6] уже нужно менять, потому что элемент [2][1] станет элементом [1][6] если ничего не изменить и дале все уедет по цепочке.

imhotep
()
Ответ на: комментарий от imhotep

Да ты просто обкурился, как я вижу. Каким образом это релеватно? Говно из вектора указателей на каждую строку можно только упоротым придумать.

Этот оверхед - чтобы использовать скобочки - чтобы это был многомерный массив а не работа с указателями и адресацией, ты же этого добивался ?


Ты совсем дурак, я вижу, раз так и не понял мысль. Фишка, видишь ли, в том, что в Сях и C++ нормальных массивов нету.

Love5an
()
Ответ на: комментарий от Love5an

Ты определись долбоеп - нет динамических массивов или нет нормальных массивов. Я тебе опровергал твой высер №1. Второй твой высер даже опровергать не буду - ты его сам опроверг, когда привел пример с выводом массива на С - в памяти они ничем не отличаются, а работа с адресацией в твоем долбаном лиспе явно не быстрей чем на С будет.

imhotep
()
Ответ на: комментарий от imhotep

Ты определись долбоеп - нет динамических массивов или нет нормальных массивов. Я тебе опровергал твой высер №1.

А у тебя что, нормальный или динамический массив? :) Это не массив, деточка, это говно. Ты вообще в курсе, что такое массив и чем он от списка отличается, например?

Второй твой высер даже опровергать не буду - ты его сам опроверг,

Ыы. Массив это он в лиспе. А в сях - линейный кусок говна памяти.

а работа с адресацией в твоем долбаном лиспе явно не быстрей чем на С будет.

Олололо. Я раньше тоже так думал. А сейчас вот как смотрю на образцы говнокода на плюсах и сях, вроде твоего, все больше начинаю в этом дичайше сомневаться.

Love5an
()
Ответ на: комментарий от Love5an

>Это не массив, деточка, это говно. Ты вообще в курсе, что такое массив и чем он от списка отличается, например?

Ты сам то чучело знаешь что такое массив ? Как ты обращаешься к его элементам - через косвенную адресацию или через базовую/индексную роли не играет.

imhotep
()
Ответ на: комментарий от Love5an

Ты настолько туп, что будешь отрицать что элементы моего массива в памяти расположены точно так же как в твоем говнолиспе ?

imhotep
()
Ответ на: комментарий от imhotep

Говно у тебя в голове, еще раз.

структура данных "массив":
...<[H]>[1]...[m,n,...]...
размер: O(n) + C(на заголовок);
доступ - по простенькой формуле(row-major/column-major), для доступа нужно знать: адрес первого элемента, размерности.

структура данных "невнятное говно от неумного второкурсника-плюсофила":
                  __________________
            _____|______________    |
    _______|_____|__________    |   |
   V       V     V          |   |   |
...[1]...[n1]...[n2]... ...[m1][m2][m3]...
no comments
Love5an
()
Ответ на: комментарий от Love5an

Ну и нахрена ты мне все это написал ? Еще раз для тупых - такая адресация была взята _специально_ чтобы средствами языка имитировать обычный многомерный массив со скобками. Именно поэтому я в твоем говнопринте заменил работу с адресами твоими любимыми скобками. В реальной жизни я таким говном не пользуюсь. А структура данных там абсолютно одинаковая - можешь проверить передав в свой говнопринт адрес первого элемента моего супермассива :)

imhotep
()
Ответ на: комментарий от imhotep

Чтобы освежить память, ты написал вот это:

В Си для адресации элемента в двумерном(и вообще *-мерном, тем более) массиве через встроенные средства языка(т.е. не подсчет оффсета по row-major ручками) надо чтобы компилятор знал размерности(конкретно для матриц - количество столбцов) массива статически. Многомерные массивы там вообще статические с какой стороны не посмотри - их даже аллоцировать нельзя в рантайме(можно только одномерные, напомню), не то что менять их размерности


вот я тебе и ответил что можно все сделать при желании и в динамике.

imhotep
()
Ответ на: комментарий от Love5an

>доступ - по простенькой формуле(row-major/column-major), для доступа нужно знать: адрес первого элемента, размерности.

Вот это кстати в С на х86 реализуется на асме через lea которая на всех последних процессорах заоптимизирована по самое нехочу при вычислении адреса с умножением на константу, что со своими динамическими массивами лисп не сможет сделать ибо нужно знать размеры еще на этапе компиляции.

imhotep
()
Ответ на: комментарий от imhotep

Ыыы. С чего это не может?

(defun f (a m n)
  (declare (type (simple-array fixnum (* 10)) a)
           (type fixnum m n)
           (optimize (speed 3) (space 0) (safety 0) (debug 0)))
  (aref a m n))
; disassembly for F
; 240C6FDA:       D1E7             SHL EDI, 1                 ; no-arg-parsing entry point
;       DC:       8D04BF           LEA EAX, [EDI+EDI*4]
;       DF:       01F0             ADD EAX, ESI
;       E1:       8BC8             MOV ECX, EAX
;       E3:       8B4209           MOV EAX, [EDX+9]
;       E6:       8B540801         MOV EDX, [EAX+ECX+1]
;       EA:       8BE5             MOV ESP, EBP
;       EC:       F8               CLC
;       ED:       5D               POP EBP
;       EE:       C3               RET

Love5an
()
Ответ на: комментарий от imhotep

Вот же ты идиот, а. На брейнфаке - тоже можно все сделать.
Массивов динамических ни в Си(многомерных, по крайней мере), ни в С++(вообще никаких, если не считать убогий std::vector и сотоварищей) нет. То, что ты предъявил это не многомерный массив, это говно. С таким же успехом мог предъявить просто массив указателей.

Love5an
()
Ответ на: комментарий от Zodd

тема увы засрана.

как определял «скорость»? тут это ключевой момент тк разницы без ошибки прибора быть не может. imho Сделай релизную сборку и прогони в VTune.

sleepy
()
Ответ на: комментарий от Love5an

Какое-то нагромождение говна - свалили все в кучу и перемешали. Пипец оптимально :) clc на выходе - это такая эмуляция ДОС вызовов ? :)

imhotep
()
Ответ на: комментарий от sleepy

Скорость определял по замеру времени. Когда речь идет про разы, точность прибора уже не так важна.

//Ппц. Устроили тут холивар. Похоже С++ vs ваш_любимый_язык нужно занести в оффтоп.

Zodd ★★★★★
() автор топика
Ответ на: комментарий от Zodd

> Похоже С++ vs ваш_любимый_язык нужно занести в оффтоп.

скорее лисп vs все остальное

lester ★★★★
()
Ответ на: комментарий от Zodd

не может быть в 2 раза.

можешь выложить запускаемый пример который бы это демонстрировал ? зы под оффтопиком не забываем #define _SECURE_SCL 0 и прочие фокусы.

sleepy
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.