Mnożenie macierzy o rozmiarach określonych przez użytkownika

0

Siemka, mam napisać program w C, który liczy iloczyn dwóch macierzy. Nie wiem do końca, dlaczego nie działa, podejrzewałbym, że coś spartaczyłem w funkcji liczącej macierz iloczynu (MAC_IL). Dodałem trochę printfów, żeby rozumieć, co się dzieje w środku, ale nie rozumiem tego zupełnie (wyniki printf'ów zupełnie mnie zbiły z tropu), coś jest zupełnie nie tak.
Kody:

funkcja tworząca macierz iloczynu

#include <stdio.h>
#include "MACIERZ_S.h"


int iloczyn (struct MACIERZ_S *MACIERZ1, struct MACIERZ_S *MACIERZ2, struct MACIERZ_S *MAC_IL) {
	
	if ((*MACIERZ1).x != (*MACIERZ2).y)
		return 1;
	else if ((*MACIERZ1).x == (*MACIERZ2).y) {
		int i, j, l;
		for (i=0; i < (*MACIERZ1).x ; i++) {
			printf ("i = %d", i); //te printfy sprawdzają, co się dzieje w tej funkcji
			for (j=0; j < (*MACIERZ2).y ; j++) {
				(*MAC_IL).wsk[i+j*4] = 0;
				printf ("MI = %d", (*MAC_IL).wsk[i+j*4]);
				printf ("j = %d", j);
				for (l=0; l < j; l++) {
					(*MAC_IL).wsk[i+j*4] = (*MAC_IL).wsk[i+j*4]+(*MACIERZ1).wsk[i+l]*(*MACIERZ2).wsk[l+j*4];			
					printf ("MI = %d", (*MAC_IL).wsk[i+j*4]);
				}
			}
		}
		return 0;
	}
	else 
		return 1;
}

program główny

#include <stdio.h>
#include <stdlib.h>
#include "MACIERZ_S.h"
#include "iloczyn.c"
#include "m_create.c"
#include "m_scanf.c"
#include "m_printf.c"


int main () {
	struct MACIERZ_S M1, M2, MAC_IL;
	printf ("Wpisz rozmiary macierzy\n");
	printf ("Wymiar pierwszej: ");
	scanf ("%d %d", &M1.x, &M1.y);
	printf ("\nWymiar drugiej: ");
	scanf ("%d %d", &M2.x, &M2.y);
	m_create (&M1);
	m_create (&M2);
	printf ("\nWprowadź parametry do macierzy\n");
	printf ("Macierz 1:\n");
	m_scanf (&M1);
	printf ("Macierz 2:\n");
	m_scanf (&M2);
	m_printf (&M1);
	printf ("\n");
	m_printf (&M2);
	m_create (&MAC_IL);
	iloczyn (&M1, &M2, &MAC_IL);
	m_printf (&MAC_IL);
	
	return 0;
}

struktura MACIERZ_S

#ifndef _MACIERZ_S_H
#define _MACIERZ_S_H

struct MACIERZ_S { 
	int x;	//rozmiar - szerokosc 
	int y;	//rozmiar - wysokosc
	int *wsk;	// "tablica" x na y
};


#endif /* MACIERZ_S.h */

funkcja pobierająca wartości do obu macierzy

void m_scanf (struct MACIERZ_S *MACIERZ) {
    int i,j;
    for(i=0; i<(*MACIERZ).x ; i++) {
        for(j=0; j<(*MACIERZ).y ; j++) {
       	scanf("%d", &(*MACIERZ).wsk[(*MACIERZ).y*i+j]);
        }
	}
	return;	
}

funkcja wypisująca zawartości macierzy

void m_printf (struct MACIERZ_S *MACIERZ) {
    int i,j;
    for(i=0; i<(*MACIERZ).x ; i++) {
        for(j=0; j<(*MACIERZ).y ; j++) {
       		printf("%d ", (*MACIERZ).wsk[(*MACIERZ).y*i+j]);
       		if (j == (*MACIERZ).y - 1)
				printf ("\n");
        }
	}
	return;	
}

program alokujący pamięć dla macierzy

void m_create(struct MACIERZ_S *MACIERZ) {
	printf("%d %d", (*MACIERZ).x, (*MACIERZ).y); //sprawdza, czy podane wartości zgadzają się
    (*MACIERZ).wsk=malloc((*MACIERZ).y*(*MACIERZ).x*sizeof(int)); 
	return;
}
1

skąd ci się wzięły takie indeksy: i+j*4? Co to za 4?
Wystarczy popatrzeć do m_printf i widać, że powinno być inaczej.
Najlepiej napisz sobie funkcję pomocniczą i korzystaj z niej gdzie tylko się da:

int* m_cellAddr(struct MACIERZ_S *MACIERZ, int row, in column)
{
     return MACIERZ->wsk +  MACIERZ->y * row + column;
}

Wtedy to mnożenie będzie wyglądać czytelniej:

int m_iloczyn (struct MACIERZ_S *MACIERZ1, struct MACIERZ_S *MACIERZ2, struct MACIERZ_S *MAC_IL) {
    if (MACIERZ1->x != MACIERZ2->y)
        return 1;
    if (MACIERZ1->wsk == NULL)
        return 1;
    if (MACIERZ2->wsk == NULL)
        return 1;
    if (MAC_IL->wsk != NULL)
        return 1;
    
    MAC_IL->x = MACIERZ2->x;
    MAC_IL->y = MACIERZ1->y;
    m_create(MAC_IL);

    int i, j, l;
    for (i=0; i < MACIERZ1->x; i++) {
        for (j=0; j < MACIERZ2->y ; j++) {
            int *pSum = m_cellAddr(MAC_IL, i, j);
            *pSum = 0;
            for (l=0; l < j; l++) {
                *pSum += *m_cellAddr(MACIERZ1, i, l) * *m_cellAddr(MACIERZ2, l, j);           
            }
        }
    }
    return 0;
}

Przy czym to API jest dziwne i nieporęczne (o czym już kiedyś wspominałem).

0

Przespałem się z tym problemem i tak, rzeczywiście te indeksy były bez sensu (napisałem sobie na kartce macierz 4x4 i napisałem *4 xD chociaż powinienem jeszcze odjąć jeden, żeby nie wychodzić poza tablicę, coś się zepsuło w każdym razie).
Zmodyfikowałem swój kod tak, jak napisałeś, niestety wciąż nie działa :/

Pokażę, jak to u mnie wygląda:
fragment main'a

	m_printf (&M2);
	printf ("\n");
	m_create (&MAC_IL);
	printf ("\n");
	m_iloczyn (&M1, &M2, &MAC_IL); //zmieniłem iloczyn na m_iloczyn
	printf ("\n");
	m_printf (&MAC_IL);

Dodałem m_cellAddr do m_iloczyn.c includem
m_iloczyn jest dokładnie taki, jaki napisałeś. Nie mam pojęcia, co jest źle

screenshot-20190103175320.png
macierz iloczynu nawet się nie wyświetla...
Czy wszystko jest ok z moją funkcją m_iloczyn?

0

Marek, przepraszam za bycie idiotą xD bardzo źle zrobiłem z tym m_create, że użyłem go dwa razy.
Tak swoją drogą, coś z tymi warunkami jest nie tak, bo funkcja zamyka się jeszcze przed wykonaniem, musiałem je zakomentować
screenshot-20190103191055.png
jest dosyć sporo printfów, użyłem ich do zdebbugowania, teraz się zastanawiam, dlaczego funkcja daje wynik 0

0

Dobra, doszedłem do tego, że coś jest spartaczone z iloczynem, bo jakieś dziwne wyniki wychodzą (w załączniku 3 zdjęcia dla iloczynu macierzy 2x2, 3x3 i 4x4)

0

@Delor Masz rację coś jest nie tak z tą pętlą. Zmieniłem ją teraz na

for (l=0; l < j+MAC_IL->x; l++) //obstawiałbym tutaj +MAC_IL->x lub +MAC_IL->y  

Działa poprawnie dla macierzy 1x1 i 2x2, dla 3x3 już niestety nie, niesymetrycznych też nie działa, sprawdzałem 2x3 * 3x2 , podejrzewam, że może być mały problem, wrzuciłem tak trochę mnemotechnicznie, ale już ledwo łączę koniec z końcem, chciałbym się wyspać, a jutro są dwa kolosy...
Bardzo byłbym wdzięczny, gdyby ktoś ogarnął, co jest nie tak w tym programie

1

Też obstawiałem coś takiego.
Masz program to szybko uruchom dla innych macierzy. Będziesz wiedział czy dobrze działa.
Wartości do macierzy możesz wziąć z jakichś przykładów w internecie lub policzyć, np. w arkuszu kalkulacyjnym.
Odpowiedź na pytanie "Czy teraz dobrze działa?" analizując tylko program na ekranie jest trudniejsze.

0

@Delor Działa dla symetrycznych :D przetestowałem na 3x3 i 4x4, niestety wciąż niesymetryczne nie działaja :/

for (i=0; i < MAC_IL->y; i++) {
        for (j=0; j < MAC_IL->x ; j++) {
            int *pSum = m_cellAddr(MAC_IL, i, j);
            *pSum = 0;
            for (l=0; l < MAC_IL->x; l++)
0
 for (i=0; i < MAC_IL->x; i++) {
         for (j=0; j < MAC_IL->y ; j++) {
             int *pSum = m_cellAddr(MAC_IL, i, j);
             *pSum = 0;
             for (l=0; l < MACIERZ1->x; l++)

Zobacz tak.

0

Wygląda już o wiele lepiej, ale wciąż ostatni wiersz jest skrzaczony
@MarekR22, mógłbyś rzucić okiem? Byłbym wdzięczny :)
screenshot-20190104005613.png

To zmodyfikowane pętle:

for (i=0; i < MAC_IL->y; i++) {
        for (j=0; j < MAC_IL->x ; j++) {
            int *pSum = m_cellAddr(MAC_IL, i, j);
            *pSum = 0;
            for (l=0; l < MACIERZ1->x; l++) {
                *pSum += *m_cellAddr(MACIERZ1, i, l) * *m_cellAddr(MACIERZ2, l, j);           
            }
        }
    }
1

M2x3 * M3x2 powinno dać M2x2.

int m_iloczyn (struct MACIERZ_S *MACIERZ1, struct MACIERZ_S *MACIERZ2, struct MACIERZ_S *MAC_IL) {
    if (MACIERZ1->y != MACIERZ2->x)
        return 1;
    if (MACIERZ1->wsk == NULL)
        return 1;
    if (MACIERZ2->wsk == NULL)
        return 1;
    if (MAC_IL->wsk != NULL)
        return 1;
 
    MAC_IL->x = MACIERZ1->x;
    MAC_IL->y = MACIERZ2->y;
    m_create(MAC_IL);
 
    int i, j, l;
    for (i=0; i < MAC_IL->x; i++) {
        for (j=0; j < MAC_IL->y ; j++) {
            int *pSum = m_cellAddr(MAC_IL, i, j);
            *pSum = 0;
            for (l=0; l < MACIERZ1->y; l++) {
                *pSum += *m_cellAddr(MACIERZ1, i, l) * *m_cellAddr(MACIERZ2, l, j);
            }
        }
    }
    return 0;
}
1

Od zera po swojemu:
https://wandbox.org/permlink/1AOwVvribTub6O8q

#include "Matrix.h"

#include <stdlib.h>

struct MMatrixDouble
{
    int rowCount;
    int columnCount;
    double m[];
};

void MMatrixDoubleFree(MMatrixDoubleRef m)
{
    free(m);
}

MMatrixDoubleRef MMatrixDoubleCreate(int rowCount, int columnCount)
{
    if (rowCount <= 0 || columnCount <= 0) return NULL;
    
    MMatrixDoubleRef result = malloc(sizeof(struct MMatrixDouble) + sizeof(double) * rowCount * columnCount);
    if (!result) return NULL;
    
    result->rowCount = rowCount;
    result->columnCount = columnCount;
    
    return result;
}

double *_MMatrixDoubleGetAddr(MMatrixDoubleRef m, int row, int column)
{
    return &m->m[row * m->columnCount + column];
}

MMatrixDoubleRef MMatrixDoubleCreateMul(MMatrixDoubleRef a, MMatrixDoubleRef b)
{
    if (a->columnCount != b->rowCount) return NULL;
    MMatrixDoubleRef result = MMatrixDoubleCreate(a->rowCount, b->columnCount);
    
    for (int row = 0; row < result->rowCount; ++row) {
        for (int col = 0; col < result->columnCount; ++col) {
            double sum = 0;
            for (int i = 0; i < a->columnCount; ++i) {
                sum += MMatrixDoubleGet(a, row, i) * MMatrixDoubleGet(b, i, col);
            }
            MMatrixDoubleSet(result, row, col, sum);
        }
    }
    return result;
}

double MMatrixDoubleGet(MMatrixDoubleRef m, int row, int column)
{
    return *_MMatrixDoubleGetAddr(m, row, column);
}

void MMatrixDoubleSet(MMatrixDoubleRef m, int row, int column, double v)
{
    *_MMatrixDoubleGetAddr(m, row, column) = v;
}

int MMatrixDoubleGetRows(MMatrixDoubleRef m)
{
    return m->rowCount;
}

int MMatrixDoubleGetColumns(MMatrixDoubleRef m)
{
    return m->columnCount;
}

void MMatrixDoubleFPrint(MMatrixDoubleRef m, FILE *f)
{
    double *a = m->m;
    for (int row = 0; row < m->rowCount; ++row) {
        for (int col = 0; col < m->columnCount; ++col) {
            fprintf(f, " %lg", *a);
            ++a;
        }
        fprintf(f, "\n");
    }
}

void MMatrixDoubleFScan(MMatrixDoubleRef m, FILE *f)
{
    double *a = m->m;
    for (int row = 0; row < m->rowCount; ++row) {
        for (int col = 0; col < m->columnCount; ++col) {
            fscanf(f, "%lg", a);
            ++a;
        }
    }
}

MMatrixDoubleRef MMatrixDoubleCreateFScan(int rowCount, int columnCount, FILE *f)
{
    MMatrixDoubleRef result = MMatrixDoubleCreate(rowCount, columnCount);
    MMatrixDoubleFScan(result, f);
    return result;
}
0

Spoko :) Zaliczyłem to zadanie :) Dziękuje Wam bardzo :)

PS to jest akurat trochę inny temat, ale czy ktoś poza mną pisze w terminalu (ja niestety muszę na zajęciach...)?

1 użytkowników online, w tym zalogowanych: 0, gości: 1