Работа с матрицами
- Войдите на сайт для отправки комментариев
Пнд, 30/11/2015 - 11:37
Здравствуйте, объясните пожалуйста как делать это задание:
Через последовательный код ввести матрицы 3*3 или 4*4 и переумножить две матрицы
Здравствуйте, объясните пожалуйста как делать это задание:
Есть два пути:
Путь первый:
1) сесть за стол;
2) почесать репу;
3) сделать;
4) если что-то по мелочи не получается, обратиться сюда со скетчем и объяснениями что не получается и как должно быть. Поможем.
Путь второй:
1) перейти в раздел "Ищу исполнителя"
2) договориться с исполнителем
3) заплатить денюшку
4) получить готовую работу.
Совет полезный, но исполнители мне не нужны. Я просто не пойму как через последовательный код ввести матрицы если можете объясните пожалуйста.
А там без разницы, матрицы или ещё чего - просто вводить числа по одному и всё. Можно первым(и) ввести размер матрицы, а дальше числа одно за одним. Попробуйте сначала ввести одно число. Если это сможете, то и матрицу введёте. Если не можете ввести одно число, скажите в чём проблема? Типа "не знаю функции ввода", "не могу описать число" и т.п. В чём беда?
Такое начало правильное?
Или так?
Ярослава, сейчас не могу, но завтра обязательно посмотрю и отпишусь. Вы ввели одно число? Можете это сделать?
Ну, как бы, не совсем. Вы пытаетесь всё усложнить. Зачем? Всё намного проще.
Вам ведь что нужно, давайте распишем.
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. И последнее, делать будем «по уму» (более или менее профессионально) или «так. как делают новички»?
Если Вам нужна помощь, ответьте пожалуйста на все пять вопросов по пунктам.
1.Квадратные
2.Всё равно
3.Хочу сама. Я хочу розобраться как это делать.
4.Да. Нужно сдать через неделю
5.По уму
Ну, давайте попробуем.
Для начала, знайте, что можно вводить из Serial числа с одновременным их преобразованием в машинный формат, а также с фильтром всякой грязи - типа игнорировать пробемы и буквы - вводить только числа. Для этого есть функции parseInt и parseFloat.
Правда, у них есть таймаут (по умолчанию - 1 секунда). Если за это время разумное число не введено, функция возвращает 0. Слава Богу, таймаут можно свой поставить.
Посмотрите на скетч ниже. Запустите его. Попробуйте вводить числа, буквы пробелы и т.п. и убедитесь, что Вы чётко понимаете, что этот скетч делает и теперь знаете как вводить число. Если есть вопросы - задавайте. Если нет, скажите мне, пойдём дальше.
Всё понятно, вопросов нет.
Ну, вот и чудненько.
Теперь Вы можете Напечатать приглашение типа "Enter matrix size:" и ввести размер матрицы.
После этого Вам необходимо запросить память под две матрицы. Матрицы у нас будут из вещественных чисел, поэтому Вы вне всякой функции должны описать два указателя на вещественное число. а после запроса размера, запросить память для обеих матриц (для обоих указателей). Количнство памяти, которое нужно запрашивать, очевидно равно квадрату размера матрицы, умноженному на количество памяти, необходимое для хранения одного действительно числа.
Для одной матрицы описание указателя и запрос памяти выглядят примерно так.
здесь предполагается. что n - ранее описанная переменная целого типа в которую Вы ввели размер матрицы.
Попробуйте написать скетч до этого места самостоятельно. Итак:
1. Описание двух указателей на float - будущих матриц
2. Запрос у юзера размера матрицы
3. запрос памяти для обеих матриц.
Всё, что вводите - пчатайте для контроля.
Получится - не получится, всё равно выкладывайте сюда скетч. Будем смотреть и идти дальше.
Давайте разбираться.
Вам действительно надо. чтобы всё, что у Вас в lopp работало бесконечное количесвто раз? Если надо, то ладно, а если надо, чтобы один раз сработалр - переносите в setup.
Между строками 12 и 13 Вы пропустили собственно запрос памяти. Т.е. строка 13 проверяет выделена ли память, а запросить её Вы забыли. Там надо вставить что-то типа matrixA = malloc(n*n(sizeof(float));
Строку 14 лучше поставить сразу после строки 12.
Для чего нужны строки 15-17 я не понял. По-моему, не нужны.
В принципе, мы нигде не проверяем n - а вдруг кто-то пошутил и нам ноль подсунул или отрицательное сичло, но это ладно - потом.
В общем, исправьте с учётом всех замечаний.
В 14 строке почему-то выдает ошибку что "n не может быть использована в качестве функции".
Потому, что Вы нигде не определили функцию n().
Но если Вы даже ее определите, ошибка не уйдет. Вероятнее всего, Вы порпустили знак умножения между n и sizeof().
Ярослава, просто в посте 13 у меня опечатка, а в посте 11 (строка 3 в коде) та же строка написана правильно. Смотрите внимательнее и поправьте.
Всё нормально работает? Без приключений и непоняток? Вы хоть пишите что-нибудь :)
В 22 строке ошибка "invalid conversion from 'void*' to 'float*' [-fpermissive]". Как ее устранить?
В 22 строке ошибка "invalid conversion from 'void*' to 'float*' [-fpermissive]". Как ее устранить?
Очень просто. добавьте преобразование типа:
matrixB = (float *) malloc(m*m*
sizeof
(
float
));
кстати, тоже самое надо сделать и в 14 строке.
Добейтесь, чтобы работало всё как надо.
Ну, это с программой никак не связано. У Вас порт почему-то занят. Закройте IDE (все окна). Вытащите ардуину из USB и воткните снова. Запустите IDE. Если не поможет, перезагрузите компьютер.
Спасибо, теперь всё работает.
Ну, вот и чудненько. Можно продолжать.
Для начала уберите из программы второй запрос размера матрицы (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 и т.д. Как по номеру строки и столбца узнать этот индекс? Очевидно, что индекс будет равен сумме номера столбца и произведения номера строки на длину строки. Так и напишем:
вот собственно и вся функция доступа к элементам.
Теперь, необходимо убедиться, что она правильно работает в обе стороны, т.е. в том, что с её помощью можно как присвоить значение элементу, так и взять его оттуда. Для этого запустим такой скетч:
попробуйте. У меня получился вот такой результат:
Вроде всё присвоилось и взялось правильно.
Теперь сдлеайте следующее:
1. Запустите скетч, потрогайте его и убедитесь, что Вам он понятен и вопросов не осталось (если остались - задавайте)
2. Уберите ввод m, как я писал в начале этого поста.
3. Скажите мне, знакомы ли Вы с циклами for и можете ли написать поэлементый ввод матрицы самостоятельно (с использованием нашей сегодняшней функции). Если думаете. что можете - напишите и опробуйте (и для мне выложите). Пусть даже неправильно, но это лучше, чем никак. Если же совсме не можете- будем думать вместе.
Что это было? Поэлеиентный ввод матрицы? Ну м как, вводится? :)
Нет))
Окей, чуть позже сегодня, поговорим о вводе, сейчас я убегаю.
Внимательно разберите этот скетч и задайте вопросы, если есть.
Запустите и убедитесь, что он успешно вводит одну (хотя память запрашивает под обе) матрицу и благополучно её печатает для контроля.
Добавьте ввод и печать второй матрицы и выложите получившийся скетч (если не заработает, всё равно выложите и напишите в чём проблема.
Как только Вы это сделаете, нам останется только перемножить их и напечатать результат. Но, последнее (печать) мы уже умеем - эти ж матрицы мы печатаем.
Вы это проверяли в работе? Запускали, внимательно смотрели?
У Вас не печатается матрица B, а вместо неё второй раз печатается матрица A.
Найдите ошибку.
великий и ужасный КОПИПАСТ :)
ЕвгенийП , классная лекция !!!!!!!!! :)
....тоже учусь , извини , что влез
пытаюсь ещё англицкий понимать....
вот это -
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);
перестраховка ? или так и надо ОБЯЗАТЕЛЬНО делать ?
типа - если не выделена память то зачем её освобождать ?
флаг выделения памяти не сбрасывается автоматически , чоли , если памяти не хватает ?
спасибо !
Привет!
По первому вопросу - не знаю, как Вам нравится.
По-второму - проверка-то была на два указателся сразу и мы не знаем кто из них NULL, потому и проверяем. В принципе, в avr-libc, кажется, освобождение указателя, который NULL безопасно - просто ничего не делается, но это не везде так и пишется уже на автомате.
спасибо
перестраховка ? или так и надо ОБЯЗАТЕЛЬНО делать ?
Лично я ВСЕГДА пишу:
Возможно, привычка берет начало с языков, в которых конструктор вызывавется явно, и для C++ это избыточно.
Но для С, мне кажется, это не лишняя проверка.
К сожалению я не могу найти ошибку.
К сожалению я не могу найти ошибку.
Ну, постарайтесь повнимательнее. Строку 90 посмотрите внимательно.
А как матрицы перемножить?
По определению произведения матриц.
Ну, Ва проще, т.к. у Вас матрицы квадратные и n=m
Т.е.
1. Запрашиваем память под третью матрицу
2. делаем двложенные циклы (внешний по строкам, внутренний по столбцам) и в этом цикле считаем значение Сij
3. Для этого сначала полагаем его нулём
4. А затем в ещё одном цикле прибавляем к нему произведение элементов матриц а и b.
Попробуйте, если не выйдет, завтра вместе будем пробовать
Запрос памяти под третью матрицу я сделала, а вложенные циклы не получилось.
где
,
.
Во-первых, в этом определении нужно обратить внимание на то, что важен порядок сомножителей, нужно знать, какой сомножитель первый, а какой -- второй.
Во-вторых, нужно отметить, что произведение определено только в том случае, если число столбцов первого сомножителя равно числу строк второго. Если это условие не выполняется, то произведение не определено.
В-третьих, размеры результата умножения определяются следующим образом: число строк результата равно числу строк первого сомножителя, а число столбцов результата равно числу столбцов второго сомножителя.
Правило вычисления элементов произведения можно сформулировать следующим образом.
Для того, чтобы вычислить элемент произведения, стоящий в
-ой строке и
-ом столбце, нужно взять
-ую строку первого сомножителя и
-ый столбец второго сомножителя, попарно перемножить их элементы, стоящие на одинаковых местах, и результаты сложить. (Точно так же мы поступаем, когда находим скалярное произведение двух векторов по их координатам, см. формулу (14.2).)
Решение. Рассмотрим произведение
. Число столбцов в первом сомножителе
равно 3, число строк во втором сомножителе
тоже равно 3. Числа совпали, следовательно, произведение определено.
Результатом умножения будет матрица
,
, у которой строк столько, сколько их в первом сомножителе, то есть 3, а столбцов столько, сколько их во втором сомножителе, то есть 2. Итак, матрица
имеет размеры
.
Находим элемент
. В его вычислении участвует первая строка
первого сомножителя
и первый столбец
второго сомножителя
:
Находим элемент
. В его вычислении участвует первая строка
первого сомножителя
и второй столбец
второго сомножителя
:
Все элементы первой строки матрицы
вычислены. Находим элемент
. В его вычислении участвует вторая строка
первого сомножителя
и первый столбец
второго сомножителя
:
Находим элемент
. В его вычислении участвует вторая строка
первого сомножителя
и второй столбец
второго сомножителя
:
Вычислены все элементы второй строки матрицы
. Аналогично находим элементы третьей строки:
Итак,
.
Рассмотрим произведение
. Число столбцов в первом сомножителе
равно 2, число строк во втором сомножителе
равно 3. Числа не совпали, следовательно, произведение не определено.
Ответ:
, произведение
не определено.
Как делать вложенные циклы?
Ярослава, так Вы же их делали - Вы вводили и печатали матрицы вложенными циклами.
Сегодня мне пришлось уехать, только сейчас вернулся домой, уже поздно. Завтра я показу Вам как перемножить, если до этого сами не сделаете.
for ( byte n = 0; n < 100; n++ )
{
for ( byte m = 0; m < 100; m++ ) // вложенный_1
{
for ( byte k = 0; k < 100; k++ ) // вложенный_2
{
// действия
}
}
}
специально не для твоей задачи , а для ответа на вопрос :)
Ну, смотрите, Ярослава, там просто три цикла: первые два по строкам и столбцам результирующей матрицы, а ещё один, чтобы накопить сумму по определению произведения матриц.
1. Разберитесь
2. Запустите и проверьте что нормально работает
3. Задайте вопросы
4. убедитесь, что всё понятно и Вы сможете теперь сама сделать что-то подобное.
А теперь, если Вам ещё не надоего, мы можем приступить к самом интересному.
На мой вопрос "Вам надо как у новичков или по уму", Вы ответили "по уму". Так, вот, сейчас всё сделано "как у новичков". Если Вам еще не надоело это занятие, мы можем теперь, когда уже понятно как делать, переделать, чтобы было по уму. Код сократится раза в три и изменять его станет легче. Возможно, он станет понятнее.
Продолжаем или хватит?
Спасибо :)
Вроде бы всё понятно, но я не могу запустить. Вы не могли бы скинуть скрины того что должно получиться.
Продолжаем.
Что значит не можете? Компилятор ругается или просто на экране монитора ничего не появляется (или появляется грязь)?
Если второе, то проверьте, чтобы скорость передачи (строка 8) совпадала со скоростью, которая указана в правом нижнем углу монитора порта. Кстати, в Вашей программе стояло 9600, это я поставил 115200.
Не запускается из-за того что у меня нет ардуины
Это серьёзная причина! :)))
Вроде же была? Вы вроде на ошибки компиллятора жаловались. Ладно, скрин-то мне нетрудно сделать. Сейчас, найду какую-нибудь ардуину.
Кстати, Вы не из Одессы часом?