Skip to content

Instantly share code, notes, and snippets.

@jdmichaud
Last active September 26, 2019 11:32
Show Gist options
  • Save jdmichaud/1c350dcb01644fc78896ad7d1d5054cd to your computer and use it in GitHub Desktop.
Save jdmichaud/1c350dcb01644fc78896ad7d1d5054cd to your computer and use it in GitHub Desktop.
C matrix
//usr/bin/cc -Wall -Wextra -Wpedantic matrix.c -o matrix && ./matrix; exit
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#define EPSILON 1E-6
#define OK 0
#define NO_INVERSE 1
typedef float matrix3[9];
typedef float matrix4[16];
#define PRINT_MATRIX(matrix, size) { \
uint8_t __i = 0; \
while (__i < size * size) { \
printf("%f ", matrix[__i]); \
if (++__i % size == 0) printf("\n"); \
} \
}
// a b c
// det(d e f) = a * (ei - hf) - b * (di - gf) + c * (dh - ge)
// g h i
float determinant3(matrix3 matrix) {
return matrix[0] * (matrix[4] * matrix[8] - matrix[7] * matrix[5])
- matrix[1] * (matrix[3] * matrix[8] - matrix[6] * matrix[5])
+ matrix[2] * (matrix[3] * matrix[7] - matrix[6] * matrix[4])
;
}
/*
* To compute an inverse:
* 1. First check the determinant is not zero
* 2. Compute the cofactor matrix
* 3. Transpose the cofactor matrix to get the adjugate matrix
* 4. Divide the adjugate matrix by the determinant
*/
uint8_t inverse3(matrix3 matrix) {
// Compute determinant to check if matrix is invertible
float det = determinant3(matrix);
if (abs(det) < EPSILON) return NO_INVERSE;
// Compute adjugate matrix (transpose of the cofactors)
matrix3 adjugate = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
adjugate[0] = (matrix[4] * matrix[8] - matrix[7] * matrix[5]);
adjugate[3] = -(matrix[3] * matrix[8] - matrix[6] * matrix[5]);
adjugate[6] = (matrix[3] * matrix[7] - matrix[6] * matrix[4]);
adjugate[1] = -(matrix[1] * matrix[8] - matrix[7] * matrix[2]);
adjugate[4] = (matrix[0] * matrix[8] - matrix[6] * matrix[2]);
adjugate[7] = -(matrix[0] * matrix[7] - matrix[6] * matrix[1]);
adjugate[2] = (matrix[1] * matrix[5] - matrix[4] * matrix[2]);
adjugate[5] = -(matrix[0] * matrix[5] - matrix[3] * matrix[2]);
adjugate[8] = (matrix[0] * matrix[4] - matrix[3] * matrix[1]);
// Divide the cofactor matrix by the dererminant
float idet = 1 / det;
matrix[0] = adjugate[0] * idet;
matrix[1] = adjugate[1] * idet;
matrix[2] = adjugate[2] * idet;
matrix[3] = adjugate[3] * idet;
matrix[4] = adjugate[4] * idet;
matrix[5] = adjugate[5] * idet;
matrix[6] = adjugate[6] * idet;
matrix[7] = adjugate[7] * idet;
matrix[8] = adjugate[8] * idet;
return OK;
}
void multiplication3(matrix3 lhs, matrix3 rhs) {
matrix3 result = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
result[0] = lhs[0] * rhs[0] + lhs[1] * rhs[3] + lhs[2] * rhs[6];
result[1] = lhs[0] * rhs[1] + lhs[1] * rhs[4] + lhs[2] * rhs[7];
result[2] = lhs[0] * rhs[2] + lhs[1] * rhs[5] + lhs[2] * rhs[8];
result[3] = lhs[3] * rhs[0] + lhs[4] * rhs[3] + lhs[5] * rhs[6];
result[4] = lhs[3] * rhs[1] + lhs[4] * rhs[4] + lhs[5] * rhs[7];
result[5] = lhs[3] * rhs[2] + lhs[4] * rhs[5] + lhs[5] * rhs[8];
result[6] = lhs[6] * rhs[0] + lhs[7] * rhs[3] + lhs[8] * rhs[6];
result[7] = lhs[6] * rhs[1] + lhs[7] * rhs[4] + lhs[8] * rhs[7];
result[8] = lhs[6] * rhs[2] + lhs[7] * rhs[5] + lhs[8] * rhs[8];
memcpy(&lhs[0], &result[0], sizeof(matrix3));
}
/*
* a b c d
* e f g h
* det(i j k l) = a * (f * (kp - ol) - g * (jp - nl) + h * (jo - nk))
* m n o p - b * (e * (kp - ol) - g * (ip - ml) + h * (io - mk))
* + c * (e * (jp - nl) - f * (ip - ml) + h * (in - mj))
* - d * (e * (jo - nk) - f * (io - mk) + g * (in - mj))
*/
float determinant4(matrix4 m) {
return
m[0] * (m[5] * (m[10] * m[15] - m[14] * m[11]) - m[6] * (m[9] * m[15] - m[13] * m[11]) + m[7] * (m[9] * m[14] - m[13] * m[10]))
- m[1] * (m[4] * (m[10] * m[15] - m[14] * m[11]) - m[6] * (m[8] * m[15] - m[12] * m[11]) + m[7] * (m[8] * m[14] - m[12] * m[10]))
+ m[2] * (m[4] * ( m[9] * m[15] - m[13] * m[11]) - m[5] * (m[8] * m[15] - m[12] * m[11]) + m[7] * (m[8] * m[13] - m[12] * m[9]))
- m[3] * (m[4] * ( m[9] * m[14] - m[13] * m[10]) - m[5] * (m[8] * m[14] - m[12] * m[10]) + m[6] * (m[8] * m[13] - m[12] * m[9]))
;
}
uint8_t inverse4(matrix4 m) {
// Compute determinant to check if matrix is invertible
float det = determinant4(m);
if (abs(det) < EPSILON) return NO_INVERSE;
// Compute adjugate matrix (transpose of the cofactors)
// a b c d A11 A12 A13 A14
// cofactor(e f g h) = (A21 A22 A23 A24)
// i j k l A31 A32 A33 A34
// m n o p A41 A42 A43 A44
//
// A11 = a * (f * (k * p - o * l) - g * (j * p - n * l) + h * (j * o - n * k))
// A12 = -b * (e * (k * p - o * l) - g * (i * p - m * l) + h * (i * o - m * k))
// A13 = c * (e * (j * p - n * l) - f * (i * p - m * l) + h * (i * n - m * j))
// A14 = -d * (e * (j * o - n * k) - f * (i * o - m * k) + g * (i * n - m * j))
// A21 = e * (b * (k * p - o * l) - c * (j * p - n * l) + d * (j * o - n * k))
// A22 = -f * (a * (k * p - o * l) - c * (i * p - m * l) + d * (i * o - m * k))
// A23 = g * (a * (j * p - n * l) - b * (i * p - m * l) + d * (i * n - m * j))
// A24 = -h * (a * (j * o - n * k) - b * (i * o - m * k) + c * (i * n - m * j))
// A31 = i * (b * (g * p - o * h) - c * (f * p - n * h) + d * (f * o - n * g))
// A32 = -j * (a * (g * p - o * h) - c * (e * p - m * h) + d * (e * o - m * g))
// A33 = k * (a * (f * p - n * h) - b * (e * p - m * h) + d * (e * n - m * f))
// A34 = -l * (a * (f * o - n * g) - b * (e * o - m * g) + c * (e * n - m * f))
// A41 = m * (b * (g * l - k * h) - c * (f * l - j * h) + d * (f * k - j * g))
// A42 = -n * (a * (g * l - k * h) - c * (e * l - i * h) + d * (e * k - i * g))
// A43 = o * (a * (f * l - j * h) - b * (e * l - i * h) + d * (e * j - i * f))
// A44 = -p * (a * (f * k - g * j) - b * (e * k - i * g) + c * (e * j - i * f))
matrix4 adjugate = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
adjugate[0] = (m[5] * (m[10] * m[15] - m[14] * m[11]) - m[6] * (m[9] * m[15] - m[13] * m[11]) + m[7] * (m[9] * m[14] - m[13] * m[10]));
adjugate[4] = -(m[4] * (m[10] * m[15] - m[14] * m[11]) - m[6] * (m[8] * m[15] - m[12] * m[11]) + m[7] * (m[8] * m[14] - m[12] * m[10]));
adjugate[8] = (m[4] * ( m[9] * m[15] - m[13] * m[11]) - m[5] * (m[8] * m[15] - m[12] * m[11]) + m[7] * (m[8] * m[13] - m[12] * m[9]));
adjugate[12] = -(m[4] * ( m[9] * m[14] - m[13] * m[10]) - m[5] * (m[8] * m[14] - m[12] * m[10]) + m[6] * (m[8] * m[13] - m[12] * m[9]));
adjugate[1] = -(m[1] * (m[10] * m[15] - m[14] * m[11]) - m[2] * (m[9] * m[15] - m[13] * m[11]) + m[3] * (m[9] * m[14] - m[13] * m[10]));
adjugate[5] = (m[0] * (m[10] * m[15] - m[14] * m[11]) - m[2] * (m[8] * m[15] - m[12] * m[11]) + m[3] * (m[8] * m[14] - m[12] * m[10]));
adjugate[9] = -(m[0] * ( m[9] * m[15] - m[13] * m[11]) - m[1] * (m[8] * m[15] - m[12] * m[11]) + m[3] * (m[8] * m[13] - m[12] * m[9]));
adjugate[13] = (m[0] * ( m[9] * m[14] - m[13] * m[10]) - m[1] * (m[8] * m[14] - m[12] * m[10]) + m[2] * (m[8] * m[13] - m[12] * m[9]));
adjugate[2] = (m[1] * ( m[6] * m[15] - m[14] * m[7]) - m[2] * (m[5] * m[15] - m[13] * m[7]) + m[3] * (m[5] * m[14] - m[13] * m[6]));
adjugate[6] = -(m[0] * ( m[6] * m[15] - m[14] * m[7]) - m[2] * (m[4] * m[15] - m[12] * m[7]) + m[3] * (m[4] * m[14] - m[12] * m[6]));
adjugate[10] = (m[0] * ( m[5] * m[15] - m[13] * m[7]) - m[1] * (m[4] * m[15] - m[12] * m[7]) + m[3] * (m[4] * m[13] - m[12] * m[5]));
adjugate[14] = -(m[0] * ( m[5] * m[14] - m[13] * m[6]) - m[1] * (m[4] * m[14] - m[12] * m[6]) + m[2] * (m[4] * m[13] - m[12] * m[5]));
adjugate[3] = -(m[1] * ( m[6] * m[11] - m[10] * m[7]) - m[2] * (m[5] * m[11] - m[9] * m[7]) + m[3] * (m[5] * m[10] - m[9] * m[6]));
adjugate[7] = (m[0] * ( m[6] * m[11] - m[10] * m[7]) - m[2] * (m[4] * m[11] - m[8] * m[7]) + m[3] * (m[4] * m[10] - m[8] * m[6]));
adjugate[11] = -(m[0] * ( m[5] * m[11] - m[9] * m[7]) - m[1] * (m[4] * m[11] - m[8] * m[7]) + m[3] * (m[4] * m[9] - m[8] * m[5]));
adjugate[15] = (m[0] * ( m[5] * m[10] - m[6] * m[9]) - m[1] * (m[4] * m[10] - m[8] * m[6]) + m[2] * (m[4] * m[9] - m[8] * m[5]));
// Divide the cofactor matrix by the dererminant
float idet = 1 / det;
m[0] = adjugate[0] * idet;
m[1] = adjugate[1] * idet;
m[2] = adjugate[2] * idet;
m[3] = adjugate[3] * idet;
m[4] = adjugate[4] * idet;
m[5] = adjugate[5] * idet;
m[6] = adjugate[6] * idet;
m[7] = adjugate[7] * idet;
m[8] = adjugate[8] * idet;
m[9] = adjugate[9] * idet;
m[10] = adjugate[10] * idet;
m[11] = adjugate[11] * idet;
m[12] = adjugate[12] * idet;
m[13] = adjugate[13] * idet;
m[14] = adjugate[14] * idet;
m[15] = adjugate[15] * idet;
return OK;
}
void multiplication4(matrix4 lhs, matrix4 rhs) {
matrix4 result = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
result[0] = lhs[0] * rhs[0] + lhs[1] * rhs[4] + lhs[2] * rhs[8] + lhs[3] * rhs[12];
result[1] = lhs[0] * rhs[1] + lhs[1] * rhs[5] + lhs[2] * rhs[9] + lhs[3] * rhs[13];
result[2] = lhs[0] * rhs[2] + lhs[1] * rhs[6] + lhs[2] * rhs[10] + lhs[3] * rhs[14];
result[3] = lhs[0] * rhs[3] + lhs[1] * rhs[7] + lhs[2] * rhs[11] + lhs[3] * rhs[15];
result[4] = lhs[4] * rhs[0] + lhs[5] * rhs[4] + lhs[6] * rhs[8] + lhs[7] * rhs[12];
result[5] = lhs[4] * rhs[1] + lhs[5] * rhs[5] + lhs[6] * rhs[9] + lhs[7] * rhs[13];
result[6] = lhs[4] * rhs[2] + lhs[5] * rhs[6] + lhs[6] * rhs[10] + lhs[7] * rhs[14];
result[7] = lhs[4] * rhs[3] + lhs[5] * rhs[7] + lhs[6] * rhs[11] + lhs[7] * rhs[15];
result[8] = lhs[8] * rhs[0] + lhs[9] * rhs[4] + lhs[10] * rhs[8] + lhs[11] * rhs[12];
result[9] = lhs[8] * rhs[1] + lhs[9] * rhs[5] + lhs[10] * rhs[9] + lhs[11] * rhs[13];
result[10] = lhs[8] * rhs[2] + lhs[9] * rhs[6] + lhs[10] * rhs[10] + lhs[11] * rhs[14];
result[11] = lhs[8] * rhs[3] + lhs[9] * rhs[7] + lhs[10] * rhs[11] + lhs[11] * rhs[15];
result[12] = lhs[12] * rhs[0] + lhs[13] * rhs[4] + lhs[14] * rhs[8] + lhs[15] * rhs[12];
result[13] = lhs[12] * rhs[1] + lhs[13] * rhs[5] + lhs[14] * rhs[9] + lhs[15] * rhs[13];
result[14] = lhs[12] * rhs[2] + lhs[13] * rhs[6] + lhs[14] * rhs[10] + lhs[15] * rhs[14];
result[15] = lhs[12] * rhs[3] + lhs[13] * rhs[7] + lhs[14] * rhs[11] + lhs[15] * rhs[15];
memcpy(&lhs[0], &result[0], sizeof(matrix4));
}
int main(/*int argc, char **argv*/) {
matrix4 matrix = { 1, 2, 3, 4, 5, 6, 7, 2, 2, 10, 11, 12, 13, 14, 2, 15 };
matrix4 matrixInverse;
memcpy(&matrixInverse[0], &matrix[0], sizeof(matrix4));
if (inverse4(matrixInverse)) {
fprintf(stderr, "cannot invert matrix\n");
} else {
multiplication4(matrixInverse, matrix);
PRINT_MATRIX(matrixInverse, 4);
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment