So I'm trying to multiply matrices in c. However when I try to multiply the numbers in the two arrays, and put them in an answer array its always zero. heres the code for the method, thanks.
My matrix struct:
typedef struct matrix {
int r;
int c;
double **mat;
} *matrix_t;
My matrix multiplying method:
matrix_t mat_mult(matrix_t a, matrix_t b)
{
int i, j, k;
double x, temp1, temp2;
double tempsol = 0.0;
x = temp1 = temp2 = 0;
matrix_t answer;
if(a -> c == b -> r)
{
answer = mat_new(a -> r, b -> c);
for(i = 0; i < a -> r; i++)
for( j = 0; j < b -> c; j++)
{
for( k = 0; k < a -> c; k++)
{
tempsol += a->mat[i][k] * b->mat[k][j];
answer-> mat[i][j] = tempsol;
}
}
return answer;
}
else if(a -> r == b -> c)
{
answer = mat_new(a -> c, b -> r);
return answer;
}
else
{
printf("Matrices could not be multiplied");
exit(1);
return;
}
}
heres the code for my mat_new as well
matrix_t mat_new(int r,int c)
{
int i = 0;
double **a;
matrix_t matrix_a;
a = (double**)malloc(r *sizeof(double *));
for(i = 0; i < r; i++)
{
a[i] = (double*)malloc(c *sizeof(double));
}
matrix_a = (matrix_t) malloc ( sizeof(struct matrix));
matrix_a -> mat = a;
matrix_a -> r = r;
matrix_a -> c = c;
return matrix_a;
}
You need to free your objects. You need to reset tempsol. But most importantly, you need to review your mat_mult().
matrix_t mat_mult(matrix_t a, matrix_t b)
{
/* ... */
if(a -> c == b -> r)
{
/* ... */
}
else if(a -> r == b -> c)
{
/* BZZZZT! */
answer = mat_new(a -> c, b -> r); /* BZZZZT! mat_mult(b, a); */
/* BZZZZT! */
return answer;
}
else
{
/* ... */
}
}
Seems like all your issues stem from reading in matrix values as integers rather than doubles. Everything works fine if you change temp in read_mat() to an int, then cast it to a double when you're putting it in the matrix.
This should work for your example:
matrix_t mat_new(int r,int c)
{
matrix_t new = malloc(sizeof*new);
new->r = r;
new->c = c;
new->mat = malloc( r*c*sizeof(double) );
return new;
}
Your code doesn't contain any obvious errors. Perhaps the problem lies in your mat_new(). The way you defined mat in your matrix structure as double **mat;, which I wouldn't recommend, may be causing some problems.
To allocate a 2x2 matrix to mat, you would need to do:
mat = new (double*)[2];
mat[0] = new double[2];
mat[1] = new double[2];
or a n by m matrix:
mat = new (double*)[n];
for (int i=0;i<n;i++) {
mat[i] = new double[m];
}
Is this what you are doing?
Related
So, I had been trying to write the code for the Small Triangles, Large Triangles problem of C in Hackerrank. Before, I state what problem I'm facing, I'll attach the question-
I only wrote the sort_by_area, swap and area functions here. The rest of it was given and unchangeable. The code I've written is getting executed properly but the structures aren't getting sorted correctly. Here is the expected output & my output-
I just cannot figure out why it is getting such weirdly swapped. If anyone could help, would mean a lot.
My code is-
#include <stdlib.h>
#include <math.h>
struct triangle
{
int a;
int b;
int c;
};
typedef struct triangle triangle;
void sort_by_area(triangle* tr, int n) {
int i, j, swapped;
for (i = 0; i < n-1; i++)
{
swapped = 0;
for (j = 0; j < n-i-1; j++)
{
if (area(tr[j].a, tr[j].b, tr[j].c) > area(tr[j+1].a, tr[j+1].b, tr[j+1].c))
{
swap(&tr[j], &tr[j+1]);
swapped = 1;
}
}
if (swapped == 0)
break;
}
}
void swap(struct triangle **xp, struct triangle **yp)
{
struct triangle *temp = *xp;
*xp = *yp;
*yp = temp;
}
int area(int a, int b, int c){
int p=(a+b+c)/2;
int q=p*(p-a)*(p-b)*(p-c);
return sqrt(q);
}
int main()
{
int n;
scanf("%d", &n);
triangle *tr = malloc(n * sizeof(triangle));
for (int i = 0; i < n; i++) {
scanf("%d%d%d", &tr[i].a, &tr[i].b, &tr[i].c);
}
sort_by_area(tr, n);
for (int i = 0; i < n; i++) {
printf("%d %d %d\n", tr[i].a, tr[i].b, tr[i].c);
}
return 0;
}```
Enable all warnings
This quickly led to swap() swapping pointers and not data.
// Corrected - swap data
void swap(struct triangle *xp, struct triangle *yp) {
struct triangle temp = *xp;
*xp = *yp;
*yp = temp;
}
Function order
Move area(), swap() definitions before calling them.
Area
(int) sqrt(q) may return the same value for different qs.
Example: (int) sqrt(100), (int) sqrt(110), (int) sqrt(120)
All return 10. Sorting will not certainly sort according to area.
Simple return the square of the area. Mathematically, sorting by area squared same as area.
int area_squared(int a, int b, int c){
int p=(a+b+c)/2;
int q=p*(p-a)*(p-b)*(p-c);
// return sqrt(q);
return q;
}
Although one could code using double, let us stay with integers.
Watch out for a+b+c as odd as odd/2 forms a truncated quotient.
Perhaps return the square of the area, scaled each side by 2?
int area_squared2(int a, int b, int c){
a *= 2; b *= 2; c *= 2;
// a+b+c is certianly even
int p=(a+b+c)/2;
int q=p*(p-a)*(p-b)*(p-c);
return q;
}
A remaining concern is int overflow. Consider long long math.
long long area_squared2LL(int a, int b, int c){
long long aa = a * 2LL;
long long bb = b * 2LL;
long long cc = c * 2LL;
long long pp = (aa+bb+cc)/2;
long long qq = pp*(pp-aa)*(pp-bb)*(pp-cc);
return qq;
}
Tip: Allocate by referenced data, not type
Easier to code right, review and maintain.
// triangle *tr = malloc(n * sizeof(triangle));
triangle *tr = malloc(sizeof *tr * n);
if (tr == NULL) {
// use tr
...
free(tr);
tr = NULL;
}
I have following code with methods to:
create a matrix
print it
add two matrices
#include <stdio.h>
#include <stdlib.h>
#define VECTOR_ROWS 3
#define VECTOR_COLS 1
void add_matrix(double***, double**, int, int);
void print_matrix(double**, int, int);
double** new_matrix(int, int);
int main() {
printf("First vector:\n");
double **vector = new_matrix(VECTOR_ROWS, VECTOR_COLS);
print_matrix(vector, VECTOR_ROWS, VECTOR_COLS);
printf("\nSecond vector:\n");
double **vector2 = new_matrix(VECTOR_ROWS, VECTOR_COLS);
print_matrix(vector2, VECTOR_ROWS, VECTOR_COLS);
printf("\nAdd vector:\n");
add_matrix(&vector, vector2, VECTOR_ROWS, VECTOR_COLS);
print_matrix(vector, VECTOR_ROWS, VECTOR_COLS);
return 0;
}
void add_matrix(double*** matrix, double** trans_matrix, int rows, int cols)
{
int r, c;
for (r = 0; r < rows; r++)
for (c = 0; c < cols; c++)
*matrix[c][r] += trans_matrix[r][c]; // WHY DOES IT WORK THIS WAY?
}
double** new_matrix(int row, int col)
{
double **matrix = (double**)malloc(row * sizeof(double*));
int r, c;
for(r = 0; r < row; r++)
matrix[r] = (double*)malloc(col * sizeof(double));
for (r = 0; r < row; r++)
for (c = 0; c < col; c++)
scanf("%lf", &matrix[r][c]);
return matrix;
}
void print_matrix(double** matrix, int rowCount, int colCount)
{
int r, c;
for (r = 0; r < rowCount; r++)
{
for (c = 0; c < colCount; c++)
printf("%lf ", matrix[r][c]);
printf("\n");
}
}
Basically, I create vector and vector2 and attempt to add them.
It only works if the first matrix in add_matrix(...) has the [r][c] swapped, as if because I passed it by reference, its rows and columns swapped. If I reference it with [r][c], I get a sef fault, but this works and I have no clue why.
The left operand in this assignment
*matrix[c][r] += trans_matrix[r][c];
is incorrect.
That is the left operand is equivalent to
*( matrix[c][r] )
Write
( *matrix )[r][c] += trans_matrix[r][c];
or
matrix[0][r][c] += trans_matrix[r][c];
Actually there is no sense to pass the pointer to the first matrix by reference because the pointer itself is not changed within the function.
The function could be declared like
void add_matrix(double** matrix, double** trans_matrix, int rows, int cols);
I must return an array double* b and compare it with double* a inside the function arrays_equal. The code doesn't work and test failed. I write here the related codes:
double* array_copy(/*IN*/ const double* a, int n) {
double *b;
b = xcalloc(n,sizeof(double));
for(int i = 0; i < n; i++){
*(b + i) = *(a + i);
printf("%.2f\n",b[i]);
}
printf("%.2f\n",b[0]);
return b;
}
and i write here my test funktion,i must got double* b1 from my array_copy function:
void array_copy_test(void) {
double a1[] = { 1.50, 2.30, 42.42 };
double* b1 = array_copy(a1, 3);
test_equal_b(arrays_equal(a1, b1, 3), true);
free(b1);
equal function:
bool arrays_equal(/*IN*/ const double* a, /*IN*/ const double* b, int n) {
int j = 0;
for(int i = 0; i<= n; i++){
if(approx(*(a+i),*(b+i))){
j++;
}
}
if(n == j){
return true;
} else{return false;}
}
void arrays_equal_test(void) {
double a3[] = { 1.5, 2.3, 42.43 };
double b3[] = { 1.5, 2.3, 42.42 };
test_equal_b(arrays_equal(a3, b3, 3), false);
}
bool approx(double a, double b) {
return fabs(a - b) < 1e-6;
}
Can somebody please tell me, where is my problem?
Your code have some errors. First of all why you wrote for(int i = 0; i<= n; i++)? It will iterate n+1 times in this way. It should be for(int i = 0; i< n; i++).
Then are you expecting your test to return true: the third element are quite different a3[2] = 42.43, b3[2] = 42.42, the difference is much bigger than 10e-6 so they are not equal.
This struct allows representing arbitrary size matrices, where M is the number of rows, N is the number of columns and data is a pointer to M*N values of type double stored by rows.
struct matrix {
size_t M, N;
double *data;
};
struct matrix *mat_directsum(const struct matrix *a, const struct matrix *b);
The function mat_directsum accepts two pointers to arrays as a parameter and should return to the direct sum, dynamically allocated on the heap.
Example:
A.M = 2
A.N = 3
A.data = (1, 1, 2, 0, 1, -3)
Example of direct sum function
I just need a few tips on how to set the function, just to see how others work with arrays of this type, because the only way that comes to mind is an iterative methods with many loops, however, it is enough work long and ingenious, I would like to know if there are easier method to solve it. Thank you
ps.
(memory allocation is not a problem of course)
EDIT
I solved like that:
struct matrix *mat_directsum(const struct matrix *a, const struct matrix *b) {
struct matrix *c = malloc(sizeof(struct matrix));
c->M = a->M + b->M;
c->N = a->N + b->N;
int n = c->M * c->M;
double *dati = calloc(n, sizeof(double));
int t = 0;//index new array
int y = 0;//index first mat
int z = 0;//index second mat
for (int i = 0; i < c->N; i++) {
if (i < a->N) {//first mat
for (int j = 0; j < c->M; j++) {
if (j < a->M) {
dati[t] = a->data[y];
y++;
}
t++;
}
} else {//second mat
for (int j = 0; j < c->M; j++) {
if (j >= a->M) {
dati[t] = b->data[z];
z++;
}
t++;
}
}
}
c->data = dati;
return c;
}
I don't know how to do it which only one for loop
//macro which will point to an element indexed at [xe][ye]
#define ELEMENT(data,rows,columns,xe,ye) (data+((xe)*(columns)+(ye)))
struct matrix
{
size_t M, N;
double *data;
};
//won't mind changing the return type from "struct matrix*" to "struct matrix"
struct matrix mat_directsum(const struct matrix *a, const struct matrix *b)
{
int x;
struct matrix res;
res.M = a->M + b->M;
res.N = a->N + b->N;
//using calloc will set the memory to zero i.e all the bytes will be set to zero.
res.data = (double*)calloc(res.M * res.N, sizeof(double));
if(res.data == NULL)
{
return res;
}
for(x = 0; x < a->M; ++x)
{
memcpy(ELEMENT(res.data, res.M, res.N, x, 0), ELEMENT(a->data, a->M, a->N, x, 0), a->N * sizeof(double));
}
for(x = 0; x < b->M; ++x)
{
//note the offset by [a->M][a->N] while accessing elements of res.
memcpy(ELEMENT(res.data, res.M, res.N, x + a->M, a->N), ELEMENT(b->data, b->M, b->N, x, 0), b->N * sizeof(double));
}
return res;
}
struct matrix res = mat_directsum(&a, &b);
if(res.data != NULL)
{
free(res.data);
}
Besides the error n = c->M * c->M, spotted by M.M (what a coincidence of Ms!), your solution has another error in the for loops: You confused the row and column numbers M and N - since the values are stored by rows, the outer loop has to be for (int i = 0; i < c->M; i++) and the inner loops have to be for (int j = 0; j < c->N; j++), so all M and N in those loops (also in the ifs) have to be swapped. Apart from that and the missing allocation error checks, your solution is fine.
I don't know how to do it which only one for loop
If you want to see an alternative approach, here's one with a helper function to insert the matrices into the sum matrix:
#include <string.h>
void mat_insert(const struct matrix *s, struct matrix *d, int r, int c)
{ // copy source matrix s to destination matrix d at row r, column c
for (int i = 0; i < s->M; i++) // for each row
memcpy(d->data+(r+i)*d->N+c, s->data+i*s->N, s->N*sizeof*s->data);
}
struct matrix *mat_directsum(const struct matrix *a, const struct matrix *b)
{
struct matrix *c = malloc(sizeof *c); if (!c) return NULL;
c->M = a->M + b->M;
c->N = a->N + b->N;
int n = c->M * c->N;
c->data = calloc(n, sizeof *c->data); if (!c->data) return free(c), NULL;
mat_insert(a, c, 0, 0); // copy a to c at row 0, column 0
mat_insert(b, c, a->M, a->N); // copy b to c at row a->M, column a->N
return c;
}
I'm having some trouble with a function that I'm trying to write as part of a project in C. I'm trying to write a function that not only resizes an array, but also assigns values to the new elements of the array.
For example if A = [a, b, c] and it needs to be doubled. The array needs to be re-sized to
[a, a+b/2, b, b+c/2, c, 3c/2]. If A = [a, b, c, d, e, f] the array should be re-sized to [a, c, e]. Any re-factoring of arrays is by some multiple of 2.
This is the offending bit of code.
void re_size_array(double *A, long n, long nx){
double *T;
long i, j;
long m;
T = (double *)malloc(sizeof(double)*nx);
if(nx > n){
m = nx/n;
double k;
for(i = 0; i < n - 1; i++){
k = (A[i+1] - A[i])/m;
for(j = 0; j < m; j++){
T[i*m + j] = A[i] + j*k;
}
}
k = A[n-1]/m;
for(i = 0; i < m; i++){
T[(n-1)*m + i] = A[n-1] + i*k;
}
A = (double*)realloc(A, sizeof(double)*nx);
if(A == NULL){
printf("Array has failed to re-size\n");
exit(1);
}
double *tmp = T;
A = T;
T = tmp;
free(T);
}
if(nx < n){
m = n/nx;
for(i = 0; i < nx; i++){
T[i] = A[i*m];
}
A = (double*)realloc(A, sizeof(double)*nx);
if(A == NULL){
printf("Array has failed to re-size\n");
exit(1);
}
double *temp = T;
A = T;
T = temp;
free(T);
}
}
I'm stuck as to why this doesn't work, I've printed out the values which are supposed to be assigned and they are all correct. I have tried swapping the pointers differently but I still get no viable result.
Instead when I try to re-size the data to a larger nx it results in the same process as A = realloc(A, nx*sizeof(double)). If I try to decrease the size, nothing happens.
Two things here:
A = T is not visible outside of the function. If you want that, then pass a pointer to the double pointer (double **) in your function signature.
You should return A; at the very end and call the function like A = re_size_array(A, n, nx)
hth :)