Mnożenie macierzy prostokątnych pobranych z pliku

0

Witam, mam problem z funkcją mnożenia macierzy prostokątnych, dla macierzy kwadratowych program się wykonuje.
Program ma za zadanie wczytać macierze z plików i wykonać na nich działania. Nie mogę znaleźć błędu, sprawdziłem czy rozmiar macierzy jest dobrze przekazany do funkcji i wszystko jest ok. Byłbym wdzięczny jeśli komuś chciałoby się temu przyjrzeć.
Dołączam plik źródłowy i pliki tekstowe z macierzami.

#include "stdafx.h"
#include <stdio.h>
#include <conio.h>
#include <string>
#include <stdint.h>
#include <iostream>
#include <stdlib.h>
using namespace std;


int wymiary_macierzy(int *kolumn, int *wierszy, FILE *plik){
	char znak;
	int elementy=0;
	int kolumny=0;
	int liczba=0;
	
	fscanf(plik,"%d",&liczba);
	while((znak = getc(plik))!=EOF){
		if (znak=='\n' && kolumny == 0)		//ilosc elementow w rzedzie, ilosc kolumn
			kolumny = elementy+1;
		fscanf(plik,"%d",&liczba);
		elementy ++;
	}
	elementy++;
	*kolumn = kolumny;
	*wierszy = elementy/kolumny;

	return 0;
}

int dodawanie(int **macierz1,int **macierz2, int i, int j, int **wynik){
	for(int k=0; k<j; k++){
		for(int l=0; l<i; l++)
			wynik[l][k]=macierz1[l][k]+macierz2[l][k];
	}
	printf("Dodawanie:\n");
	for(int k=0; k<j; k++){
		for(int l=0; l<i; l++)
			printf("%d\t",wynik[l][k]);
		printf("\n");
	}
	return 0;
}

int odejmowanie(int **macierz1,int **macierz2, int i, int j, int **wynik){
	for(int k=0; k<j; k++){
		for(int l=0; l<i; l++)
			wynik[l][k]=macierz1[l][k]-macierz2[l][k];
	}
	printf("Odejmowanie:\n");
	for(int k=0; k<j; k++){
		for(int l=0; l<i; l++)
			printf("%d\t",wynik[l][k]);
		printf("\n");
	}
	return 0;
}

int mnozenie(int **macierz1,int **macierz2, int m, int n, int p, int q,int **wynik){
	int c,d,k;
	for ( c = 0 ; c < m ; c++ )
    {
      for ( d = 0 ; d < q ; d++ )
      {
		wynik[c][d]=0;
        for ( k = 0 ; k < m ; k++ )
        {
          wynik[c][d]+=macierz1[c][k]*macierz2[k][d];
        }
      }
    }

	printf("Mnozenie: \n");
	for ( c = 0 ; c < m ; c++ )
    {
      for ( d = 0 ; d < q ; d++ )
        printf("%d\t", wynik[d][c]);
 
      printf("\n");
    }

	return 0;
}



int _tmain(int argc, _TCHAR* argv[])
{
	int i=0, j=0;
	FILE *plik1;	//otwieram pierwszy plik i zapisuje macierz do programu
	
	if ((plik1 = fopen("macierz1.txt","r"))==NULL)
		printf("zly plik");
	wymiary_macierzy(&i,&j,plik1);

	printf("macierz1: %d x %d\n",i,j);
	int kolumny1 = i, wiersze1 = j;	//zapisuje rozmiary pierwszej macierzy

	int ** macierz1;
	macierz1 = (int**)malloc(j*sizeof(int*));
	for(int k=0; k<i; k++){
		macierz1[k] = (int*)malloc(i*sizeof(int));
	}
	int liczba=0;
	if ((plik1 = fopen("macierz1.txt","r"))==NULL)
		printf("zly plik");
	for(int k=0; k<j; k++){
		for(int l=0; l<i; l++){

			fscanf(plik1,"%d",&liczba);
			macierz1[l][k] = liczba;
		}
	}
	for(int k=0; k<j; k++){
		for(int l=0; l<i; l++)
			printf("%d\t",macierz1[l][k]);
		printf("\n");
	}

	fclose(plik1);

	FILE *plik2;		//otwieram drugi plik i zapisuje macierz do programu, analogicznie do pierwszego
	
	if ((plik2 = fopen("macierz2.txt","r"))==NULL)
		printf("zly plik");

	wymiary_macierzy(&i,&j,plik2);
	int kolumny2 = i, wiersze2 = j;	//zapisuje rozmiary drugiej macierzy

	printf("macierz2: %d x %d\n",i,j);
	int ** macierz2;
	macierz2 = (int**)malloc(j*sizeof(int*));
	for(int k=0; k<i; k++){
		macierz2[k] = (int*)malloc(i*sizeof(int));
	}
	if ((plik2 = fopen("macierz2.txt","r"))==NULL)
		printf("zly plik");
	for(int k=0; k<j; k++){
		for(int l=0; l<i; l++){

			fscanf(plik2,"%d",&liczba);
			macierz2[l][k] = liczba;
		}
	}
	for(int k=0; k<j; k++){
		for(int l=0; l<i; l++)
			printf("%d\t",macierz2[l][k]);
		printf("\n");
	}

	fclose(plik2);

	//w tym momencie mamy wczytane macierze i ich rozmiary
	if(kolumny1==kolumny2 && wiersze1==wiersze2){
		int ** wynik;
		wynik = (int**)malloc(j*sizeof(int*));
		for(int k=0; k<i; k++){
			wynik[k] = (int*)malloc(i*sizeof(int));
		}
		dodawanie(macierz1, macierz2, kolumny1, wiersze1, wynik);
		odejmowanie(macierz1, macierz2, kolumny1, wiersze1, wynik);
	} else printf("Nie mozna wykonac dodawania i odejmowania macierzy\n");

	if(kolumny1==wiersze2){
		int ** wynik;
		wynik = (int**)malloc(wiersze1*sizeof(int*));
		for(int k=0; k<kolumny2; k++){
			wynik[k] = (int*)malloc(kolumny2*sizeof(int));
		}
		mnozenie(macierz1, macierz2, wiersze1, kolumny1, wiersze2, kolumny2, wynik);
	} else printf("Nie mozna wykonac mnozenia macierzy\n");

	_getch();
	return 0;
}
0

czemu nie masz funkcji wczytującej macierze? Obie wczytuje się chyba tak samo.
tak samo nie ma funkcji drukującej macierze.
ani funkcji tworzącej nową macierz.

przepisując co chwila to samo zwiększasz szanse zrobienia błędu i utrudniasz potem możliwość znalezienia błędu.

0

Tak jak pisze @MarekR22 - ja bym to trochę inaczej zrobił:

  1. Najpierw wczytujesz rozmiar macierzy /z konsoli/ a później wczytujesz macierz /z pliku/ (i to jeszcze hardcodowanego). Jest to ofc bezsensowne, rozmiar macierzy powinien być w pliku razem z nią. O ile nie masz jasno inaczej powiedziane w wymaganiach, zmień lepiej format plików z macierzą.

  2. ja bym proponował żebyś przepisał main na coś w rodzaju:

int main() {
    matrix_t fst = load_matrix("macierz1.txt"); // jeśli już musi być hardcodowane
    matrix_t snd = load_matrix("macierz2.txt");
    matrix_t result = empty_matrix(fst.cols, snd.rows);

    mul_matrix(fst, snd, result);
    print_matrix(result);

    // itp, np. dodawanie czy co jeszcze chcesz wyświetlać.
}
0

Ok, dzięki za odpowiedzi. Zdaję sobie sprawę, że można by to ładniej zapisać i że kod nie wygląda zbyt przejrzyście, ale ogólnie do funkcji mnozenie wykonuje się poprawnie. Jeśli chodzi o rozmiary macierzy to z warunków zadania wynika, że nie powinny być zapisane w pliku. Zresztą w momencie gdy wywołuję funkcję mnozenie, obie macierze i ich wymiary mam już zapisane do pamięci. Moje pytanie bardziej dotyczyło bardziej samego algorytmu zawartego w funkcji mnozenie.

0

@msm wczytywanie rozmiaru z konsoli jest zbędne. Koniec linii jest wystarczającą informacją, problemem jest jak sobie z tym poradzić.
A można np tak.

0

Zdaję sobie sprawę, że można by to ładniej zapisać i że kod nie wygląda zbyt przejrzyście, ale ogólnie do funkcji mnozenie wykonuje się poprawnie. Jeśli chodzi o rozmiary macierzy to z warunków zadania wynika, że nie powinny być zapisane w pliku. Zresztą w momencie gdy wywołuję funkcję mnozenie, obie macierze i ich wymiary mam już zapisane do pamięci. Moje pytanie bardziej dotyczyło bardziej samego algorytmu zawartego w funkcji mnozenie.

Myślę że mylisz się co do tego co jest największym problemem w tym kodzie ;].
Największym problemem jest to ze jest tam straszny bałagan, i nawet Ty (twórca) zaczynasz się w tym gubić (i spodziewasz się że jakieś szaraczki z forum się połapią szybciej ;P).

Porównując mój stary kod (akurat w C#, pierwsze co grep znalazł ;] - 'kiedyś działał') :

public static Matrix operator*(Matrix m0, Matrix m1)
{
    Matrix result = Matrix.Identity;
    for (int x = 0; x < m0.Cols; x++)
        for (int y = 0; y < m0.Rows; y++)
         {
            double sum = 0;
            for (int i = 0; i < m0.Cols; i++)
            { sum += m0[i, y] * m1[x, i]; }

            result[x, y] = sum;
        }
    return result;
}

I Twój:

int mnozenie(int **macierz1,int **macierz2, int m, int n, int p, int q,int **wynik){
        int c,d,k;
        for ( c = 0 ; c < m ; c++ )
    {
      for ( d = 0 ; d < q ; d++ )
      {
                wynik[c][d]=0;
        for ( k = 0 ; k < m ; k++ )
        {
          wynik[c][d]+=macierz1[c][k]*macierz2[k][d];
        }
      }

Co sprowadziłem sobie do formy bardziej kanonicznej żeby porównać:

int mnozenie(int **macierz1,int **macierz2, int m0cols, int n, int p, int m0rows, int **wynik){
    for (int x = 0 ; x < m0cols ; x++ )
    {
      for (int y = 0 ; y < m0rows ; y++ )
      {
        wynik[x][y]=0;
        for (int i = 0 ; i < m0cols ; i++ )
        {
          wynik[x][y]+=macierz2[i][y] * macierz1[x][i];
        }
    }

Kod jest prawie taki sam... Poza tym że Ty przyjmujesz dwa zupełnie niepotrzebne parametry (?), oraz mnożysz macierze w odwrotnej kolejności niż ja. Czyli albo przekazujesz złe parametry (bo pogubiłeś się gdzieś w kodzie) albo masz błąd gdzieś wcześniej (bo pogubiłeś się gdzieś w kodzie) ;).

0

a ja już widzę jeden błąd.

int mnozenie(int **macierz1,int **macierz2, int m, int n, int p, int q,int **wynik){
    int c,d,k;
    for ( c = 0 ; c < m ; c++ ) { // tu masz do "m" dobrze
        for ( d = 0 ; d < q ; d++ ) {
            wynik[c][d]=0;
            for ( k = 0 ; k < m ; k++ ) { // tu też masz do "m" i to jest ŹLE powinno być "n" albo "p" (bo by można było mnożyć n==p)
                wynik[c][d]+=macierz1[c][k]*macierz2[k][d];
            }
        }
    }
...
}

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