C语言矩阵运算

本文档介绍了用C语言编写的矩阵操作头文件matrix.h,包括矩阵创建(零矩阵、单位矩阵、对角矩阵)、基本运算(加减乘、转置、逆矩阵)、辅助函数(系数矩阵、行列式计算)以及矩阵输入输出。矩阵操作涉及从一维数组构造、内存管理到高级数学运算。
摘要由CSDN通过智能技术生成

这是一个用C语言编写的矩阵运算头文件,话不多说,上代码

matrix.h

/**
 * File name: matrix.h
 * Author: Tiancai Xu
 * Version: 1.0
 * Data: 2021-10-29
 * Copyright: 2021.10, Tiancai Xu
 * This file defines the matrix and its basic operations
 * This file is for study or reference only
*/

#ifndef _STDARG_H
#include <stdarg.h>
#endif // _STDARG_H

#ifndef _STDIO_H
#include <stdio.h>
#endif // _STDIO_H

#ifndef _STDLIB_H
#include <stdlib.h>
#endif // _STDLIB_H

#ifndef _TIME_H
#include <time.h>
#endif // _TIME_H

#ifndef _MATRIX_H
#define _MATRIX_H

#define size_m unsigned int

/**< Matrix variable */
typedef struct
{
    double** M; /**< Data of Matrix */
    size_m row; /**< The number of row */
    size_m col; /**< The number of column */
} Matrix;
/**< Tips: This format is recommended for declarations: Matrix M = {NULL, 0, 0}; */

Matrix from(double* arr, size_m row, size_m col);
Matrix zeros(size_m row, size_m col);
Matrix ones(size_m row, size_m col);
Matrix diag(int order, ...);
Matrix diag_M(Matrix A);
Matrix iden(int order);
Matrix randM(size_m row, size_m col);
Matrix add(Matrix A, Matrix B);
Matrix sub(Matrix A, Matrix B);
Matrix mult_MM(Matrix A, Matrix B);
Matrix mult_kM(double k, Matrix B);
Matrix T(Matrix A);
Matrix inv(Matrix A);
Matrix cof(Matrix A, int r, int c);
double mode(Matrix A);
void scanM(Matrix* A);
void printM(Matrix A);
void clearM(Matrix* A);

#endif // _MATRIX_H

matrix.c

/**
 * File name: matrix.c
 * Author: Tiancai Xu
 * Version: 1.0
 * Data: 2021-10-29
 * Copyright: 2021.10, Tiancai Xu
 * This file includes the implementation of the functions declarated in matrix.h
 * This file is for study or reference only
*/

#include "matrix.h"

/** \brief Create a block of 2-D array memory
 *
 * \param row The number of row
 * \param col The number of column
 * \return M 2-D array pointer
 *
 */
static double** getM(size_m row, size_m col)
{
    int i;
    double** M;

    M = (double**)malloc(sizeof(double*) * row);

    for (i = 0; i < row; i++)
        *(M + i) = (double*)malloc(sizeof(double) * col);

    return M;
}

/** \brief Transform a 2-D array to Matrix
 *
 * \param arr The first adress of the a-D array
 * \param row The number of row
 * \param col The number of column
 * \return M Matrix
 *
 * For a 2-D array arr[r][c], use from((double*)arr,r,c) to avoid the gcc compiler warning
 */
Matrix from(double* arr, size_m row, size_m col)
{
    int i, j;
    Matrix M;
    M.row = row;
    M.col = col;
    M.M = getM(row, col);

    for (i = 0; i < row; i++)
        for (j = 0; j < col; j++)
            M.M[i][j] = *(arr + i * col + j);

    return M;
}

/** \brief Create a zeros Matrix
 *
 * \param row The number of row
 * \param col The number of column
 * \return M Matrix
 *
 */
Matrix zeros(size_m row, size_m col)
{
    int i, j;
    Matrix M;
    M.row = row;
    M.col = col;
    M.M = getM(row, col);

    for (i = 0; i < row; i++)
        for (j = 0; j < col; j++)
            M.M[i][j] = 0;

    return M;
}

/** \brief Create a ones Matrix
 *
 * \param row The number of row
 * \param col The number of column
 * \return M Matrix
 *
 */
Matrix ones(size_m row, size_m col)
{
    int i, j;
    Matrix M;
    M.row = row;
    M.col = col;
    M.M = getM(row, col);

    for (i = 0; i < row; i++)
        for (j = 0; j < col; j++)
            M.M[i][j] = 1;

    return M;
}

/** \brief Create a diagonal Matrix
 *
 * \param order The order of the Matrix
 * \return M Matrix
 *
 */
Matrix diag(int order, ...)
{
    int i;
    va_list valist;
    Matrix M;
    M = zeros(order, order);

    va_start(valist, order);

    for (i = 0; i < order; i++)
        M.M[i][i] = va_arg(valist, double);

    return M;
}

/** \brief Create a diagonal Matrix
 *
 * \param A It's a row or column vector
 * \return M Matrix
 *
 */
Matrix diag_M(Matrix A)
{
    int i, order;
    Matrix M;
    order = A.row * A.col;
    M = zeros(order, order);

    if (A.row == 1)
        for (i = 0; i < order; i++)
            M.M[i][i] = A.M[0][i];
    else if (A.col == 1)
        for (i = 0; i < order; i++)
            M.M[i][i] = A.M[i][0];
    else
    {
        fprintf(stderr, "Error: Arguments must be a row or column vector.\n");
        exit(-1);
    }

    return M;
}

/** \brief Create a identity Matrix
 *
 * \param order The order of the Matrix
 * \return M Matrix
 *
 */
Matrix iden(int order)
{
    int i;
    Matrix M;
    M = zeros(order, order);

    for (i = 0; i < order; i++)
        M.M[i][i] = 1;

    return M;
}

/** \brief Create a random Matrix between 0 and 1.0
 *
 * \param row The number of row
 * \param col The number of column
 * \return M Matrix
 *
 */
Matrix randM(size_m row, size_m col)
{
    time_t t;
    int i, j;
    Matrix M = zeros(row, col);
    srand((unsigned) time(&t));

    for (i = 0; i < row; i++)
        for (j = 0; j < col; j++)
            M.M[i][j] = ((double) rand()) / ((double)RAND_MAX);
    return M;
}

/** \brief Matrix addition
 *
 * \param A Matrix
 * \param B Matrix
 * \return M Matrix, M = A + B
 *
 */
Matrix add(Matrix A, Matrix B)
{
    if (!(A.row == B.row && A.col == B.col))
    {
        fprintf(stderr, "Error: The two matrices must have the same size.\n");
        exit(-1);
    }

    int i, j;
    Matrix M;
    M.row = A.row;
    M.col = A.col;
    M.M = getM(M.row, M.col);

    for (i = 0; i < M.row; i++)
        for (j = 0; j < M.col; j++)
            M.M[i][j] = A.M[i][j] + B.M[i][j];

    return M;
}

/** \brief Matrix subtraction
 *
 * \param A Matrix
 * \param B Matrix
 * \return M Matrix, M = A - B
 *
 */
Matrix sub(Matrix A, Matrix B)
{
    if (!(A.row == B.row && A.col == B.col))
    {
        fprintf(stderr, "Error: The two matrices must have the same size.\n");
        exit(-1);
    }

    int i, j;
    Matrix M;
    M.row = A.row;
    M.col = A.col;
    M.M = getM(M.row, M.col);

    for (i = 0; i < M.row; i++)
        for (j = 0; j < M.col; j++)
            M.M[i][j] = A.M[i][j] - B.M[i][j];

    return M;
}

/** \brief Matrix multiplication
 *
 * \param A Matrix
 * \param B Matrix
 * \return M Matrix, M = A * B
 *
 */
Matrix mult_MM(Matrix A, Matrix B)
{
    if (A.col != B.row)
    {
        fprintf(stderr, "Error: The number of columns in matrix A must be equal to the number of rows in matrix B.\n");
        exit(-1);
    }

    int i, j, k;
    Matrix M;
    M.row = A.row;
    M.col = B.col;
    M.M = getM(M.row, M.col);

    for (i = 0; i < M.row; i++)
        for (j = 0; j < M.col; j++)
        {
            M.M[i][j] = 0;

            for (k = 0; k < A.col; k++)
                M.M[i][j] += A.M[i][k] * B.M[k][j];
        }

    return M;
}

/** \brief Matrix multiplication
 *
 * \param k Real number
 * \param A Matrix
 * \return M Matrix, M = k * A
 *
 */
Matrix mult_kM(double k, Matrix B)
{
    int i, j;
    Matrix M;
    M.row = B.row;
    M.col = B.col;
    M.M = getM(M.row, M.col);

    for (i = 0; i < M.row; i++)
        for (j = 0; j < M.col; j++)
            M.M[i][j] = k * B.M[i][j];

    return M;
}

/** \brief Matrix transpose
 *
 * \param A Matrix
 * \return M Matrix, M = A^T
 *
 */
Matrix T(Matrix A)
{
    int i, j;
    Matrix M;
    M.row = A.col;
    M.col = A.row;
    M.M = getM(M.row, M.col);

    for (i = 0; i < M.row; i++)
        for (j = 0; j < M.col; j++)
            M.M[i][j] = A.M[j][i];

    return M;
}

/** \brief Matrix inversion
 *
 * \param A Matrix
 * \return M Inverse Matrix, M = A^-1
 *
 */
Matrix inv(Matrix A)
{
    if (A.row != A.col)
    {
        fprintf(stderr, "Error: The matrix must be square.\n");
        exit(-1);
    }

    int m = mode(A);

    if (m == 0)
    {
        fprintf(stderr, "Error: The inverse of the target matrix does not exist.\n");
        exit(-1);
    }

    int i, j, s;
    Matrix M, temp;
    M.row = A.row;
    M.col = A.col;
    M.M = getM(M.row, M.col);

    for (i = 0; i < M.row; i++)
        for (j = 0; j < M.col; j++)
        {
            temp = cof(A, i, j);
            s = (i + j) % 2 == 0 ? 1 : -1;
            M.M[j][i] = s * mode(temp) / m;
            clearM(&temp);
        }

    return M;
}

/** \brief Complementary minor, cofactor
 *
 * \param A Matrix
 * \param r The index of row
 * \param c The index of column
 * \return M The cofactor Matrix M[r][c]
 *
 */

Matrix cof(Matrix A, int r, int c)
{
    if (A.row != A.col)
    {
        fprintf(stderr, "Error: The matrix must be square.\n");
        exit(-1);
    }

    if (r < 0 || r > A.row)
    {
        fprintf(stderr, "Error: Out of matrix index range.(r)\n");
        exit(-1);
    }

    if (c < 0 || c > A.col)
    {
        fprintf(stderr, "Error: Out of matrix index range.(c)\n");
        exit(-1);
    }

    int i, j, m, n;
    Matrix M;
    M.row = A.row - 1;
    M.col = A.col - 1;
    M.M = getM(M.row, M.col);

    for (i = 0, m = 0; i < A.row; i++)
    {
        if (i == r)
            continue;

        for (j = 0, n = 0; j < A.col; j++)
        {
            if (j == c)
                continue;

            M.M[m][n] = A.M[i][j];
            n++;
        }

        m++;
    }

    return M;
}

/** \brief Get the mode of Matrix
 *
 * \param A Matrix
 * \return result The mode, result = |A|
 *
 */
double mode(Matrix A)
{
    if (A.row != A.col)
    {
        fprintf(stderr, "Error: The matrix must be square.\n");
        exit(-1);
    }

    if (A.row == 1)
        return A.M[0][0];

    double result;
    int i, s;
    Matrix M;

    for (result = 0, i = 0; i < A.row; i++)
    {
        s = i % 2 == 0 ? 1 : -1;
        M = cof(A, i, 0);
        result += A.M[i][0] * s * mode(M);
        clearM(&M);
    }

    return result;
}

/** \brief Input a Matrix
 *
 * \param A Matrix pointer
 * \return void
 *
 */
void scanM(Matrix* A)
{
    int i, j;

    if (A->M == NULL)
    {
        printf("Enter the number of row&column, e.g. 5,5: ");
        scanf("%u,%u", &A->row, &A->col);
    }

    for (i = 0; i < A->row; i++)
        for (j = 0; j < A->col; j++)
        {
            printf("Enter M(%d,%d): ", i, j);
            scanf("%lf", &A->M[i][j]);
        }
}

/** \brief Print a Matrix
 *
 * \param A Matrix
 * \return void
 *
 */
void printM(Matrix A)
{
    int i, j;

    for (i = 0; i < A.row; i++)
    {
        for (j = 0; j < A.col; j++)
            printf("%-10.4g ", A.M[i][j]);

        printf("\n");
    }
}

/** \brief Clear a Matrix
 *
 * \param A Matrix pointer
 * \return void
 *
 * To release occupied memory
 */
void clearM(Matrix* A)
{
    int i;

    if (A->M != NULL)
    {
        for (i = 0; i < A->row; i++)
            free(A->M[i]);

        free(A->M);
    }

    A->M = NULL;
    A->row = 0;
    A->col = 0;
}

测试用test.c

/**< IDE: Code::Blocks 20.03 64bit */
#include <stdio.h>
#include "matrix.h"

int main()
{
    Matrix M = {NULL, 0, 0};
    Matrix M1 = {NULL, 0, 0};
    Matrix M2 = {NULL, 0, 0};

    printf("/*****************************/\n");

    printf("\nM = zeros(2, 3)\n");
    M = zeros(2, 3);
    printM(M);
    clearM(&M);

    printf("\n/*****************************/\n");

    printf("\nM = ones(3, 2)\n");
    M = ones(3, 2);
    printM(M);
    clearM(&M);

    printf("\n/*****************************/\n");

    printf("\nM = iden(3)\n");
    M = iden(3);
    printM(M);
    clearM(&M);

    printf("\n/*****************************/\n");

    printf("\nM = diag(3, 1.0, 2.0, 3.1)\n");
    M = diag(3, 1.0, 2.0, 3.1);
    printM(M);
    clearM(&M);

    printf("\n/*****************************/\n");

    printf("\nM = randM(2, 2)\n");
    M = randM(2, 2);
    printM(M);
    clearM(&M);

    printf("\n/*****************************/\n");

    printf("\nM = from((double*)arr, 2, 3)\n");
    double arr[3][3] = {{1.0, 2.0, 3.0}, {2.0, 2.0, 1.0}, {3.0, 4.0, 3.0}};
    M = from((double*)arr, 3, 3);
    printM(M);
    M1 = T(M);
    printf("\nM1 = T(M)\n");
    printM(M1);
    printf("\nM2 = mult_MM(M1, M)\n");
    M2 = mult_MM(M1, M);
    printM(M2);
    clearM(&M1);
    clearM(&M2);
    printf("\nM1 = inv(M)\n");
    M1 = inv(M);
    printM(M1);
    printf("\nM1 = mult_MM(M, M1)\n");
    M2 = mult_MM(M, M1);
    printM(M2);
    clearM(&M);
    clearM(&M1);
    clearM(&M2);

    printf("\n/*****************************/\n");

    return 0;
}

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值