Титла: Задача на C Публикувано от: theenemy в May 03, 2010, 19:28 Напишете програма, която умножава две матрици. Съставете два варианта: един с използване на масиви и втори с използване на указатели. Използвайте стандартните функции за време, за да определите кой вариант работи по-бързо.
Трябва ми за сряда. Плс хелп. Титла: Re: Задача на C Публикувано от: b2l в May 03, 2010, 19:51 Примерно:
main() { nov masiv[n,t] = pyrvi masiv[n,m] * vtori masiv[m,t]; zasechi mi vreme(); return 0; } Втори пример с указатели: main() { ukazatel kym nov masiv = ukazatel kym pyrvi masiv * ukazatel kym vtori masiv; zasechi mi vreme(); return 0; } И ти остава само да сравниш двете времена, но мисля, че за това и сам ще се справиш :) Успех в сряда! Титла: Re: Задача на C Публикувано от: theenemy в May 03, 2010, 20:09 Аз имам една програм с масиви, но нямам идея другата как ще стане. Ето я и нея:
#include<iostream> using namespace std; int main(){ const int N=10;//тука си избираш колко да е N float A[N][N], B[N][N], C[N][N]; //декларация на трите двумерни масива А, B и С float max=0; int i, j, k; cout<<"Vyvedete masiv A: \n"; for(j=0; j<N;j++){ //Въвеждане на масив А cout<<" "<<j+1<<" red: \n"; for(i=0; i<N;i++){ cout<<i+1<<"-i element: ";cin>>A[j]; } } cout<<"Vyvedete masiv B: \n"; for(j=0; j<N;j++){ //Въвеждане на масив B cout<<" "<<j+1<<" red: \n"; for(i=0; i<N;i++){ cout<<i+1<<"-i element: ";cin>>B[j]; } } for(j=0; j<N;j++) //при всяка итерация се изчислява ред на двумерния масив С for(i=0; i<N;i++){ //при всяка итерация се изчислява елемент от ред двумерния масив С C[j]=0; for(k=0;k<N;k++)//при всяка итерация се прибавя резултат от умножението на елементите на А и Б към стоността на поредния елемент на С C[j]+=A[j][k]*B[k]; if(max<C[j])max=C[j]; } cout<<" Masiva C: \n"; for(j=0; j<N;j++){ //цикъл за извеждане for(i=0; i<N;i++)cout<<C[j]<<' ';cout<<endl; } cout<<"Maksimalni element na masiva C e: "<<max<<endl; return 0; } Титла: Re: Задача на C Публикувано от: bop_bop_mara в May 03, 2010, 20:35 Аз имам една програм с масиви, но нямам идея другата как ще стане. Ето я и нея: Първо това е на C++, уточни за кой от двата езика става въпрос. Второ, кое не ти е ясно - как се умножават две матрици, как се ползват масиви или как се ползват указатели? Титла: Re: Задача на C Публикувано от: theenemy в May 03, 2010, 20:52 Честно казано не съм много на ясно нито с масивите, нито с указателите :(
Титла: Re: Задача на C Публикувано от: bop_bop_mara в May 03, 2010, 20:56 ОК, а искаш да се научиш или искаш просто програма :)
Титла: Re: Задача на C Публикувано от: theenemy в May 03, 2010, 21:02 Първо да се науча, а след това да мога сам да си правя програмите, но като се има предвид че досега не съм се занимавал със програмиране, не ми е особено лесно :(
Титла: Re: Задача на C Публикувано от: task_struct в May 03, 2010, 21:34 По мой изчисления от поне 3 месеца ти го преподават, а че ти през тях не си се занимавал, не ми се струва нормално... но то вече кой ли не не приемат в университетите само и само да съберат хора ...
След около 5 секунди търсене в Google: http://www.google.bg/search?aq=1&oq=martix+multiplication&sourceid=chrome&client=ubuntu&channel=cs&ie=UTF-8&q=matrix+multiplication+in+c Титла: Re: Задача на C Публикувано от: gat3way в May 03, 2010, 22:53 Коя работи по-бързо в крайна сметка?
Титла: Re: Задача на C Публикувано от: b2l в May 03, 2010, 23:05 Няма ли да е тази с указателите.
Титла: Re: Задача на C Публикувано от: gat3way в May 03, 2010, 23:37 Защо трябва да е решението с указателите?
Титла: Re: Задача на C Публикувано от: b2l в May 03, 2010, 23:39 Може би заради броя на операциите... (просто предположение).
Титла: Re: Задача на C Публикувано от: gat3way в May 03, 2010, 23:46 Броят на операциите трябва да е същият, очевидно някъде другаде има уловка.
Титла: Re: Задача на C Публикувано от: b2l в May 03, 2010, 23:53 Ами предполагам, трябва да мислите ми да се насочат към това - какво е указател? - променливи, които съдържат стойност от паметта. Указателя към масив ще сочи първия елемент на този масив. Аре стига ме мъчи де :).
Титла: Re: Задача на C Публикувано от: gat3way в May 03, 2010, 23:57 Добре де, тая памет трябва да се dereference-ва, иначе как ще умножаваш и събираш там съдържанието на стойностите, намиращи се на тоя адрес. Нямам никаква идея кое ще е по-бързо, и на мен ми е интересно.
При варианта с указатели, нямаме указатели към масиви а към int или каквито там стойности, идеята е да се прави с pointer аритметика. Демек където ще кажеш a[2][2] примерно ще е *(b+2*length+3). Някой дето разбира повече да се изкаже, аз нямам идея :) Грр спи ми се и пиша глупости :) Титла: Re: Задача на C Публикувано от: task_struct в May 04, 2010, 00:34 Според мен просто му искат 2 функци - едната с входен параметър указател, а другата с матрица. ;)
Другият вариант е една функция за смятане на статично заделена матрица, а другата с динамично заделена. Реално погледнато няма разлика между: a[ i ][j] и *((b+i)+j), това би трябвало да са един и същ брой инструкции, дори да се еднакви :) ( не съм го тествал) i и j ще отидат в регистрите на процесора поради това, че са локални променливи. Остават самите мартици - при данимично създадените не знам как ще е ( пиша за embedded, а там няма динамична памет ), при статичните може да се оптимизира при компилирането и част от матриците също да отидат в регистрите. Също така съвременните процесори поддръжат Very long instruction word ( http://en.wikipedia.org/wiki/Very_long_instruction_word ), така че компилаторът да оптимизира кода и част от него да се изпълнява успоредно. ( Някъде бях намерил 1 pdf за AMD процесори, където беше описано как може да се пише кода така, че компилатора да оптимизира като използва тези инструкции ). Също така който е заинтересован може да прегледа проекта Eigen(http://eigen.tuxfamily.org/index.php?title=Main_Page) той е точно за работа с матрици и вектори и там се използват допълнителните инструкции на процесора. В заключение: Смятам, че няма да има разлика между двата метода :) Титла: Re: Задача на C Публикувано от: niakoi в May 04, 2010, 11:11 привет,
не претендирам, че съм гуру в С, обаче винаги съм вярвал, че Код , дори в някои книги по този начин обясняват работата с масиви и каква е връзката с пойнтерите поздрави нас Титла: Re: Задача на C Публикувано от: remotex в May 04, 2010, 11:36 Надали ще е само до аритметиката с указатели - според мен дали ще е изписано със квадратни скоби или обикновени за процесора е се тая..
Хе-хе всяко нещо си има предимства и недостатъци... едва ли ще задълбават чак толкова надълбоко в архитектури, процесори и оптимизации за тях. Предполагам "грешният" отговор който обикновено признават за верен в сл. е: Масивите са по-бързи, но си ограничен до размерността на масива ...а пък с указатели можеш да си направиш динамичен масив/структура от данни (макар и по-бавна заради динамичното заделяне и после търкане на елементите 1 по 1 - т.е. само така си мислят даскалята и карат "децата" да преоткриват топлата вода като прескачат stl, boost etc.) Титла: Re: Задача на C Публикувано от: lkr в May 04, 2010, 13:51 Достъпът до индекс е еднакъв откъм инструкции, но динамичните почти винаги ще бъдат по-бавни, task_struct изреди някои причини. Други такива са, че при достатъчно големи масиви може да се получи memory fragmentation, а това води до cache misses, което е една от най-бавните операции при днешните x86.
Титла: Re: Задача на C Публикувано от: hyankov в May 04, 2010, 15:10 Хахах, тъкмо се готвех, да се изрежа квалитетно, че в C (респективно и в C++) такова животно като масиви няма, когато видях, че niakoi ме е изпреварил ;)
Някой може ли да отговори, ако има "масиви" в С, защо следните две операции при са синтактично верни и при това ще дадат един резултат: Код: int array[10]; Отговорът е написан няколко поста по-нагоре. Не се заяждам, но заданието е доста идиотско "Веднъж с масиви, веднъж с указатели" иначе сигурен съм, че има някакъв замисъл. Титла: Re: Задача на C Публикувано от: task_struct в May 04, 2010, 15:32 Защото операцията [] се замества с поинтър аритметика от предпроцесора :)
Титла: Re: Задача на C Публикувано от: task_struct в May 04, 2010, 15:55 Хъм, излязоха доста интересни резултати на VS 6.0 За съжаление вмомента нямам под ръка GCC за да тествам там как стоят нещата :(
Код
Генерираният от това асемблер е: Код: TITLE D:\Opit\main.c Както виждате arr[2] = 10; и 3[arr] = 11; генерират по 1 инструкция, докато *(p + 2) = 25; генерира 2. Следователно варианта с масиви/матрици би трябвало да е по-бърз. ::) Титла: Re: Задача на C Публикувано от: gat3way в May 04, 2010, 17:36 Още по-забавни резултати :)
t1.c: Код
t2.c: Код
Асемблерен код на main() функцията, компилираме го без оптимизации: t1: Код: 0x08048384 <main+0>: lea 0x4(%esp),%ecx t2: Код: 0x08048384 <main+0>: lea 0x4(%esp),%ecx Или демек 5 инструкции повече. Обаче компилираме ли го с флаг за оптимизация (O1 и нагоре), и двете генерират абсолютно идентичен код: Код: 0x08048384 <main+0>: lea 0x4(%esp),%ecx Има една разлика между масивите и указателите обаче - масивите могат да бъдат в стека или data секцията (в зависимост от това дали са локални/глобални променливи), указателите се очаква да сочат към памет в хийпа. Обаче последното не е задължително - примерно ако се ползва alloca() няма да е така. Обаче и при това положение, не виждам разлика. Паметта би трябвало да се dereference-ва еднакво бързо без значение къде е. Performance драми може да има с TLB misses при големи матрици, но това трябва да е валидно и за двата варианта. Другото което си мисля е дали линукс ядрото не предпочита при нужда да pageout-ва страници памет от хийпа пред страници памет от стека, ама много ме съмнява да (може да) го прави, а и не виждам с какво това би било по-умно от LRU стратегията. Та все още не мога да се сетя защо едното трябва да е по-бързо от другото. В хийпа трябва да е по-бавно заради malloc() ама ако е малка матрицата може да го заделим в стека и тва е доста бърза операция (измества се само стек пойнтера). После, не е казано че трябва да ползваме malloc() въобще, може и сaмо с mmap(), което ще е малко по-бързо. Ако изключим времето за заделяне и освобождаваме, двете трябва да са еднакво бързи. |