aboutsummaryrefslogtreecommitdiff
path: root/helium/mathfunctions.cpp
blob: b0b642e57e2adcec321fa5aa4b35db280442baab (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
// Copyright 2006 Google Inc.
// All Rights Reserved.
// Author: <renn@google.com> (Marius Renn)

// Local includes
#include "debugging.h"
#include "mathfunctions.h"

// C includes
#include <math.h>
#include <stdlib.h>

unsigned helium::SquaredRoot(unsigned x) {
  unsigned k = 0, c = 0;
  for(unsigned o = 1; o <= x; o += k) {
    k += 2;
    c++;
  }
  return c;
}

unsigned helium::Binomi(unsigned n, int k) {
  return ((n == k) || (k <= 1)) ? 1 : Binomi(n-1, k-1) + Binomi(n-1, k);
}

// This comparison function is required for qsort(...), which is used in
// the Median(...) function below.
int float_compare(const void* a, const void* b) {
  const float* f_a = reinterpret_cast<const float*>(a);
  const float* f_b = reinterpret_cast<const float*>(b);
  return (*f_a > *f_b) ? 1 : ((*f_a < *f_b) ? -1 : 0);
}

float helium::Median(float* values, unsigned size) {
  qsort(values, size, sizeof(float), float_compare);
  return values[size / 2];
}

// I feel the need to defend the rare case of using macros here:
// To avoid having to actually swap a row value-by-value in memory, an internal 
// list of n values is stored that map each index to the position of the row. 
// To access an element in the matrix, a look-up must be made to access the
// correct row. These macros should simplify this access, and make the code
// more readable.
#define ELEM_A(ROW, COL) A[rows[ROW] * n + COL]
#define ELEM_B(ROW) b[rows[ROW]]

bool helium::Gauss(float* A, float* b, float* x, unsigned n) {
  float tmp_x[n];
  unsigned rows[n];
  for (unsigned i = 0; i < n; i++) rows[i] = i;
  
  // Diagonalization
  for (unsigned i = 0; i < n; i++) {
    // Find pivot
    float max_val = fabs(ELEM_A(i, i));
    float cur_val = 0.0;
    
    unsigned r = i;
    for (unsigned k = i + 1; k < n; k++) { 
      cur_val = fabs(ELEM_A(k, i));
      if (cur_val > max_val) {
        max_val = cur_val;
        r = k;
      }
    }
    
    // Swap rows to make pivot the current row
    unsigned tmp = rows[r];
    rows[r] = rows[i];
    rows[i] = tmp;
    
    if (max_val == 0.0) return false; 
    
    // Scale row and subtract
    for (unsigned k = i + 1; k < n; k++) {
      float cur_factor =  ELEM_A(k, i) / max_val;
      for (unsigned j = i; j < n; j++) 
        ELEM_A(k, j) = ELEM_A(k, j) - ELEM_A(i, j) * cur_factor; 
      ELEM_B(k) = ELEM_B(k) - ELEM_B(i) * cur_factor;
    }
  }
  
  // Back substitution
  for (int i = n - 1; i >= 0; i--) {
    tmp_x[rows[i]] = ELEM_B(i);
    for (unsigned j = n - 1; j > i; j--) 
      tmp_x[rows[i]] -= tmp_x[rows[j]] * ELEM_A(i, j);
    tmp_x[rows[i]] /= ELEM_A(i, i);
  }
  
  // Swap back values
  for (int i = 0; i < n; i++) x[i] = tmp_x[rows[i]];
  
  return true;
}