Работа с матрицами

Jaroslava
Offline
Зарегистрирован: 30.11.2015

Здравствуйте, объясните пожалуйста как делать это задание:

Через последовательный код ввести матрицы 3*3 или 4*4 и переумножить две матрицы

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Jaroslava пишет:

Здравствуйте, объясните пожалуйста как делать это задание:

Есть два пути:

Путь первый:

1) сесть за стол;
2) почесать репу;
3) сделать;
4) если что-то по мелочи не получается, обратиться сюда со скетчем и объяснениями что не получается и как должно быть. Поможем.

Путь второй:

1) перейти в раздел "Ищу исполнителя"
2) договориться с исполнителем
3) заплатить денюшку
4) получить готовую работу.

Jaroslava
Offline
Зарегистрирован: 30.11.2015

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

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

А там без разницы, матрицы или ещё чего - просто вводить числа по одному и всё. Можно первым(и) ввести размер матрицы, а дальше числа одно за одним. Попробуйте сначала ввести одно число. Если это сможете, то и матрицу введёте. Если не можете ввести одно число, скажите в чём проблема? Типа "не знаю функции ввода", "не могу описать число" и т.п. В чём беда?

Jaroslava
Offline
Зарегистрирован: 30.11.2015
void setup() { 
int i = 0;
int j = 0;
while(j < 4)
{
while (Serial.available() < 4 * 2) // ожидание, пока во входном буфере не появится 40 байт
{  // 40 байт -- одна строка матрицы из 4 элементов типа int
}
for(i = 0; i < 4; i++)
{
unsigned int tmp1 = Serial.read();  // считывание очередного байта из буфера
unsigned int tmp2 = Serial.read();

}
j++;
}  

}

Такое начало правильное?

Jaroslava
Offline
Зарегистрирован: 30.11.2015
void setup() {
  struct Data
    {
      uint8_t value1_1;
      uint8_t value1_2;
      uint8_t value1_3;
    };
    Data array[3] =
    {
      {1,2,3 },
      {4,5,6},
      {7,8,9}
    };

Или так?

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Ярослава, сейчас не могу, но завтра обязательно посмотрю и отпишусь. Вы ввели одно число? Можете это сделать?

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Ну, как бы, не совсем. Вы пытаетесь всё усложнить. Зачем? Всё намного проще. 

Вам ведь что нужно, давайте распишем.

1. ввести размер матриц (матрицы всегда квадратные? или могут быть 3х4 и 4х3? уточните). Т.е. вводится одно или два числа (N или N и M)
2. ввести первую матрицу A - т.е. пачку чисел в количестве NхN (или NxM).
3. ввести вторую матрицу B - т.е. пачку чисел в количестве NхN (или NxM).
4. Посчитать третью матрицу C по известной формуле.
5. Вывести матрицу С на печать.

Вот собственно и всё. Ну, там по дороге может стоит, например, печатать введённые матрицы A и B для контроля. Но это (печать матрицы) нам и так нужно в п.5, так что дополнительных усилий для этого не потребуется.

Т.е., как видите, от Вас требуется уметь ввести одно число и уметь сделать это в цикле.

В принципе, мне нетрудно Вам помочь, но если Вам это нужно ответьте не несколько вопросов:

1.     Матрицы квадратные или могут быть прямоугольными?

2.     Матрицы состоят из целых чисел или из действительных (если всё равно, то лучше остановиться на втором)?

3.     Вы хотите, чтобы я подталкивал Вас шаг за шагом (чтобы в итоге Вы сделали всё сами) или просто сделал всё сразу?

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

5.     И последнее, делать будем «по уму» (более или менее профессионально) или «так. как делают новички»?

Если Вам нужна помощь, ответьте пожалуйста на все пять вопросов по пунктам.

Jaroslava
Offline
Зарегистрирован: 30.11.2015

1.Квадратные

2.Всё равно

3.Хочу сама. Я хочу розобраться как это делать.

4.Да. Нужно сдать через неделю

5.По уму

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Ну, давайте попробуем.

Для начала, знайте, что можно вводить из Serial числа с одновременным их преобразованием в машинный формат, а также с фильтром всякой грязи - типа игнорировать пробемы и буквы - вводить только числа. Для этого есть функции parseInt и parseFloat.

Правда, у них есть таймаут (по умолчанию - 1 секунда). Если за это время разумное число не введено, функция возвращает 0. Слава Богу, таймаут можно свой поставить.

Посмотрите на скетч ниже. Запустите его. Попробуйте вводить числа, буквы пробелы и т.п. и убедитесь, что Вы чётко понимаете, что этот скетч делает и теперь знаете как вводить число. Если есть вопросы - задавайте. Если нет, скажите мне, пойдём дальше.

//
//	Бесконечный таймаут для форматированного ввода
//
#define	ENDLESS	0xffffffff

void setup() {
	//
	//	Инициализация Serial
	//
	Serial.begin(115200);
	Serial.setTimeout(ENDLESS);
}

void loop() {
	//
	//	Ввод целого числа
	//
	Serial.print("Enter integer: ");
	int n = Serial.parseInt();
	//
	//	Печать введённого числа для контроля
	//
	Serial.println(n);

	//
	//	Ввод действительного числа
	//
	Serial.print("Enter float: ");
	float f = Serial.parseFloat();
	//
	//	Печать введённого числа для контроля
	//
	Serial.println(f);
}

 

Jaroslava
Offline
Зарегистрирован: 30.11.2015

Всё понятно, вопросов нет.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Ну, вот и чудненько.

Теперь Вы можете Напечатать приглашение типа "Enter matrix size:" и ввести размер матрицы.

После этого Вам необходимо запросить память под две матрицы. Матрицы у нас будут из вещественных чисел, поэтому Вы вне всякой функции должны описать два указателя на вещественное число. а после запроса размера, запросить память для обеих матриц (для обоих указателей). Количнство памяти, которое нужно запрашивать, очевидно равно квадрату размера матрицы, умноженному на количество памяти, необходимое для хранения одного действительно числа. 

Для одной матрицы описание указателя и запрос памяти выглядят примерно так.

float * matrixA;
.....
matrixA = malloc(n*n*sizeof(float));
if (! matrixA) Serial.println("ERROR: Not enough memory");

здесь предполагается. что n - ранее описанная переменная целого типа в которую Вы ввели размер матрицы.

Попробуйте написать скетч до этого места самостоятельно. Итак:

1. Описание двух указателей на float - будущих матриц

2. Запрос у юзера размера матрицы

3. запрос памяти для обеих матриц.

Всё, что вводите - пчатайте для контроля.

Получится - не получится, всё равно выкладывайте сюда скетч. Будем смотреть и идти дальше.

Jaroslava
Offline
Зарегистрирован: 30.11.2015
#define ENDLESS 0xffffffff
void setup() {
  Serial.begin(115200);
  Serial.setTimeout(ENDLESS);
 

}

void loop() {
    float * matrixA;
    Serial.print("Enter matrix size: ");
    int n = Serial.parseInt();
    if (! matrixA) Serial.println("ERROR: Not enough memory");
    Serial.println(n);
    Serial.print("Enter float: ");
    float f = Serial.parseFloat();
    Serial.println(f);

    float * matrixB;
    Serial.print("Enter matrix size: ");
    int m = Serial.parseInt();
    if (! matrixB) Serial.println("ERROR: Not enough memory");
    Serial.println(m);
    Serial.print("Enter float: ");    
    float v = Serial.parseFloat();
    Serial.println(v);
 

}

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Давайте разбираться.

Вам действительно надо. чтобы всё, что у Вас в lopp работало бесконечное количесвто раз? Если надо, то ладно, а если надо, чтобы один раз сработалр - переносите в setup.

Между строками 12 и 13 Вы пропустили собственно запрос памяти. Т.е. строка 13 проверяет выделена ли память, а запросить её Вы забыли. Там надо вставить что-то типа matrixA = malloc(n*n(sizeof(float));

Строку 14 лучше поставить сразу после строки 12.

Для чего нужны строки 15-17 я не понял. По-моему, не нужны.

В принципе, мы нигде не проверяем n - а вдруг кто-то пошутил и нам ноль подсунул или отрицательное сичло, но это ладно - потом.

В общем, исправьте с учётом всех замечаний.

Jaroslava
Offline
Зарегистрирован: 30.11.2015
#define ENDLESS 0xffffffff
void setup() {
  Serial.begin(115200);
  Serial.setTimeout(ENDLESS);
 

}

void loop() {
   float * matrixA;
    Serial.print("Enter matrix size: ");
    int n = Serial.parseInt();
    Serial.println(n);
    matrixA = malloc(n*n(sizeof(float));
    if (! matrixA) Serial.println("ERROR: Not enough memory");


    float * matrixB;
    Serial.print("Enter matrix size: ");
    int m = Serial.parseInt();
    Serial.println(m);
    matrixA = malloc(m*m(sizeof(float));
    if (! matrixB) Serial.println("ERROR: Not enough memory");
   
   
 

}

В 14 строке почему-то выдает ошибку что "n не может  быть использована в качестве функции". 

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Потому, что Вы нигде не определили функцию n().

Но если Вы даже ее определите, ошибка не уйдет. Вероятнее всего, Вы порпустили знак умножения между n и sizeof().

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Ярослава, просто в посте 13 у меня опечатка, а в посте 11 (строка 3 в коде) та же строка написана правильно. Смотрите внимательнее и поправьте.

Jaroslava
Offline
Зарегистрирован: 30.11.2015

   #define ENDLESS 0xffffffff
void setup() {
  Serial.begin(115200);
  Serial.setTimeout(ENDLESS);
 

}

void loop() {
   float * matrixA;
    Serial.print("Enter matrix size: ");
    int n = Serial.parseInt();
    Serial.println(n);
    matrixA = malloc(n*n*sizeof(float));
    if (! matrixA) Serial.println("ERROR: Not enough memory");


    float * matrixB;
    Serial.print("Enter matrix size: ");
    int m = Serial.parseInt();
    Serial.println(m);
    matrixB = malloc(m*m*sizeof(float));
    if (! matrixB) Serial.println("ERROR: Not enough memory");
   
 }
ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Всё нормально работает? Без приключений и непоняток? Вы хоть пишите что-нибудь :)

Jaroslava
Offline
Зарегистрирован: 30.11.2015

В 22 строке ошибка "invalid conversion from 'void*' to 'float*' [-fpermissive]". Как ее устранить?

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Jaroslava пишет:

В 22 строке ошибка "invalid conversion from 'void*' to 'float*' [-fpermissive]". Как ее устранить?

Очень просто. добавьте преобразование типа:

matrixB = (float *) malloc(m*m*sizeof(float));

кстати, тоже самое надо сделать и в 14 строке.

Добейтесь, чтобы работало всё как надо.

Jaroslava
Offline
Зарегистрирован: 30.11.2015
Я все испрвила но выдает такую ошибку
 
 
avrdude: ser_open(): can't open device "\\.\COM1": Отказано в доступе.
 
 
Проблема загрузки в плату.
avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 1 of 10: not in sync: resp=0x7a
avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 2 of 10: not in sync: resp=0x7a
avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 3 of 10: not in sync: resp=0x7a
avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 4 of 10: not in sync: resp=0x7a
avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 5 of 10: not in sync: resp=0x7a
avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 6 of 10: not in sync: resp=0x7a
avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 7 of 10: not in sync: resp=0x7a
avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 8 of 10: not in sync: resp=0x7a
avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 9 of 10: not in sync: resp=0x7a
avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 10 of 10: not in sync: resp=0x7a
Проблема загрузки в плату. 
ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Ну, это с программой никак не связано. У Вас порт почему-то занят. Закройте IDE (все окна). Вытащите ардуину из USB и воткните снова. Запустите IDE. Если не поможет, перезагрузите компьютер.

Jaroslava
Offline
Зарегистрирован: 30.11.2015

Спасибо, теперь всё работает.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Ну, вот и чудненько. Можно продолжать.

Для начала уберите из программы второй запрос размера матрицы (m) - Вы же не собираетесь перемножать матрицы разных размеров? Тогда зачем Вам m, если она всё равно обязана быть равной n? Убирайте запрос m. Останется один запрос размера и два запрса памяти n*n*sizeof(float) каждый. 

Кстати, у нас что-то не очень быстро получается - неделя прошла. Если жизнь заставляет вернуться к п. 3 из поста 7, не стесняйтесь, предложение всё ещё в силе.

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

Итак, для начала давайте поймём, что то, что мы запросили для matrixA  - это просто кусок памяти, состоящий из n*n чисел типа float. Нумеруются они традиционно с нуля, значит у нас есть числа от matrixA[0] до matrixA[n*n-1]. К ним (числам) можно обращаться через этот индекс, например, matrixA[0], matrixA[1], ... matrixA[n*n-1].

Но нам бы хотелось обращаться более традиционным для матриц способом - через два индекса: номер строки и номер столбца, так же? Давайте это сделаем. Для начала условимся, что матрица у нас в памяти хранится, например, по строкам - т.е. сначала в памяти идёт первая строка (n чисел), затем вторая строка (n чисел), и т.д. В этом нет ничего магического. Мы могли бы договориться, что хранится всё по столбцам - главное как-то договориться и потом действовать везде одинаково чтобы не получилось, что записываем матрицу в память по строкам, а читаем по столбцам :) И, кстати, как это принято в программировании, строки и столбцы мы будем нумеровать от 0 до n-1 (а не от 1 до n).

Для доступа к элементам напишем маленькую функцию elem. Параметрами у неё будут: указатель на начало памяти, где хранится матрица, длина строки, номер строки и номер столбца. Возвращать она будет ссылку на нужный элемент. То, что именно ссылку - очень важно. В этом случае функцию можно использовать не только, чтобы взять элемент, но чтобы записать в него значение, т.е. функцию, возвращающую ссылку можно использовать в левой части оператора присваивания. Функция очень простая.

Для начала представьте себе, что все элементы матрицы пронумерованы сквозным индексрм - нулевая строка от 0 до n-1, первая - от n до 2n-1, вторая - от 2n до 3n-1 и т.д. Как по номеру строки и столбца узнать этот индекс? Очевидно, что индекс будет равен сумме номера столбца и произведения номера строки на длину строки.  Так и напишем:

float & elem(float * matrix, const int n, const int row, const int column) {
	return matrix[row * n + column];
}

вот собственно и вся функция доступа к элементам.

Теперь, необходимо убедиться, что она правильно работает в обе стороны, т.е. в том, что с её помощью можно как присвоить значение элементу, так и взять его оттуда. Для этого запустим такой скетч:

#define ENDLESS 0xffffffff

float & elem(float * matrix, const int n, const int row, const int column) {
	return matrix[row * n + column];
}

void setup() {
	Serial.begin(115200);
	Serial.setTimeout(ENDLESS);

	float * matrixA;
	Serial.print("Enter matrix size: ");
	int n = Serial.parseInt();
	Serial.println(n);
	matrixA = (float *) malloc(n*n*sizeof(float));
	if (! matrixA) Serial.println("ERROR: Not enough memory");

	//
	//	Присваиваем значения некоторым элементам
	//
	elem(matrixA, n, 0, 2) = 902;
	elem(matrixA, n, 1, 1) = 911;
	elem(matrixA, n, 0, 0) = 900;
	//
	//	Печатаем присвоенные значения для проверки
	//
	Serial.print("A[0,2]="); Serial.println(elem(matrixA, n, 0, 2));
	Serial.print("A[1,1]="); Serial.println(elem(matrixA, n, 1, 1));
	Serial.print("A[0,0]="); Serial.println(elem(matrixA, n, 0, 0));
}

void loop() {}

попробуйте. У меня получился вот такой результат:

Enter matrix size: 5
A[0,2]=902.00
A[1,1]=911.00
A[0,0]=900.00

Вроде всё присвоилось и взялось правильно.

Теперь сдлеайте следующее:

1. Запустите скетч, потрогайте его и убедитесь, что Вам он понятен и вопросов не осталось (если остались - задавайте)
2. Уберите ввод m, как я писал в начале этого поста.
3. Скажите мне, знакомы ли Вы с циклами for и можете ли написать поэлементый ввод матрицы самостоятельно (с использованием нашей сегодняшней функции). Если думаете. что можете - напишите и опробуйте (и для мне выложите). Пусть даже неправильно, но это лучше, чем никак. Если же совсме не можете- будем думать вместе.

 

 

 

Jaroslava
Offline
Зарегистрирован: 30.11.2015
#define ENDLESS 0xffffffff

float & elem(float * matrix, const int n, const int row, const int column) {
  return matrix[row * n + column];

}
void setup() {
  Serial.begin(115200);
  Serial.setTimeout(ENDLESS);
  
 }
void loop() {

 int PWMpin = 10;
  for (int i=0; i <= 1000; i++){
     analogWrite(PWMpin, i);
      delay(10); }}

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Что это было? Поэлеиентный ввод матрицы? Ну м как, вводится? :)

Jaroslava
Offline
Зарегистрирован: 30.11.2015

Нет))

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Окей, чуть позже сегодня, поговорим о вводе, сейчас я убегаю.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Внимательно разберите этот скетч и задайте вопросы, если есть.

Запустите и убедитесь, что он успешно вводит одну (хотя память запрашивает под обе) матрицу и благополучно её печатает для контроля.

Добавьте ввод и печать второй матрицы и выложите получившийся скетч (если не заработает, всё равно выложите и напишите в чём проблема.

Как только Вы это сделаете, нам останется только перемножить их и напечатать результат. Но, последнее (печать) мы уже умеем - эти ж матрицы мы печатаем.

#define ENDLESS 0xffffffff

float & elem(float * matrix, const int n, const int row, const int column) {
	return matrix[row * n + column];
}

void setup() {
  Serial.begin(115200);
  Serial.setTimeout(ENDLESS);
}

void loop() {
	bool SizeNotEntered = true;
	int n;

	//
	//	Вввод размера матрицы
	//
	while (SizeNotEntered) {
		Serial.println("Enter matrix size: ");
		n = Serial.parseInt();
		SizeNotEntered = (n < 2 || n > 5);
		if (SizeNotEntered) Serial.println("error: matrix size must be between 2 and 5");
	}
	Serial.print("Matrix size is ");
	Serial.println(n);

	//
	//	Запрос памяти
	//
	float *	matrixA = (float *) malloc(n*n*sizeof(float));
	float *	matrixB = (float *) malloc(n*n*sizeof(float));
	if (! matrixA || !matrixB) {
		Serial.println("error: not enough memory");
		if (matrixB) free(matrixB);
		if (matrixA) free(matrixA);
		return;
	}
	
	//
	//	Ввод значений матрицы А
	//
	Serial.println("Enter matrix A");
	//	Цикл по строкам
	for (int row = 0; row < n; row++) {
		Serial.print("ROW ");
		Serial.print(row);
		Serial.print("(");
		Serial.print(n);
		Serial.println(" float numbers separated with space or comma):");
		// цикл по столбцам внутри строки
		for (int column = 0; column < n; column ++) {
			elem(matrixA, n, row, column) = Serial.parseFloat();
		}
	}
	//
	//	Печать значений матрицы A для контроля
	//
	Serial.println("Matrix A");
	//	Цикл по строкам
	for (int row = 0; row < n; row++) {
		// цикл по столбцам внутри строки
		for (int column = 0; column < n; column ++) {
			Serial.print(elem(matrixA, n, row, column));
			Serial.print(" ");
		}
		Serial.println();
	}
	
	//
	//	Освобождение памяти
	//
	free(matrixB);
	free(matrixA);
 }

 

Jaroslava
Offline
Зарегистрирован: 30.11.2015
#define ENDLESS 0xffffffff

float & elem(float * matrix, const int n, const int row, const int column) {
    return matrix[row * n + column];
}
void setup() {
  Serial.begin(115200);
  Serial.setTimeout(ENDLESS);
}

void loop() {
    bool SizeNotEntered = true;
    int n;
    //
    //  Вввод размера матрицы
    //
    while (SizeNotEntered) {
        Serial.println("Enter matrix size: ");
        n = Serial.parseInt();
        SizeNotEntered = (n < 2 || n > 5);
        if (SizeNotEntered) Serial.println("error: matrix size must be between 2 and 5");
    }
    Serial.print("Matrix size is ");
    Serial.println(n);
    //
    //  Запрос памяти
    //
    float * matrixA = (float *) malloc(n*n*sizeof(float));
    float * matrixB = (float *) malloc(n*n*sizeof(float));
    if (! matrixA || !matrixB) {
        Serial.println("error: not enough memory");
        if (matrixB) free(matrixB);
        if (matrixA) free(matrixA);
        return;
    }
    //
    //  Ввод значений матрицы А
    //
    Serial.println("Enter matrix A");
    //  Цикл по строкам
    for (int row = 0; row < n; row++) {
        Serial.print("ROW ");
        Serial.print(row);
        Serial.print("(");
        Serial.print(n);
        Serial.println(" float numbers separated with space or comma):");
        // цикл по столбцам внутри строки
        for (int column = 0; column < n; column ++) {
            elem(matrixA, n, row, column) = Serial.parseFloat();
        }
    }
    //
    //  Печать значений матрицы A для контроля
    //
    Serial.println("Matrix A");
    //  Цикл по строкам
    for (int row = 0; row < n; row++) {
        // цикл по столбцам внутри строки
        for (int column = 0; column < n; column ++) {
            Serial.print(elem(matrixA, n, row, column));
            Serial.print(" ");
        }
        Serial.println();
    }

    //
    //  Ввод значений матрицы B
    //
    Serial.println("Enter matrix B");
    //  Цикл по строкам
    for (int row = 0; row < n; row++) {
        Serial.print("ROW ");
        Serial.print(row);
        Serial.print("(");
        Serial.print(n);
        Serial.println(" float numbers separated with space or comma):");
        // цикл по столбцам внутри строки
        for (int column = 0; column < n; column ++) {
            elem(matrixB, n, row, column) = Serial.parseFloat();
        }
    }
    //
    //  Печать значений матрицы B для контроля
    //
    Serial.println("Matrix B");
    //  Цикл по строкам
    for (int row = 0; row < n; row++) {
        // цикл по столбцам внутри строки
        for (int column = 0; column < n; column ++) {
            Serial.print(elem(matrixA, n, row, column));
            Serial.print(" ");
        }
        Serial.println();
    }
    //
    //  Освобождение памяти
    //
    free(matrixB);
    free(matrixA);
 }

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Вы это проверяли в работе? Запускали, внимательно смотрели?

У Вас не печатается матрица B, а вместо неё второй раз печатается матрица A.

Найдите ошибку.

SU-27-16
SU-27-16 аватар
Offline
Зарегистрирован: 13.08.2012

великий и ужасный КОПИПАСТ :)
ЕвгенийП ,  классная лекция !!!!!!!!! :)
....тоже учусь , извини , что влез

пытаюсь ещё англицкий понимать....
вот это - if (SizeNotEntered) Serial.println("error: matrix size must be between 2 and 5"); - 
не будет ли более правильным - 
"error: matrix size must be between 1 and 6"

а вот это

032         if (matrixB) free(matrixB);
033         if (matrixA) free(matrixA);

перестраховка ? или так и надо ОБЯЗАТЕЛЬНО делать ?
типа - если не выделена память то зачем её освобождать ?
флаг выделения памяти не сбрасывается автоматически , чоли ,  если памяти не хватает ?

спасибо !

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Привет!

По первому вопросу - не знаю, как Вам нравится.

По-второму - проверка-то была на два указателся сразу и мы не знаем кто из них NULL, потому и проверяем. В принципе, в avr-libc, кажется, освобождение указателя, который NULL безопасно - просто ничего не делается, но это не везде так и пишется уже на автомате.

SU-27-16
SU-27-16 аватар
Offline
Зарегистрирован: 13.08.2012

спасибо 

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

SU-27-16 пишет:

перестраховка ? или так и надо ОБЯЗАТЕЛЬНО делать ?

Лично я ВСЕГДА пишу:

if(matrixB){
free(matrixB);
matrixB = NULL;
}

Возможно, привычка берет начало с языков, в которых конструктор вызывавется явно, и для C++ это избыточно.

Но для С, мне кажется, это не лишняя проверка.

Jaroslava
Offline
Зарегистрирован: 30.11.2015

К сожалению я не могу найти ошибку.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Jaroslava пишет:

К сожалению я не могу найти ошибку.

Ну, постарайтесь повнимательнее. Строку 90 посмотрите внимательно.

Jaroslava
Offline
Зарегистрирован: 30.11.2015
#define ENDLESS 0xffffffff

float & elem(float * matrix, const int n, const int row, const int column) {
    return matrix[row * n + column];
}
void setup() {
  Serial.begin(115200);
  Serial.setTimeout(ENDLESS);
}

void loop() {
    bool SizeNotEntered = true;
    int n;
    //
    //  Вввод размера матрицы
    //
    while (SizeNotEntered) {
        Serial.println("Enter matrix size: ");
        n = Serial.parseInt();
        SizeNotEntered = (n < 2 || n > 5);
        if (SizeNotEntered) Serial.println("error: matrix size must be between 2 and 5");
    }
    Serial.print("Matrix size is ");
    Serial.println(n);
    //
    //  Запрос памяти
    //
    float * matrixA = (float *) malloc(n*n*sizeof(float));
    float * matrixB = (float *) malloc(n*n*sizeof(float));
    if (! matrixA || !matrixB) {
        Serial.println("error: not enough memory");
        if (matrixB) free(matrixB);
        if (matrixA) free(matrixA);
        return;
    }
     //
    //  Ввод значений матрицы А
    //
    Serial.println("Enter matrix A"); 
   //  Цикл по строкам
    for (int row = 0; row < n; row++) {
        Serial.print("ROW ");
        Serial.print(row);
        Serial.print("(");
        Serial.print(n);
        Serial.println(" float numbers separated with space or comma):");
        // цикл по столбцам внутри строки
        for (int column = 0; column < n; column ++) {
      elem(matrixA, n, row, column) = Serial.parseFloat();
        }
    }
     //
    //  Печать значений матрицы A для контроля
    //
    Serial.println("Matrix A");
   //  Цикл по строкам
    for (int row = 0; row < n; row++) {
        // цикл по столбцам внутри строки
        for (int column = 0; column < n; column ++) {
            Serial.print(elem(matrixA, n, row, column));
            Serial.print(" ");
        }
        Serial.println();
    }
     //
    //  Ввод значений матрицы B
    //
    Serial.println("Enter matrix B");
    //  Цикл по строкам
    for (int row = 0; row < n; row++) {
        Serial.print("ROW ");
        Serial.print(row);
        Serial.print("(");
        Serial.print(n);
        Serial.println(" float numbers separated with space or comma):");
        // цикл по столбцам внутри строки
        for (int column = 0; column < n; column ++) {
            elem(matrixB, n, row, column) = Serial.parseFloat();
        }
    }
    //
    //  Печать значений матрицы B для контроля
    //
    Serial.println("Matrix B");
    //  Цикл по строкам
    for (int row = 0; row < n; row++) {
        // цикл по столбцам внутри строки
        for (int column = 0; column < n; column ++) {
            Serial.print(elem(matrixB, n, row, column));
            Serial.print(" ");
        }
        Serial.println();
}
     
    //
    //  Освобождение памяти
    //
    free(matrixB);
    free(matrixA);
 }

 

Jaroslava
Offline
Зарегистрирован: 30.11.2015

А как матрицы перемножить?

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

По определению произведения матриц.

Ну, Ва проще, т.к. у Вас матрицы квадратные и n=m

Т.е. 

1. Запрашиваем память под третью матрицу

2. делаем двложенные циклы (внешний по строкам, внутренний по столбцам) и в этом цикле считаем значение Сij

3. Для этого сначала полагаем его нулём

4. А затем в ещё одном цикле прибавляем к нему произведение элементов матриц а и b.

Попробуйте, если не выйдет, завтра вместе будем пробовать

Jaroslava
Offline
Зарегистрирован: 30.11.2015
#define ENDLESS 0xffffffff //Нескінченний таймаут для форматованого введення

float & elem(float * matrix, const int n, const int row, const int column) {
    return matrix[row * n + column];
}
void setup() {
  // Ініціалізація Serial
  Serial.begin(9600);
  Serial.setTimeout(ENDLESS);
}

void loop() {
    bool SizeNotEntered = true;
    int n;
    //  Введення розміру матриці
    while (SizeNotEntered) {
        Serial.println("Enter matrix size: ");
        n = Serial.parseInt();
        SizeNotEntered = (n < 2 || n > 5);
        if (SizeNotEntered) Serial.println("error: matrix size must be between 2 and 5");
    }
    Serial.print("Matrix size is ");
    Serial.println(n);
    // Запит пам'яті
    float * matrixA = (float *) malloc(n*n*sizeof(float));
    float * matrixB = (float *) malloc(n*n*sizeof(float));
    float * matrixC = (float *) malloc(n*n*sizeof(float));
    if (! matrixA || !matrixB || !matrixC) {
        Serial.println("error: not enough memory");
        if (matrixC) free(matrixC);
        if (matrixB) free(matrixB);
        if (matrixA) free(matrixA);
        return;
    }
    // Введення значень матриці А
    Serial.println("Enter matrix A");
    //  Цикл по рядках
    for (int row = 0; row < n; row++) {
        Serial.print("ROW ");
        Serial.print(row);
        Serial.print("(");
        Serial.print(n);
        Serial.println(" float numbers separated with space or comma):");
        //  цикл по стовпцях усередині рядка
        for (int column = 0; column < n; column ++) {
            elem(matrixA, n, row, column) = Serial.parseFloat();
        }
    }
    //  Друк значень матриці A для контролю
    Serial.println("Matrix A");
    //  Цикл по рядках
    for (int row = 0; row < n; row++) {
        // цикл по стовпцях усередині рядка
        for (int column = 0; column < n; column ++) {
            Serial.print(elem(matrixA, n, row, column));
            Serial.print(" ");
        }
        Serial.println();
    }

      // Введення значень матриці B
    Serial.println("Enter matrix B");
    //  Цикл по рядках
    for (int row = 0; row < n; row++) {
        Serial.print("ROW ");
        Serial.print(row);
        Serial.print("(");
        Serial.print(n);
        Serial.println(" float numbers separated with space or comma):");
        // цикл по стовпцях усередині рядка
        for (int column = 0; column < n; column ++) {
            elem(matrixB, n, row, column) = Serial.parseFloat();
        }
    }
    //  Друк значень матриці B для контролю
    Serial.println("Matrix B");
    //  Цикл по рядках
    for (int row = 0; row < n; row++) {
        // цикл по стовпцях усередині рядка
        for (int column = 0; column < n; column ++) {
            Serial.print(elem(matrixB, n, row, column));
            Serial.print(" ");
        }
        Serial.println();
    }
    // Звільнення пам'яті
    free(matrixB);
    free(matrixA);
 }

Запрос памяти под третью матрицу я сделала, а вложенные циклы не получилось. 

SU-27-16
SU-27-16 аватар
Offline
Зарегистрирован: 13.08.2012
Определение 14.4   Произведением матрицы $ A$ размеров $ m\times n$ на матрицу $ B$ размеров $ n\times k$ называется матрица $ C$ размеров $ m\times k$ , элементы которой вычисляются по формуле

 

$\displaystyle c_{ij}=a_{i1}b_{1j}+a_{i2}b_{2j}+\ldots+a_{in}b_{nj}=\sum_{s=1}^n a_{is}  b_{sj},$ (14.5)


 

где $ i=1,\dots,m$ , $ j=1,\dots,k$ .         

 

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

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

В-третьих, размеры результата умножения определяются следующим образом: число строк результата равно числу строк первого сомножителя, а число столбцов результата равно числу столбцов второго сомножителя.

Правило вычисления элементов произведения можно сформулировать следующим образом.

Для того, чтобы вычислить элемент произведения, стоящий в $ i$ -ой строке и $ j$ -ом столбце, нужно взять $ i$ -ую строку первого сомножителя и $ j$ -ый столбец второго сомножителя, попарно перемножить их элементы, стоящие на одинаковых местах, и результаты сложить. (Точно так же мы поступаем, когда находим скалярное произведение двух векторов по их координатам, см. формулу (14.2).)

 

        Пример 14.3   Даны матрицы $ A=\left(\begin{array}{rrr}1&2&-1\\ 3&4&0\\ -1&2&-2\end{array}\right)$ , $ B=\left(\begin{array}{rr} 3&-2\\ 1&0\\ 4&-3\end{array}\right)$ . Найдите произведения $ AB$ и $ BA$ .

Решение. Рассмотрим произведение $ AB$ . Число столбцов в первом сомножителе $ (A)$ равно 3, число строк во втором сомножителе $ (B)$ тоже равно 3. Числа совпали, следовательно, произведение определено.

Результатом умножения будет матрица $ C$ , $ C=AB$ , у которой строк столько, сколько их в первом сомножителе, то есть 3, а столбцов столько, сколько их во втором сомножителе, то есть 2. Итак, матрица $ C$ имеет размеры $ 3\times 2$ .

Находим элемент $ c_{11}$ . В его вычислении участвует первая строка $ \left(\begin{array}{rrr}1&2&-1\end{array}\right)$ первого сомножителя $ (A)$ и первый столбец $ \left(\begin{array}{r}3\\ 1\\ 4\end{array}\right)$ второго сомножителя $ (B)$ :

 

$\displaystyle c_{11}=1\cdot3+2\cdot1+(-1)\cdot4=1.$

 

Находим элемент $ c_{12}$ . В его вычислении участвует первая строка $ \left(\begin{array}{rrr}1&2&-1\end{array}\right)$ первого сомножителя $ (A)$ и второй столбец $ \left(\begin{array}{r}-2\\ 0\\ -3\end{array}\right)$ второго сомножителя $ (B)$ :

 

$\displaystyle c_{12}=1\cdot(-2)+2\cdot0+(-1)\cdot(-3)=1.$

 

Все элементы первой строки матрицы $ C$ вычислены. Находим элемент $ c_{21}$ . В его вычислении участвует вторая строка $ \left(\begin{array}{rrr}3&4&0\end{array}\right)$ первого сомножителя $ (A)$ и первый столбец $ \left(\begin{array}{r}3\\ 1\\ 4\end{array}\right)$ второго сомножителя $ (B)$ :

 

$\displaystyle c_{21}=3\cdot3+4\cdot1+0\cdot4=13.$

 

Находим элемент $ c_{22}$ . В его вычислении участвует вторая строка $ \left(\begin{array}{rrr}3&4&0\end{array}\right)$ первого сомножителя $ (A)$ и второй столбец $ \left(\begin{array}{r}-2\\ 0\\ -3\end{array}\right)$ второго сомножителя $ (B)$ :

 

$\displaystyle c_{22}=3\cdot(-2)+4\cdot0+0\cdot(-3)=-6.$

 

Вычислены все элементы второй строки матрицы $ C$ . Аналогично находим элементы третьей строки:

 

$\displaystyle c_{31}=(-1)\cdot3+2\cdot1+(-2)\cdot4=-9,$

 

 

$\displaystyle c_{32}=(-1)\cdot(-2)+2\cdot0 +(-2)\cdot(-3)=8.$

 

Итак, $ C=\left(\begin{array}{rr}1&1\\ 13&-6\\ -9&8\end{array}\right)$ .

Рассмотрим произведение $ BA$ . Число столбцов в первом сомножителе $ (B)$ равно 2, число строк во втором сомножителе $ (A)$ равно 3. Числа не совпали, следовательно, произведение не определено.

Ответ: $ AB=\left(\begin{array}{rr}1&1\\ 13&-6\\ -9&8\end{array}\right)$ , произведение $ BA$ не определено.         

 

 

 

        Замечание 14.3   Легко проверить, что произведение квадратных матриц одного порядка всегда существует (определено).
Jaroslava
Offline
Зарегистрирован: 30.11.2015

Как делать вложенные циклы?

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Ярослава, так Вы же их делали - Вы вводили и печатали матрицы вложенными циклами.

Сегодня мне пришлось уехать, только сейчас вернулся домой, уже поздно. Завтра я показу Вам как перемножить, если до этого сами не сделаете.

SU-27-16
SU-27-16 аватар
Offline
Зарегистрирован: 13.08.2012

for ( byte n = 0; n < 100; n++ )
 {
    for ( byte m = 0; m < 100; m++ )    // вложенный_1
     {
        
for ( byte k = 0; k < 100; k++ )   // вложенный_2
         {

            // действия
          }
      }
 }

специально не для твоей задачи , а для ответа на вопрос :)

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Ну, смотрите, Ярослава, там просто три цикла: первые два по строкам и столбцам результирующей матрицы, а ещё один, чтобы накопить сумму по определению произведения матриц.

#define ENDLESS 0xffffffff //Нескінченний таймаут для форматованого введення

float & elem(float * matrix, const int n, const int row, const int column) {
    return matrix[row * n + column];
}
void setup() {
  // Ініціалізація Serial
  Serial.begin(115200);
  Serial.setTimeout(ENDLESS);
}

void loop() {
    bool SizeNotEntered = true;
    int n;
    //  Введення розміру матриці
    while (SizeNotEntered) {
        Serial.println("Enter matrix size: ");
        n = Serial.parseInt();
        SizeNotEntered = (n < 2 || n > 5);
        if (SizeNotEntered) Serial.println("error: matrix size must be between 2 and 5");
    }
    Serial.print("Matrix size is ");
    Serial.println(n);
    // Запит пам'яті
    float * matrixA = (float *) malloc(n*n*sizeof(float));
    float * matrixB = (float *) malloc(n*n*sizeof(float));
    float * matrixC = (float *) malloc(n*n*sizeof(float));
    if (! matrixA || !matrixB || !matrixC) {
        Serial.println("error: not enough memory");
        if (matrixC) free(matrixC);
        if (matrixB) free(matrixB);
        if (matrixA) free(matrixA);
        return;
    }
    // Введення значень матриці А
    Serial.println("Enter matrix A");
    //  Цикл по рядках
    for (int row = 0; row < n; row++) {
        Serial.print("ROW ");
        Serial.print(row);
        Serial.print("(");
        Serial.print(n);
        Serial.println(" float numbers separated with space or comma):");
        //  цикл по стовпцях усередині рядка
        for (int column = 0; column < n; column ++) {
            elem(matrixA, n, row, column) = Serial.parseFloat();
        }
    }
    //  Друк значень матриці A для контролю
    Serial.println("Matrix A");
    //  Цикл по рядках
    for (int row = 0; row < n; row++) {
        // цикл по стовпцях усередині рядка
        for (int column = 0; column < n; column ++) {
            Serial.print(elem(matrixA, n, row, column));
            Serial.print(" ");
        }
        Serial.println();
    }

      // Введення значень матриці B
    Serial.println("Enter matrix B");
    //  Цикл по рядках
    for (int row = 0; row < n; row++) {
        Serial.print("ROW ");
        Serial.print(row);
        Serial.print("(");
        Serial.print(n);
        Serial.println(" float numbers separated with space or comma):");
        // цикл по стовпцях усередині рядка
        for (int column = 0; column < n; column ++) {
            elem(matrixB, n, row, column) = Serial.parseFloat();
        }
    }
    //  Друк значень матриці B для контролю
    Serial.println("Matrix B");
    //  Цикл по рядках
    for (int row = 0; row < n; row++) {
        // цикл по стовпцях усередині рядка
        for (int column = 0; column < n; column ++) {
            Serial.print(elem(matrixB, n, row, column));
            Serial.print(" ");
        }
        Serial.println();
    }

	//
	//	перемножение матриц
	//
	//  Цикл по рядках
	for (int row = 0; row < n; row++) {
		// цикл по стовпцях усередині рядка
		for (int column = 0; column < n; column ++) {
			//	здесь вычисляем С[row, column]
			//	сначала 0, чтобы накапливать сумму
			elem(matrixC, n, row, column) = 0;	
			//
			// Накапливаем сумму точно по определению произведения матриц
			for (int r = 0; r < n; r++) {
				elem(matrixC, n, row, column) += elem(matrixA, n, row, r) * elem(matrixB, n, r, column);
			}
		}
	}			

    //  Друк значень матриці C
    Serial.println();
    Serial.println("Matrix C = A x B");
    //  Цикл по рядках
    for (int row = 0; row < n; row++) {
        // цикл по стовпцях усередині рядка
        for (int column = 0; column < n; column ++) {
            Serial.print(elem(matrixC, n, row, column));
            Serial.print(" ");
        }
        Serial.println();
    }
    Serial.println("---------------------------");
    Serial.println();

    // Звільнення пам'яті
    free(matrixC);
    free(matrixB);
    free(matrixA);
 }

1. Разберитесь
2. Запустите и проверьте что нормально работает
3. Задайте вопросы
4. убедитесь, что всё понятно и Вы сможете теперь сама сделать что-то подобное.

А теперь, если Вам ещё не надоего, мы можем приступить к самом интересному.

На мой вопрос "Вам надо как у новичков или по уму", Вы ответили "по уму". Так, вот, сейчас всё сделано "как у новичков". Если Вам еще не надоело это занятие, мы можем теперь, когда уже понятно как делать, переделать, чтобы было по уму. Код сократится раза в три и изменять его станет легче. Возможно, он станет понятнее. 

Продолжаем или хватит?

Jaroslava
Offline
Зарегистрирован: 30.11.2015

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

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Что значит не можете? Компилятор ругается или просто на экране монитора ничего не появляется (или появляется грязь)?

Если второе, то проверьте, чтобы скорость передачи (строка 8) совпадала со скоростью, которая указана в правом нижнем углу монитора порта. Кстати, в Вашей программе стояло 9600, это я поставил 115200.

Jaroslava
Offline
Зарегистрирован: 30.11.2015

Не запускается из-за того что у меня нет ардуины

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Это серьёзная причина! :)))

Вроде же была? Вы вроде на ошибки компиллятора жаловались. Ладно, скрин-то мне нетрудно сделать. Сейчас, найду какую-нибудь ардуину.

Кстати, Вы не из Одессы часом?