annotate q/q.c @ 18:f1e44afb41a3

WIP with control and DAC in sync and not hanging. Control data is wrong but baby steps.
author Daniel O'Connor <darius@dons.net.au>
date Tue, 25 Feb 2025 14:36:10 +1030
parents 388074ff9474
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
14
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1 /* Project: Q-Number (Q16.16, signed) library
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
2 * Author: Richard James Howe
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
3 * License: The Unlicense
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
4 * Email: howe.r.j.89@gmail.com
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
5 * Repo: <https://github.com/q>
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
6 *
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
7 *
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
8 * A Q32.32 version would be useful.
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
9 *
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
10 * The following should be changed/done for this library:
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
11 *
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
12 * - Moving towards a header-only model.
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
13 * - Removal of dependencies such as 'isalpha', 'tolower'
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
14 * as they are locale dependent.
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
15 * - Make components optional (filters, expression parser, ...)
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
16 * - Make hyperbolic arc sin/cos/tan functions.
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
17 * - Fix bugs / inaccuracies in CORDIC code.
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
18 * - Improve accuracy of all the functions and quantify error and
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
19 * their limits.
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
20 *
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
21 * BUG: Enter: 2.71791, get 2.0625, 2.7179 works fine. (Need to
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
22 * limit decimal places).
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
23 */
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
24
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
25 #include "q.h"
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
26 #include <assert.h>
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
27 #include <ctype.h>
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
28 #include <inttypes.h>
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
29 #include <limits.h>
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
30 #include <stdarg.h> /* for expression evaluator error handling */
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
31 #include <stdio.h> /* vsnprintf, for expression evaluator */
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
32 #include <string.h>
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
33
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
34 #define UNUSED(X) ((void)(X))
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
35 #define BOOLIFY(X) (!!(X))
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
36 #define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)]))
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
37 #define MULTIPLIER (INT16_MAX)
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
38 #define DMIN (INT32_MIN)
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
39 #define DMAX (INT32_MAX)
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
40 #define MIN(X, Y) ((X) < (Y) ? (X) : (Y))
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
41 #define MAX(X, Y) ((X) < (Y) ? (Y) : (X))
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
42
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
43 #ifndef CONFIG_Q_HIDE_FUNCS /* 1 = hide hidden (testing) functions, 0 = enable them */
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
44 #define CONFIG_Q_HIDE_FUNCS (0)
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
45 #endif
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
46
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
47 typedef int16_t hd_t; /* half Q width, signed */
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
48 typedef uint64_t lu_t; /* double Q width, unsigned */
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
49
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
50 const qinfo_t qinfo = {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
51 .whole = QBITS,
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
52 .fractional = QBITS,
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
53 .zero = (u_t)0uL << QBITS,
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
54 .bit = 1uL,
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
55 .one = (u_t)1uL << QBITS,
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
56 .min = (u_t)(QHIGH << QBITS),
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
57 .max = (u_t)((QHIGH << QBITS) - 1uL),
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
58
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
59 .pi = QPI, /* 3.243F6 A8885 A308D 31319 8A2E0... */
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
60 .e = QMK(0x2, 0xB7E1, 16), /* 2.B7E1 5162 8A... */
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
61 .sqrt2 = QMK(0x1, 0x6A09, 16), /* 1.6A09 E667 F3... */
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
62 .sqrt3 = QMK(0x1, 0xBB67, 16), /* 1.BB67 AE85 84... */
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
63 .ln2 = QMK(0x0, 0xB172, 16), /* 0.B172 17F7 D1... */
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
64 .ln10 = QMK(0x2, 0x4D76, 16), /* 2.4D76 3776 AA... */
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
65
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
66 .version = QVERSION,
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
67 };
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
68
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
69 qconf_t qconf = { /* Global Configuration Options */
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
70 .bound = qbound_saturate,
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
71 .dp = 4,
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
72 .base = 10,
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
73 };
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
74
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
75 /********* Basic Library Routines ********************************************/
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
76
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
77
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
78 static inline void implies(const int x, const int y) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
79 assert(!x || y);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
80 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
81
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
82 static inline void mutual(const int x, const int y) { /* mutual implication */
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
83 assert(BOOLIFY(x) == BOOLIFY(y));
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
84 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
85
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
86 static inline void exclusive(const int x, const int y) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
87 assert(BOOLIFY(x) != BOOLIFY(y));
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
88 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
89
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
90 static inline void static_assertions(void) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
91 BUILD_BUG_ON(CHAR_BIT != 8);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
92 // BUILD_BUG_ON((sizeof(q_t)*CHAR_BIT) != (QBITS * 2));
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
93 BUILD_BUG_ON( sizeof(q_t) != sizeof(u_t));
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
94 BUILD_BUG_ON( sizeof(u_t) != sizeof(d_t));
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
95 BUILD_BUG_ON(sizeof(lu_t) != sizeof(ld_t));
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
96 BUILD_BUG_ON(sizeof(d_t) != (sizeof(hd_t) * 2));
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
97 BUILD_BUG_ON(sizeof(lu_t) != (sizeof(u_t) * 2));
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
98 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
99
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
100 q_t qbound_saturate(const ld_t s) { /**< default saturation handler */
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
101 assert(s > DMAX || s < DMIN);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
102 if (s > DMAX) return DMAX;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
103 return DMIN;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
104 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
105
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
106 q_t qbound_wrap(const ld_t s) { /**< wrap numbers on overflow */
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
107 assert(s > DMAX || s < DMIN);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
108 if (s > DMAX) return DMIN + (s % DMAX);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
109 return DMAX - ((-s) % DMAX);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
110 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
111
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
112 static inline q_t qsat(const ld_t s) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
113 static_assertions();
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
114 if (s > DMAX || s < DMIN) return qconf.bound(s);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
115 return s;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
116 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
117
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
118 d_t arshift(const d_t v, const unsigned p) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
119 u_t vn = v;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
120 if (v >= 0l)
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
121 return vn >> p;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
122 const u_t leading = ((u_t)(-1l)) << ((sizeof(v) * CHAR_BIT) - p - 1);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
123 return leading | (vn >> p);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
124 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
125
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
126 static inline d_t divn(const d_t v, const unsigned p) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
127 /* return v / (1l << p); */
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
128 const u_t shifted = ((u_t)v) >> p;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
129 if (qispositive(v))
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
130 return shifted;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
131 const u_t leading = ((u_t)(-1l)) << ((sizeof(v)*CHAR_BIT) - p - 1);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
132 return leading | shifted;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
133 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
134
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
135 /* These really all should be moved the header for efficiency reasons */
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
136 static inline u_t qhigh(const q_t q) { return ((u_t)q) >> QBITS; }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
137 static inline u_t qlow(const q_t q) { return ((u_t)q) & QMASK; }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
138 static inline q_t qcons(const u_t hi, const u_t lo) { return (hi << QBITS) | (lo & QMASK); }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
139
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
140 int qtoi(const q_t toi) { return ((lu_t)((ld_t)toi)) >> QBITS; }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
141 q_t qint(const int toq) { return ((u_t)((d_t)toq)) << QBITS; }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
142 signed char qtoc(const q_t q) { return qtoi(q); }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
143 q_t qchar(signed char c) { return qint(c); }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
144 short qtoh(const q_t q) { return qtoi(q); }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
145 q_t qshort(short s) { return qint(s); }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
146 long qtol(const q_t q) { return qtoi(q); }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
147 q_t qlong(long l) { return qint(l); }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
148 long long qtoll(const q_t q) { return qtoi(q); }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
149 q_t qvlong(long long ll) { return qint(ll); }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
150
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
151 q_t qisnegative(const q_t a) { return QINT(BOOLIFY(qhigh(a) & QHIGH)); }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
152 q_t qispositive(const q_t a) { return QINT(!(qhigh(a) & QHIGH)); }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
153 q_t qisinteger(const q_t a) { return QINT(!qlow(a)); }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
154 q_t qisodd(const q_t a) { return QINT(qisinteger(a) && (qhigh(a) & 1)); }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
155 q_t qiseven(const q_t a) { return QINT(qisinteger(a) && !(qhigh(a) & 1)); }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
156 q_t qless(const q_t a, const q_t b) { return QINT(a < b); }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
157 q_t qeqless(const q_t a, const q_t b) { return QINT(a <= b); }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
158 q_t qmore(const q_t a, const q_t b) { return QINT(a > b); }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
159 q_t qeqmore(const q_t a, const q_t b) { return QINT(a >= b); }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
160 q_t qequal(const q_t a, const q_t b) { return QINT(a == b); }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
161 q_t qunequal(const q_t a, const q_t b) { return QINT(a != b); }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
162
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
163 q_t qnegate(const q_t a) { return (~(u_t)a) + 1ULL; }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
164 q_t qmin(const q_t a, const q_t b) { return qless(a, b) ? a : b; }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
165 q_t qmax(const q_t a, const q_t b) { return qmore(a, b) ? a : b; }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
166 q_t qabs(const q_t a) { return qisnegative(a) ? qnegate(a) : a; }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
167 q_t qadd(const q_t a, const q_t b) { return qsat((ld_t)a + (ld_t)b); }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
168 q_t qsub(const q_t a, const q_t b) { return qsat((ld_t)a - (ld_t)b); }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
169 q_t qcopysign(const q_t a, const q_t b) { return qisnegative(b) ? qnegate(qabs(a)) : qabs(a); }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
170 q_t qand(const q_t a, const q_t b) { return a & b; }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
171 q_t qxor(const q_t a, const q_t b) { return a ^ b; }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
172 q_t qor(const q_t a, const q_t b) { return a | b; }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
173 q_t qinvert(const q_t a) { return ~a; }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
174 q_t qnot(const q_t a) { return QINT(!a); }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
175 q_t qlogical(const q_t a) { return QINT(BOOLIFY(a)); }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
176
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
177 q_t qlrs(const q_t a, const q_t b) { /* assert low bits == 0? */ return (u_t)a >> (u_t)qtoi(b); }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
178 q_t qlls(const q_t a, const q_t b) { return (u_t)a << b; }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
179 q_t qars(const q_t a, const q_t b) { return arshift(a, qtoi(b)); }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
180 q_t qals(const q_t a, const q_t b) { return qsat((lu_t)a << b); }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
181 q_t qsign(const q_t a) { return qisnegative(a) ? -QINT(1) : QINT(1); }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
182 q_t qsignum(const q_t a) { return a ? qsign(a) : QINT(0); }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
183
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
184 q_t qapproxequal(const q_t a, const q_t b, const q_t epsilon) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
185 assert(qeqmore(epsilon, qint(0)));
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
186 return QINT(qless(qabs(qsub(a, b)), epsilon));
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
187 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
188
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
189 q_t qapproxunequal(const q_t a, const q_t b, const q_t epsilon) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
190 return QINT(!qapproxequal(a, b, epsilon));
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
191 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
192
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
193 q_t qwithin(q_t v, q_t b1, q_t b2) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
194 const q_t hi = qmax(b1, b2);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
195 const q_t lo = qmin(b1, b2);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
196 if (qequal(v, b1) || qequal(v, b2))
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
197 return 1;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
198 return qless(v, hi) && qmore(v, lo) ? QINT(1) : QINT(0);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
199 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
200
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
201 q_t qwithin_interval(q_t v, q_t expected, q_t allowance) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
202 const q_t b1 = qadd(expected, allowance);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
203 const q_t b2 = qsub(expected, allowance);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
204 return qwithin(v, b1, b2);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
205 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
206
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
207 q_t qfloor(const q_t q) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
208 return q & ~QMASK;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
209 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
210
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
211 q_t qceil(q_t q) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
212 const q_t adj = qisinteger(q) ? QINT(0) : QINT(1);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
213 q = qadd(q, adj);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
214 return ((u_t)q) & (QMASK << QBITS);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
215 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
216
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
217 q_t qtrunc(q_t q) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
218 const q_t adj = qisnegative(q) && qlow(q) ? QINT(1) : QINT(0);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
219 q = qadd(q, adj);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
220 return ((u_t)q) & (QMASK << QBITS);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
221 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
222
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
223 q_t qround(q_t q) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
224 const int negative = qisnegative(q);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
225 q = qabs(q);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
226 const q_t adj = (qlow(q) & QHIGH) ? QINT(1) : QINT(0);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
227 q = qadd(q, adj);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
228 q = ((u_t)q) & (QMASK << QBITS);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
229 return negative ? qnegate(q) : q;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
230 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
231
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
232 int qpack(const q_t *q, char *buffer, const size_t length) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
233 assert(buffer);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
234 if (length < sizeof(*q))
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
235 return -1;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
236 q_t qn = *q;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
237 uint8_t *b = (uint8_t*)buffer;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
238 for (size_t i = 0; i < sizeof(qn); i++) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
239 b[i] = qn;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
240 qn = (u_t)qn >> CHAR_BIT;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
241 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
242 return sizeof(qn);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
243 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
244
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
245 int qunpack(q_t *q, const char *buffer, const size_t length) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
246 assert(q);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
247 assert(buffer);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
248 if (length < sizeof(*q))
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
249 return -1;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
250 uint8_t *b = (uint8_t*)buffer;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
251 u_t nq = 0;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
252 for (size_t i = 0; i < sizeof(*q); i++) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
253 nq <<= CHAR_BIT;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
254 nq |= b[sizeof(*q)-i-1];
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
255 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
256 *q = nq;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
257 return sizeof(*q);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
258 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
259
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
260 static inline ld_t multiply(const q_t a, const q_t b) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
261 const ld_t dd = ((ld_t)a * (ld_t)b) + (lu_t)QHIGH;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
262 /* N.B. portable version of "dd >> QBITS", for double width signed values */
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
263 return dd < 0 ? (-1ull << (2 * QBITS)) | ((lu_t)dd >> QBITS) : ((lu_t)dd) >> QBITS;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
264 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
265
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
266 q_t qmul(const q_t a, const q_t b) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
267 return qsat(multiply(a, b));
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
268 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
269
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
270 q_t qfma(const q_t a, const q_t b, const q_t c) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
271 return qsat(multiply(a, b) + (ld_t)c);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
272 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
273
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
274 q_t qdiv(const q_t a, const q_t b) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
275 assert(b);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
276 const ld_t dd = ((ld_t)a) << QBITS;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
277 ld_t bd2 = divn(b, 1);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
278 if (!((dd >= 0 && b > 0) || (dd < 0 && b < 0)))
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
279 bd2 = -bd2;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
280 /* Overflow not checked! */
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
281 /*return (dd/b) + (bd2/b);*/
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
282 return (dd + bd2) / b;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
283 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
284
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
285 q_t qrem(const q_t a, const q_t b) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
286 return qsub(a, qmul(qtrunc(qdiv(a, b)), b));
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
287 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
288
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
289 q_t qmod(q_t a, q_t b) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
290 return qsub(a, qmul(qfloor(qdiv(a, b)), b));
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
291 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
292
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
293 static char itoch(const unsigned ch) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
294 assert(ch < 36);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
295 if (ch <= 9)
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
296 return ch + '0';
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
297 return ch + 'A' - 10;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
298 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
299
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
300 static inline void swap(char *a, char *b) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
301 assert(a);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
302 assert(b);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
303 const int c = *a;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
304 *a = *b;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
305 *b = c;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
306 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
307
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
308 static void reverse(char *s, const size_t length) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
309 assert(s);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
310 for (size_t i = 0; i < length/2; i++)
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
311 swap(&s[i], &s[length - i - 1]);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
312 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
313
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
314 static int uprint(u_t p, char *s, const size_t length, const d_t base) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
315 assert(s);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
316 assert(base >= 2 && base <= 36);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
317 if (length < 2)
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
318 return -1;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
319 size_t i = 0;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
320 do {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
321 unsigned ch = p % base;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
322 p /= base;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
323 s[i++] = itoch(ch);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
324 } while (p && i < length);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
325 if (p && i >= length)
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
326 return -1;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
327 reverse(s, i);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
328 return i;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
329 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
330
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
331 /* <https://codereview.stackexchange.com/questions/109212> */
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
332 int qsprintbdp(q_t p, char *s, size_t length, const u_t base, const d_t idp) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
333 assert(s);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
334 const int negative = BOOLIFY(qisnegative(p));
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
335 if (negative)
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
336 p = qnegate(p);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
337 const d_t hi = qhigh(p);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
338 char frac[QBITS + 2] = { '.', };
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
339 memset(s, 0, length);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
340 assert(base >= 2 && base <= 36);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
341 u_t lo = qlow(p);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
342 size_t i = 1;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
343 for (i = 1; lo; i++) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
344 if (idp >= 0 && (int)i > idp)
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
345 break;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
346 lo *= base;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
347 assert(i < (QBITS + 2));
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
348 frac[i] = itoch(lo >> QBITS);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
349 lo &= QMASK;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
350 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
351 if (negative)
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
352 s[0] = '-';
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
353 const int hisz = uprint(hi, s + negative, length - (1 + negative), base);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
354 if (hisz < 0 || (hisz + i + negative + 1) > length)
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
355 return -1;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
356 memcpy(s + hisz + negative, frac, i);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
357 return i + hisz;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
358 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
359
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
360 int qsprintb(q_t p, char *s, size_t length, const u_t base) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
361 return qsprintbdp(p, s, length, base, qconf.dp);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
362 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
363
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
364 int qsprint(const q_t p, char *s, const size_t length) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
365 return qsprintb(p, s, length, qconf.base);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
366 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
367
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
368 static inline int extract(unsigned char c, const int radix) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
369 c = tolower(c);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
370 if (c >= '0' && c <= '9')
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
371 c -= '0';
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
372 else if (c >= 'a' && c <= 'z')
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
373 c -= ('a' - 10);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
374 else
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
375 return -1;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
376 if (c < radix)
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
377 return c;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
378 return -1;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
379 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
380
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
381 static inline q_t qmk(d_t integer, u_t fractional) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
382 const int negative = integer < 0;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
383 integer = negative ? -integer : integer;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
384 const q_t r = qcons((d_t)integer, fractional);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
385 return negative ? qnegate(r) : r;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
386 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
387
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
388 static inline u_t integer_logarithm(u_t num, const u_t base) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
389 assert(num > 0 && base >= 2 && base <= 36);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
390 u_t r = -1;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
391 do r++; while (num /= base);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
392 return r;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
393 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
394
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
395 int qnconvbdp(q_t *q, const char *s, size_t length, const d_t base, const u_t idp) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
396 assert(q);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
397 assert(s);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
398 assert(base >= 2 && base <= 36);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
399 *q = QINT(0);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
400 if (length < 1)
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
401 return -1;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
402 d_t hi = 0, lo = 0, places = 1, negative = 0, overflow = 0;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
403 size_t sidx = 0;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
404
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
405 if (s[sidx] == '-') {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
406 if (length < 2)
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
407 return -1;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
408 negative = 1;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
409 sidx++;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
410 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
411
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
412 for (; sidx < length && s[sidx]; sidx++) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
413 const d_t e = extract(s[sidx], base);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
414 if (e < 0)
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
415 break;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
416 if (hi > MULTIPLIER) { /* continue on with conversion, do not accumulate */
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
417 overflow = 1;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
418 } else {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
419 hi = (hi * base) + e;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
420 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
421 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
422 if (sidx >= length || !s[sidx])
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
423 goto done;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
424 if (s[sidx] != '.')
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
425 return -2;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
426 sidx++;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
427
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
428 const u_t ilog = integer_logarithm(0x10000, base);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
429 const u_t max = MIN(idp, ilog); /* Calculate maximum decimal places given base */
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
430
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
431 for (u_t dp = 0; sidx < length && s[sidx]; sidx++, dp++) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
432 const int ch = extract(s[sidx], base);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
433 if (ch < 0)
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
434 return -3;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
435 if (dp < max) { /* continue on with conversion , do not accumulate */
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
436 /* We could get more accuracy by looking at one digit
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
437 * passed the maximum digits allowed and rounding if
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
438 * that digit exists in the input. */
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
439 lo = (lo * base) + ch;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
440 if (places >= (DMAX / base))
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
441 return -4;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
442 places *= base;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
443 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
444 assert((dp + 1) > dp);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
445 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
446 if (!places)
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
447 return -5;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
448 lo = ((d_t)((u_t)lo << QBITS) / places);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
449 done:
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
450 if (overflow) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
451 *q = negative ? qinfo.min : qinfo.max;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
452 return -6;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
453 } else {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
454 const q_t nq = qmk(hi, lo);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
455 *q = negative ? qnegate(nq) : nq;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
456
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
457 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
458 return 0;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
459 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
460
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
461 int qnconvb(q_t *q, const char *s, size_t length, const d_t base) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
462 return qnconvbdp(q, s, length, base, qconf.dp);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
463 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
464
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
465 int qnconv(q_t *q, const char *s, size_t length) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
466 return qnconvb(q, s, length, qconf.base);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
467 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
468
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
469 int qconv(q_t *q, const char * const s) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
470 assert(s);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
471 return qnconv(q, s, strlen(s));
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
472 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
473
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
474 int qconvb(q_t *q, const char * const s, const d_t base) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
475 assert(s);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
476 return qnconvb(q, s, strlen(s), base);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
477 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
478
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
479 typedef enum {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
480 CORDIC_MODE_VECTOR_E/* = 'VECT'*/,
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
481 CORDIC_MODE_ROTATE_E/* = 'ROT'*/,
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
482 } cordic_mode_e;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
483
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
484 typedef enum {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
485 CORDIC_COORD_HYPERBOLIC_E = -1,
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
486 CORDIC_COORD_LINEAR_E = 0,
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
487 CORDIC_COORD_CIRCULAR_E = 1,
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
488 } cordic_coordinates_e;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
489
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
490 static const d_t cordic_circular_inverse_scaling = 0x9B74; /* 1/scaling-factor */
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
491 static const d_t cordic_hyperbolic_inverse_scaling = 0x13520; /* 1/scaling-factor */
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
492
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
493 static inline int mulsign(d_t a, d_t b) { /* sign(a*b) */
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
494 const int aneg = a < 0;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
495 const int bneg = b < 0;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
496 return aneg ^ bneg ? -QINT(1) : QINT(1);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
497 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
498
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
499 /* Universal CORDIC <https://en.wikibooks.org/wiki/Digital_Circuits/CORDIC>
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
500 *
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
501 * x(i+1) = x(i) - u.d(i).y(i).pow(2, -i)
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
502 * y(i+1) = y(i) + d(i).x(i).pow(2, -i)
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
503 * z(i+1) = z(i) - d(i).a(i)
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
504 *
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
505 * d(i) = sgn(z(i)) (rotation)
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
506 * d(i) = -sgn(x(i).y(i)) (vectoring)
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
507 *
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
508 * hyperbolic linear circular
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
509 * u = -1 0 1
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
510 * a = atanh(pow(2, -i)) pow(2, -i) atan(pow(2, -i))
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
511 *
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
512 * linear shift sequence: i = 0, 1, 2, 3, ...
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
513 * circular shift sequence: i = 1, 2, 3, 4, ...
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
514 * hyperbolic shift sequence: i = 1, 2, 3, 4, 4, 5, ... */
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
515 static int cordic(const cordic_coordinates_e coord, const cordic_mode_e mode, int iterations, d_t *x0, d_t *y0, d_t *z0) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
516 assert(x0);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
517 assert(y0);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
518 assert(z0);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
519 if (mode != CORDIC_MODE_VECTOR_E && mode != CORDIC_MODE_ROTATE_E)
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
520 return -1;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
521
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
522 BUILD_BUG_ON(sizeof(d_t) != sizeof(uint32_t));
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
523 BUILD_BUG_ON(sizeof(u_t) != sizeof(uint32_t));
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
524
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
525 static const u_t arctans[] = { /* atan(2^0), atan(2^-1), atan(2^-2), ... */
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
526 0xC90FuL, 0x76B1uL, 0x3EB6uL, 0x1FD5uL,
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
527 0x0FFAuL, 0x07FFuL, 0x03FFuL, 0x01FFuL,
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
528 0x00FFuL, 0x007FuL, 0x003FuL, 0x001FuL,
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
529 0x000FuL, 0x0007uL, 0x0003uL, 0x0001uL,
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
530 0x0000uL, // 0x0000uL,
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
531 };
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
532 static const size_t arctans_length = sizeof arctans / sizeof arctans[0];
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
533
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
534 static const u_t arctanhs[] = { /* atanh(2^-1), atanh(2^-2), ... */
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
535 0x8c9fuL, 0x4162uL, 0x202buL, 0x1005uL,
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
536 0x0800uL, 0x0400uL, 0x0200uL, 0x0100uL,
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
537 0x0080uL, 0x0040uL, 0x0020uL, 0x0010uL,
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
538 0x0008uL, 0x0004uL, 0x0002uL, 0x0001uL,
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
539 0x0000uL, // 0x0000uL,
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
540 };
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
541 static const size_t arctanhs_length = sizeof arctanhs / sizeof arctanhs[0];
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
542
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
543 static const u_t halfs[] = { /* 2^0, 2^-1, 2^-2, ..*/
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
544 0x10000uL,
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
545 0x8000uL, 0x4000uL, 0x2000uL, 0x1000uL,
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
546 0x0800uL, 0x0400uL, 0x0200uL, 0x0100uL,
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
547 0x0080uL, 0x0040uL, 0x0020uL, 0x0010uL,
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
548 0x0008uL, 0x0004uL, 0x0002uL, 0x0001uL,
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
549 //0x0000uL, // 0x0000uL,
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
550 };
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
551 static const size_t halfs_length = sizeof halfs / sizeof halfs[0];
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
552
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
553 const u_t *lookup = NULL;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
554 size_t i = 0, j = 0, k = 0, length = 0;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
555 const size_t *shiftx = NULL, *shifty = NULL;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
556 int hyperbolic = 0;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
557
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
558 switch (coord) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
559 case CORDIC_COORD_CIRCULAR_E:
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
560 lookup = arctans;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
561 length = arctans_length;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
562 i = 0;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
563 shifty = &i;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
564 shiftx = &i;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
565 break;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
566 case CORDIC_COORD_HYPERBOLIC_E:
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
567 lookup = arctanhs;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
568 length = arctanhs_length;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
569 hyperbolic = 1;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
570 i = 1;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
571 shifty = &i;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
572 shiftx = &i;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
573 break;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
574 case CORDIC_COORD_LINEAR_E:
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
575 lookup = halfs;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
576 length = halfs_length;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
577 shifty = &j;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
578 shiftx = NULL;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
579 i = 1;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
580 break;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
581 default: /* not implemented */
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
582 return -2;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
583 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
584
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
585 iterations = iterations > (int)length ? (int)length : iterations;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
586 iterations = iterations < 0 ? (int)length : iterations;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
587
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
588 d_t x = *x0, y = *y0, z = *z0;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
589
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
590 /* rotation mode: z determines direction,
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
591 * vector mode: y determines direction */
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
592 for (; j < (unsigned)iterations; i++, j++) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
593 again:
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
594 {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
595 const d_t m = mode == CORDIC_MODE_ROTATE_E ? z : -y /*-mulsign(x, y)*/;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
596 const d_t d = -!!(m < 0);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
597 const d_t xs = ((((shiftx ? divn(y, *shiftx) : 0)) ^ d) - d);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
598 const d_t ys = (divn(x, *shifty) ^ d) - d;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
599 const d_t xn = x - (hyperbolic ? -xs : xs);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
600 const d_t yn = y + ys;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
601 const d_t zn = z - ((lookup[j] ^ d) - d);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
602 x = xn; /* cosine, in circular, rotation mode */
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
603 y = yn; /* sine, in circular, rotation mode */
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
604 z = zn;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
605 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
606 if (hyperbolic) { /* Experimental/Needs bug fixing */
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
607 switch (1) { // TODO: Correct hyperbolic redo of iteration
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
608 case 0: break;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
609 case 1: if (k++ >= 3) { k = 0; goto again; } break;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
610 case 2: {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
611 assert(j <= 120);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
612 size_t cmp = j + 1;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
613 if (cmp == 4 || cmp == 13 /*|| cmp == 40 || cmp == 121 || cmp == floor(pow(3,i-1)/2) */) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
614 if (k) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
615 k = 0;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
616 } else {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
617 k = 1;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
618 goto again;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
619 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
620 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
621 break;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
622 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
623 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
624 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
625 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
626 *x0 = x;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
627 *y0 = y;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
628 *z0 = z;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
629
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
630 return iterations;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
631 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
632
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
633 /* See: - <https://dspguru.com/dsp/faqs/cordic/>
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
634 * - <https://en.wikipedia.org/wiki/CORDIC> */
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
635 static int qcordic(q_t theta, const int iterations, q_t *sine, q_t *cosine) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
636 assert(sine);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
637 assert(cosine);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
638
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
639 static const q_t pi = QPI, npi = -QPI;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
640 static const q_t hpi = QPI/2, hnpi = -(QPI/2);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
641 static const q_t qpi = QPI/4, qnpi = -(QPI/4);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
642 static const q_t dpi = QPI*2, dnpi = -(QPI*2);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
643
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
644 /* Convert to range -pi to pi, we could use qmod,
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
645 * however that uses multiplication and division, and
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
646 * if we can use those operators freely then there are
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
647 * other, better algorithms we can use instead of CORDIC
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
648 * for sine/cosine calculation. */
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
649 while (qless(theta, npi)) theta = qadd(theta, dpi);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
650 while (qmore(theta, pi)) theta = qadd(theta, dnpi);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
651
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
652 int negate = 0, shift = 0;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
653
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
654 /* convert to range -pi/2 to pi/2 */
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
655 if (qless(theta, hnpi)) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
656 theta = qadd(theta, pi);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
657 negate = 1;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
658 } else if (qmore(theta, hpi)) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
659 theta = qadd(theta, npi);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
660 negate = 1;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
661 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
662
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
663 /* convert to range -pi/4 to pi/4 */
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
664 if (qless(theta, qnpi)) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
665 theta = qadd(theta, hpi);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
666 shift = -1;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
667 } else if (qmore(theta, qpi)) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
668 theta = qadd(theta, hnpi);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
669 shift = 1;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
670 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
671
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
672 d_t x = cordic_circular_inverse_scaling, y = 0, z = theta /* no theta scaling needed */;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
673
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
674 /* CORDIC in Q2.16 format */
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
675 if (cordic(CORDIC_COORD_CIRCULAR_E, CORDIC_MODE_ROTATE_E, iterations, &x, &y, &z) < 0)
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
676 return -1;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
677
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
678 /* undo shifting and quadrant changes */
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
679 if (shift > 0) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
680 const d_t yt = y;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
681 y = x;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
682 x = -yt;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
683 } else if (shift < 0) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
684 const d_t yt = y;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
685 y = -x;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
686 x = yt;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
687 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
688
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
689 if (negate) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
690 x = -x;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
691 y = -y;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
692 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
693 /* set output; no scaling needed */
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
694 *cosine = x;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
695 *sine = y;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
696 return 0;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
697 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
698
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
699 q_t qatan(const q_t t) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
700 q_t x = qint(1), y = t, z = QINT(0);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
701 cordic(CORDIC_COORD_CIRCULAR_E, CORDIC_MODE_VECTOR_E, -1, &x, &y, &z);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
702 return z;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
703 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
704
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
705 q_t qatan2(const q_t a, const q_t b) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
706 q_t x = b, y = a, z = QINT(0);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
707 if (qequal(b, QINT(0))) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
708 assert(qunequal(a, QINT(0)));
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
709 if (qmore(a, QINT(0)))
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
710 return QPI/2;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
711 return -(QPI/2);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
712 } else if (qless(b, QINT(0))) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
713 if (qeqmore(a, QINT(0)))
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
714 return qadd(qatan(qdiv(a, b)), QPI);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
715 return qsub(qatan(qdiv(a, b)), QPI);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
716 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
717 cordic(CORDIC_COORD_CIRCULAR_E, CORDIC_MODE_VECTOR_E, -1, &x, &y, &z);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
718 return z;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
719 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
720
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
721 void qsincos(q_t theta, q_t *sine, q_t *cosine) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
722 assert(sine);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
723 assert(cosine);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
724 const int r = qcordic(theta, -1, sine, cosine);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
725 assert(r >= 0);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
726 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
727
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
728 q_t qsin(const q_t theta) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
729 q_t sine = QINT(0), cosine = QINT(0);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
730 qsincos(theta, &sine, &cosine);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
731 return sine;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
732 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
733
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
734 q_t qcos(const q_t theta) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
735 q_t sine = QINT(0), cosine = QINT(0);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
736 qsincos(theta, &sine, &cosine);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
737 return cosine;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
738 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
739
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
740 q_t qtan(const q_t theta) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
741 q_t sine = QINT(0), cosine = QINT(0);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
742 qsincos(theta, &sine, &cosine);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
743 return qdiv(sine, cosine); /* can use qcordic_div, with range limits it imposes */
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
744 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
745
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
746 q_t qcot(const q_t theta) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
747 q_t sine = QINT(0), cosine = QINT(0);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
748 qsincos(theta, &sine, &cosine);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
749 return qdiv(cosine, sine); /* can use qcordic_div, with range limits it imposes */
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
750 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
751
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
752 q_t qcordic_mul(const q_t a, const q_t b) { /* works for small values; result < 4 */
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
753 q_t x = a, y = QINT(0), z = b;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
754 const int r = cordic(CORDIC_COORD_LINEAR_E, CORDIC_MODE_ROTATE_E, -1, &x, &y, &z);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
755 assert(r >= 0);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
756 return y;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
757 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
758
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
759 q_t qcordic_div(const q_t a, const q_t b) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
760 q_t x = b, y = a, z = QINT(0);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
761 const int r = cordic(CORDIC_COORD_LINEAR_E, CORDIC_MODE_VECTOR_E, -1, &x, &y, &z);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
762 assert(r >= 0);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
763 return z;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
764 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
765
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
766 void qsincosh(const q_t a, q_t *sinh, q_t *cosh) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
767 assert(sinh);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
768 assert(cosh);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
769 q_t x = cordic_hyperbolic_inverse_scaling, y = QINT(0), z = a; /* (e^2x - 1) / (e^2x + 1) */
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
770 const int r = cordic(CORDIC_COORD_HYPERBOLIC_E, CORDIC_MODE_ROTATE_E, -1, &x, &y, &z);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
771 assert(r >= 0);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
772 *sinh = y;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
773 *cosh = x;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
774 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
775
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
776 q_t qtanh(const q_t a) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
777 q_t sinh = QINT(0), cosh = QINT(0);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
778 qsincosh(a, &sinh, &cosh);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
779 return qdiv(sinh, cosh);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
780 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
781
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
782 q_t qcosh(const q_t a) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
783 q_t sinh = QINT(0), cosh = QINT(0);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
784 qsincosh(a, &sinh, &cosh);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
785 return cosh;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
786 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
787
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
788 q_t qsinh(const q_t a) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
789 q_t sinh = QINT(0), cosh = QINT(0);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
790 qsincosh(a, &sinh, &cosh);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
791 return sinh;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
792 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
793
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
794 q_t qcordic_exp(const q_t e) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
795 q_t s = QINT(0), h = QINT(0);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
796 qsincosh(e, &s, &h);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
797 return qadd(s, h);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
798 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
799
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
800 q_t qcordic_ln(const q_t d) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
801 q_t x = qadd(d, QINT(1)), y = qsub(d, QINT(1)), z = QINT(0);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
802 const int r = cordic(CORDIC_COORD_HYPERBOLIC_E, CORDIC_MODE_VECTOR_E, -1, &x, &y, &z);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
803 assert(r >= 0);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
804 return qadd(z, z);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
805 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
806
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
807 q_t qcordic_sqrt(const q_t n) { /* testing only; works for 0 < x < 2 */
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
808 const q_t quarter = 1uLL << (QBITS - 2); /* 0.25 */
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
809 q_t x = qadd(n, quarter),
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
810 y = qsub(n, quarter),
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
811 z = 0;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
812 const int r = cordic(CORDIC_COORD_HYPERBOLIC_E, CORDIC_MODE_VECTOR_E, -1, &x, &y, &z);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
813 assert(r >= 0);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
814 return qmul(x, cordic_hyperbolic_inverse_scaling);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
815 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
816
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
817 q_t qhypot(const q_t a, const q_t b) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
818 q_t x = qabs(a), y = qabs(b), z = QINT(0); /* abs() should not be needed? */
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
819 const int r = cordic(CORDIC_COORD_CIRCULAR_E, CORDIC_MODE_VECTOR_E, -1, &x, &y, &z);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
820 assert(r >= 0);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
821 return qmul(x, cordic_circular_inverse_scaling);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
822 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
823
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
824 q_t qatanh(q_t x) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
825 assert(qabs(qless(x, QINT(1))));
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
826 return qmul(qlog(qdiv(qadd(QINT(1), x), qsub(QINT(1), x))), QMK(0, 0x8000, 16));
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
827 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
828
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
829 q_t qasinh(q_t x) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
830 return qlog(qadd(x, qsqrt(qadd(qmul(x, x), QINT(1)))));
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
831 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
832
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
833 q_t qacosh(q_t x) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
834 assert(qeqmore(x, QINT(1)));
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
835 return qlog(qadd(x, qsqrt(qsub(qmul(x, x), QINT(1)))));
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
836 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
837
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
838 void qpol2rec(const q_t magnitude, const q_t theta, q_t *i, q_t *j) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
839 assert(i);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
840 assert(j);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
841 q_t sin = QINT(0), cos = QINT(0);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
842 qsincos(theta, &sin, &cos);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
843 *i = qmul(sin, magnitude);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
844 *j = qmul(cos, magnitude);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
845 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
846
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
847 void qrec2pol(const q_t i, const q_t j, q_t *magnitude, q_t *theta) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
848 assert(magnitude);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
849 assert(theta);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
850 const int is = qisnegative(i), js = qisnegative(j);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
851 q_t x = qabs(i), y = qabs(j), z = QINT(0);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
852 const int r = cordic(CORDIC_COORD_CIRCULAR_E, CORDIC_MODE_VECTOR_E, -1, &x, &y, &z);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
853 assert(r >= 0);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
854 *magnitude = qmul(x, cordic_circular_inverse_scaling);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
855 if (is && js)
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
856 z = qadd(z, QPI);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
857 else if (js)
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
858 z = qadd(z, QPI/2l);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
859 else if (is)
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
860 z = qadd(z, (3l*QPI)/2l);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
861 *theta = z;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
862 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
863
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
864 q_t qcordic_hyperbolic_gain(const int n) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
865 q_t x = QINT(1), y = QINT(0), z = QINT(0);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
866 const int r = cordic(CORDIC_COORD_HYPERBOLIC_E, CORDIC_MODE_ROTATE_E, n, &x, &y, &z);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
867 assert(r >= 0);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
868 return x;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
869 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
870
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
871 q_t qcordic_circular_gain(const int n) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
872 q_t x = QINT(1), y = QINT(0), z = QINT(0);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
873 const int r = cordic(CORDIC_COORD_CIRCULAR_E, CORDIC_MODE_ROTATE_E, n, &x, &y, &z);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
874 assert(r >= 0);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
875 return x;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
876 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
877
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
878 static inline int isodd(const unsigned n) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
879 return n & 1;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
880 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
881
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
882 d_t dpower(d_t b, unsigned e) { /* https://stackoverflow.com/questions/101439 */
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
883 d_t result = 1;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
884 for (;;) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
885 if (isodd(e))
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
886 result *= b;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
887 e >>= 1;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
888 if (!e)
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
889 break;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
890 b *= b;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
891 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
892 return result;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
893 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
894
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
895 d_t dlog(d_t x, const unsigned base) { /* rounds up, look at remainder to round down */
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
896 d_t b = 0;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
897 assert(x && base > 1);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
898 while ((x /= (d_t)base)) /* can use >> for base that are powers of two */
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
899 b++;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
900 return b;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
901 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
902
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
903 q_t qlog(q_t x) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
904 q_t logs = 0;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
905 assert(qmore(x, 0));
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
906 static const q_t lmax = QMK(9, 0x8000, 16); /* 9.5, lower limit needs checking */
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
907 for (; qmore(x, lmax); x = divn(x, 1))
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
908 logs = qadd(logs, qinfo.ln2);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
909 return qadd(logs, qcordic_ln(x));
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
910 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
911
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
912 q_t qsqr(const q_t x) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
913 return qmul(x, x);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
914 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
915
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
916 q_t qexp(const q_t e) { /* exp(e) = exp(e/2)*exp(e/2) */
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
917 if (qless(e, QINT(1))) /* 1.1268 is approximately the limit for qcordic_exp */
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
918 return qcordic_exp(e);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
919 return qsqr(qexp(divn(e, 1)));
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
920 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
921
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
922 q_t qpow(q_t n, q_t exp) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
923 implies(qisnegative(n), qisinteger(exp));
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
924 implies(qequal(n, QINT(0)), qunequal(exp, QINT(0)));
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
925 if (qequal(QINT(0), n))
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
926 return QINT(1);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
927 if (qisnegative(n)) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
928 const q_t abspow = qpow(qabs(n), exp);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
929 return qisodd(exp) ? qnegate(abspow) : abspow;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
930 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
931 if (qisnegative(exp))
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
932 return qdiv(QINT(1), qpow(n, qabs(exp)));
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
933 return qexp(multiply(qlog(n), exp));
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
934 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
935
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
936 q_t qsqrt(const q_t x) { /* Newton-Rhaphson method */
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
937 assert(qeqmore(x, 0));
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
938 const q_t difference = qmore(x, QINT(100)) ? 0x0100 : 0x0010;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
939 if (qequal(QINT(0), x))
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
940 return QINT(0);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
941 q_t guess = qmore(x, qinfo.sqrt2) ? divn(x, 1) : QINT(1);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
942 while (qmore(qabs(qsub(qmul(guess, guess), x)), difference))
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
943 guess = divn(qadd(qdiv(x, guess), guess), 1);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
944 return qabs(guess); /* correct for overflow int very large numbers */
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
945 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
946
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
947 q_t qasin(const q_t t) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
948 assert(qless(qabs(t), QINT(1)));
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
949 /* can also use: return qatan(qdiv(t, qsqrt(qsub(QINT(1), qmul(t, t))))); */
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
950 return qatan2(t, qsqrt(qsub(QINT(1), qmul(t, t))));
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
951 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
952
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
953 q_t qacos(const q_t t) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
954 assert(qeqless(qabs(t), QINT(1)));
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
955 /* can also use: return qatan(qdiv(qsqrt(qsub(QINT(1), qmul(t, t))), t)); */
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
956 return qatan2(qsqrt(qsub(QINT(1), qmul(t, t))), t);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
957 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
958
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
959 q_t qdeg2rad(const q_t deg) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
960 return qdiv(qmul(QPI, deg), QINT(180));
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
961 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
962
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
963 q_t qrad2deg(const q_t rad) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
964 return qdiv(qmul(QINT(180), rad), QPI);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
965 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
966
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
967 void qfilter_init(qfilter_t *f, const q_t time, const q_t rc, const q_t seed) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
968 assert(f);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
969 memset(f, 0, sizeof(*f));
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
970 f->time = time;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
971 f->rc = rc;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
972 f->filtered = seed; /* alpha * seed for LPF */
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
973 f->raw = seed;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
974 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
975
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
976 q_t qfilter_low_pass(qfilter_t *f, const q_t time, const q_t data) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
977 assert(f);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
978 /* If the calling rate is constant (for example the function is
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
979 * guaranteed to be always called at a rate of 5 milliseconds) we
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
980 * can avoid the costly alpha calculation! */
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
981 const q_t dt = (u_t)time - (u_t)f->time;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
982 const q_t alpha = qdiv(dt, qadd(f->rc, dt));
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
983 f->filtered = qfma(alpha, qsub(data, f->filtered), f->filtered);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
984 f->time = time;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
985 f->raw = data;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
986 return f->filtered;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
987 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
988
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
989 q_t qfilter_high_pass(qfilter_t *f, const q_t time, const q_t data) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
990 assert(f);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
991 const q_t dt = (u_t)time - (u_t)f->time;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
992 const q_t alpha = qdiv(f->rc, qadd(f->rc, dt));
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
993 f->filtered = qmul(alpha, qadd(f->filtered, qsub(data, f->raw)));
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
994 f->time = time;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
995 f->raw = data;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
996 return f->filtered;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
997 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
998
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
999 q_t qfilter_value(const qfilter_t *f) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1000 assert(f);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1001 return f->filtered;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1002 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1003
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1004 /* Must be called at a constant rate; perhaps a PID which takes call time
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1005 * into account could be made, but that would complicate things. Differentiator
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1006 * term needs filtering also. It would be nice to create a version that took
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1007 * into account the time delta, see
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1008 * <https://www.quora.com/Do-I-need-to-sample-at-a-constant-rate-for-PID-control-or-is-it-sufficient-to-know-the-time-at-which-my-sample-was-taken-even-if-the-increment-varies>
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1009 * */
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1010 q_t qpid_update(qpid_t *pid, const q_t error, const q_t position) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1011 assert(pid);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1012 const q_t p = qmul(pid->p_gain, error);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1013 pid->i_state = qadd(pid->i_state, error);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1014 pid->i_state = qmax(pid->i_state, pid->i_min);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1015 pid->i_state = qmin(pid->i_state, pid->i_max);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1016 const q_t i = qmul(pid->i_state, pid->i_gain);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1017 const q_t d = qmul(pid->d_gain, qsub(position, pid->d_state));
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1018 pid->d_state = position;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1019 return qsub(qadd(p, i), d);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1020 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1021
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1022 /* Simpsons method for numerical integration, from "Math Toolkit for
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1023 * Real-Time Programming" by Jack Crenshaw */
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1024 q_t qsimpson(q_t (*f)(q_t), const q_t x1, const q_t x2, const unsigned n) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1025 assert(f);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1026 assert((n & 1) == 0);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1027 const q_t h = qdiv(qsub(x2, x1), QINT(n));
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1028 q_t sum = 0, x = x1;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1029 for (unsigned i = 0; i < (n / 2u); i++){
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1030 sum = qadd(sum, qadd(f(x), qmul(QINT(2), f(qadd(x,h)))));
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1031 x = qadd(x, qmul(QINT(2), h));
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1032 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1033 sum = qsub(qmul(QINT(2), sum), qadd(f(x1), f(x2)));
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1034 return qdiv(qmul(h, sum), QINT(3));
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1035 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1036
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1037 /* The matrix meta-data field is not used at the moment, but could be
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1038 * used for things like versioning, determining whether the matrix is
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1039 * all zeros, or is the identify matrix, whether it contains valid data,
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1040 * and more. Some common matrix operations are missing, such as factorization
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1041 *
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1042 * A function for image kernels might be useful. */
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1043
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1044 enum { METADATA, LENGTH, ROW, COLUMN, DATA, };
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1045
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1046 int qmatrix_is_valid(const q_t *m) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1047 const size_t size = m[LENGTH], row = m[ROW], column = m[COLUMN];
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1048 const size_t elements = row * column;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1049 if (elements < row || elements < column) /* overflow */
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1050 return 0;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1051 if (elements > size)
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1052 return 0;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1053 return 1;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1054 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1055
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1056 int qmatrix_resize(q_t *m, const size_t row, const size_t column) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1057 const size_t rc = row * column;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1058 const size_t sz = m[LENGTH];
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1059 if ((row && column) && (rc < row || rc < column)) /* overflow */
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1060 return -1;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1061 if (rc > sz)
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1062 return -1;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1063 m[ROW] = row;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1064 m[COLUMN] = column;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1065 return 0;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1066 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1067
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1068 int qmatrix_apply_unary(q_t *r, const q_t *a, q_t (*func)(q_t)) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1069 assert(r);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1070 assert(qmatrix_is_valid(r));
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1071 assert(a);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1072 assert(qmatrix_is_valid(a));
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1073 assert(func);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1074 const q_t *ma = &a[DATA];
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1075 q_t *mr = &r[DATA];
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1076 const size_t arows = a[ROW], acolumns = a[COLUMN];
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1077 if (qmatrix_resize(r, arows, acolumns) < 0)
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1078 return -1;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1079 for (size_t i = 0; i < arows; i++)
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1080 for (size_t j = 0; j < acolumns; j++)
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1081 mr[i*acolumns + j] = func(ma[i*acolumns + j]);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1082 return 0;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1083 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1084
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1085 int qmatrix_apply_scalar(q_t *r, const q_t *a, q_t (*func)(q_t, q_t), const q_t c) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1086 assert(r);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1087 assert(qmatrix_is_valid(r));
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1088 assert(a);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1089 assert(qmatrix_is_valid(a));
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1090 assert(func);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1091 const q_t *ma = &a[DATA];
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1092 q_t *mr = &r[DATA];
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1093 const size_t arows = a[ROW], acolumns = a[COLUMN];
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1094 if (qmatrix_resize(r, arows, acolumns) < 0)
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1095 return -1;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1096 for (size_t i = 0; i < arows; i++)
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1097 for (size_t j = 0; j < acolumns; j++)
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1098 mr[i*acolumns + j] = func(ma[i*acolumns + j], c);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1099 return 0;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1100 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1101
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1102 int qmatrix_apply_binary(q_t *r, const q_t *a, const q_t *b, q_t (*func)(q_t, q_t)) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1103 assert(a);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1104 assert(qmatrix_is_valid(a));
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1105 assert(b);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1106 assert(qmatrix_is_valid(b));
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1107 assert(r);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1108 assert(qmatrix_is_valid(r));
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1109 assert(func);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1110 const q_t *ma = &a[DATA], *mb = &b[DATA];
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1111 q_t *mr = &r[DATA];
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1112 const size_t arows = a[ROW], acolumns = a[COLUMN];
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1113 const size_t brows = b[ROW], bcolumns = b[COLUMN];
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1114 const size_t rrows = r[ROW], rcolumns = r[COLUMN];
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1115 if (arows != brows || acolumns != bcolumns)
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1116 return -1;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1117 if (arows != rrows || acolumns != rcolumns)
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1118 return -1;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1119 for (size_t i = 0; i < arows; i++)
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1120 for (size_t j = 0; j < acolumns; j++) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1121 const size_t idx = (i*acolumns) + j;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1122 mr[idx] = func(ma[idx], mb[idx]);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1123 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1124 return 0;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1125 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1126
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1127 static q_t qfz(q_t a) { UNUSED(a); return QINT(0); }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1128 static q_t qf1(q_t a) { UNUSED(a); return QINT(1); }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1129
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1130 int qmatrix_zero(q_t *r) { return qmatrix_apply_unary(r, r, qfz); }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1131 int qmatrix_one(q_t *r) { return qmatrix_apply_unary(r, r, qf1); }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1132 int qmatrix_logical(q_t *r, const q_t *a) { return qmatrix_apply_unary(r, a, qlogical); }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1133 int qmatrix_not(q_t *r, const q_t *a) { return qmatrix_apply_unary(r, a, qnot); }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1134 int qmatrix_signum(q_t *r, const q_t *a) { return qmatrix_apply_unary(r, a, qsignum); }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1135 int qmatrix_invert(q_t *r, const q_t *a) { return qmatrix_apply_unary(r, a, qinvert); }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1136 int qmatrix_add(q_t *r, const q_t *a, const q_t *b) { return qmatrix_apply_binary(r, a, b, qadd); }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1137 int qmatrix_sub(q_t *r, const q_t *a, const q_t *b) { return qmatrix_apply_binary(r, a, b, qsub); }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1138 int qmatrix_and(q_t *r, const q_t *a, const q_t *b) { return qmatrix_apply_binary(r, a, b, qand); }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1139 int qmatrix_or (q_t *r, const q_t *a, const q_t *b) { return qmatrix_apply_binary(r, a, b, qor); }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1140 int qmatrix_xor(q_t *r, const q_t *a, const q_t *b) { return qmatrix_apply_binary(r, a, b, qxor); }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1141
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1142 int qmatrix_scalar_add(q_t *r, const q_t *a, const q_t scalar) { return qmatrix_apply_scalar(r, a, qadd, scalar); }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1143 int qmatrix_scalar_sub(q_t *r, const q_t *a, const q_t scalar) { return qmatrix_apply_scalar(r, a, qsub, scalar); }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1144 int qmatrix_scalar_mul(q_t *r, const q_t *a, const q_t scalar) { return qmatrix_apply_scalar(r, a, qmul, scalar); }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1145 int qmatrix_scalar_div(q_t *r, const q_t *a, const q_t scalar) { return qmatrix_apply_scalar(r, a, qdiv, scalar); }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1146 int qmatrix_scalar_mod(q_t *r, const q_t *a, const q_t scalar) { return qmatrix_apply_scalar(r, a, qmod, scalar); }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1147 int qmatrix_scalar_rem(q_t *r, const q_t *a, const q_t scalar) { return qmatrix_apply_scalar(r, a, qrem, scalar); }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1148 int qmatrix_scalar_and(q_t *r, const q_t *a, const q_t scalar) { return qmatrix_apply_scalar(r, a, qand, scalar); }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1149 int qmatrix_scalar_or (q_t *r, const q_t *a, const q_t scalar) { return qmatrix_apply_scalar(r, a, qor, scalar); }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1150 int qmatrix_scalar_xor(q_t *r, const q_t *a, const q_t scalar) { return qmatrix_apply_scalar(r, a, qxor, scalar); }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1151
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1152 int qmatrix_is_square(const q_t *m) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1153 assert(m);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1154 assert(qmatrix_is_valid(m));
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1155 return m[COLUMN] == m[ROW];
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1156 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1157
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1158 int qmatrix_identity(q_t *r) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1159 assert(r);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1160 assert(qmatrix_is_valid(r));
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1161 if (!qmatrix_is_square(r))
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1162 return -1;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1163 q_t *mr = &r[DATA];
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1164 const size_t length = r[ROW];
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1165 for (size_t i = 0; i < length; i++)
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1166 for (size_t j = 0; j < length; j++)
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1167 mr[i*length + j] = i == j ? QINT(1) : QINT(0);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1168 return 0;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1169 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1170
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1171 int qmatrix_copy(q_t *r, const q_t *a) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1172 assert(r);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1173 assert(qmatrix_is_valid(r));
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1174 assert(a);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1175 assert(qmatrix_is_valid(a));
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1176 const size_t arows = a[ROW], acolumns = a[COLUMN];
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1177 const size_t copy = arows * acolumns * sizeof (q_t);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1178 if ((arows && acolumns) && (copy < arows || copy < acolumns))
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1179 return -1;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1180 if (qmatrix_resize(r, arows, acolumns) < 0)
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1181 return -1;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1182 memcpy(&r[DATA], &a[DATA], copy);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1183 return 0;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1184 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1185
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1186 q_t qmatrix_trace(const q_t *m) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1187 assert(m);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1188 assert(qmatrix_is_square(m));
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1189 const size_t length = m[ROW];
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1190 const q_t *mm = &m[DATA];
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1191 q_t tr = QINT(0);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1192 for (size_t i = 0; i < length; i++)
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1193 for (size_t j = 0; j < length; j++)
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1194 if (i == j)
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1195 tr = qadd(tr, mm[i*length + j]);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1196 return tr;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1197 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1198
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1199 q_t qmatrix_equal(const q_t *a, const q_t *b) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1200 assert(a);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1201 assert(qmatrix_is_valid(a));
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1202 assert(b);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1203 assert(qmatrix_is_valid(b));
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1204 const size_t arow = a[ROW], acolumn = a[COLUMN];
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1205 const size_t brow = b[ROW], bcolumn = b[COLUMN];
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1206 const q_t *ma = &a[DATA];
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1207 const q_t *mb = &a[DATA];
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1208 if (a == b)
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1209 return QINT(1);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1210 if (arow != brow && acolumn != bcolumn)
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1211 return QINT(0);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1212 return !memcmp(ma, mb, sizeof(q_t) * arow * brow);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1213 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1214
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1215 static q_t determine(const q_t *m, const size_t length) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1216 assert(m);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1217 if (length == 1)
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1218 return m[0];
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1219 if (length == 2)
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1220 return qsub(qmul(m[0], m[3]), qmul(m[1], m[2]));
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1221 size_t co1 = 0, co2 = 0;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1222 q_t det = QINT(0), sgn = QINT(1);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1223 q_t co[length*length]; /* This should really be passed in */
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1224 for (size_t i = 0; i < length; i++) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1225 for (size_t j = 0; j < length; j++)
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1226 for (size_t k = 0; k < length; k++)
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1227 if (j && k != i) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1228 co[co1*length + co2] = m[j*length + k];
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1229 if (++co2 > (length - 2)) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1230 co1++;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1231 co2 = 0;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1232 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1233 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1234 det = qadd(det, qcopysign(qmul(m[(0*length) + i], determine(co, length - 1)), sgn));
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1235 sgn = qnegate(sgn);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1236 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1237 return det;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1238 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1239
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1240 q_t qmatrix_determinant(const q_t *m) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1241 assert(m);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1242 assert(qmatrix_is_square(m));
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1243 assert(m[ROW] < 16);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1244 const size_t length = m[ROW];
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1245 const q_t *mm = &m[DATA];
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1246 return determine(mm, length);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1247 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1248
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1249 int qmatrix_transpose(q_t *r, const q_t *m) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1250 assert(r);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1251 assert(qmatrix_is_valid(r));
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1252 assert(m);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1253 assert(qmatrix_is_valid(m));
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1254 q_t *mr = &r[DATA];
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1255 const q_t *mm = &m[DATA];
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1256 const size_t mrows = m[ROW], mcolumns = m[COLUMN];
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1257 const size_t msize = mrows * mcolumns;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1258 const size_t rsize = r[LENGTH];
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1259 if (msize > rsize)
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1260 return -1;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1261 for (size_t i = 0; i < mrows; i++)
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1262 for (size_t j = 0; j < mcolumns; j++)
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1263 mr[i*mcolumns + j] = mm[j*mcolumns + i];
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1264 r[ROW] = mcolumns;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1265 r[COLUMN] = mrows;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1266 return 0;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1267 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1268
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1269 int qmatrix_mul(q_t *r, const q_t *a, const q_t *b) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1270 assert(a);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1271 assert(qmatrix_is_valid(a));
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1272 assert(b);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1273 assert(qmatrix_is_valid(b));
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1274 assert(r);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1275 assert(qmatrix_is_valid(r));
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1276 q_t *mr = &r[DATA];
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1277 const q_t *ma = &a[DATA], *mb = &b[DATA];
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1278 const size_t arows = a[ROW], acolumns = a[COLUMN];
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1279 const size_t brows = b[ROW], bcolumns = b[COLUMN];
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1280 if (acolumns != brows)
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1281 return -1;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1282 if (qmatrix_resize(r, arows, bcolumns) < 0)
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1283 return -1;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1284 for (size_t i = 0; i < arows; i++)
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1285 for (size_t j = 0; j < bcolumns; j++) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1286 q_t s = QINT(0);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1287 for (size_t k = 0; k < brows; k++)
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1288 s = qadd(s, qmul(ma[i*acolumns + k], mb[k*bcolumns + j]));
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1289 mr[i*arows + j] = s;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1290 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1291 return 0;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1292 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1293
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1294 static int addchar(char **str, size_t *length, const int ch) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1295 assert(str && *str);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1296 assert(length);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1297 if (!length)
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1298 return -1;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1299 char *s = *str;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1300 *s++ = ch;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1301 *str = s;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1302 *length -= 1;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1303 return 0;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1304 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1305
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1306 static int addstr(char **str, size_t *length, char *addme) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1307 assert(str && *str);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1308 assert(length);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1309 assert(addme);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1310 const size_t sz = strlen(addme);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1311 for (size_t i = 0; i < sz; i++)
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1312 if (addchar(str, length, addme[i]) < 0)
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1313 return -1;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1314 return 0;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1315 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1316
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1317 int qmatrix_sprintb(const q_t *m, char *str, size_t length, unsigned base) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1318 assert(str);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1319 assert(m);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1320 const q_t *mm = &m[DATA];
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1321 const size_t rows = m[ROW], columns = m[COLUMN];
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1322 if (base < 2 || base > 36)
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1323 return -1;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1324 if (!qmatrix_is_valid(m))
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1325 return addstr(&str, &length, "[ INVALID ]");
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1326 if (addstr(&str, &length, "[ ") < 0)
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1327 return -1;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1328 for (size_t i = 0; i < rows; i++) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1329 for (size_t j = 0; j < columns; j++) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1330 const int r = qsprintb(mm[i*columns + j], str, length, base);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1331 if (r < 0)
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1332 return -1;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1333 if ((length - r) > length)
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1334 return -1;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1335 length -= r;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1336 str += r;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1337 if (rows)
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1338 if (addchar(&str, &length, columns && j < (columns - 1) ? ',' : i < rows - 1 ? ';' : ' ') < 0)
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1339 return -1;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1340 if ((columns && j < (columns - 1)) || (i < (rows - 1)))
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1341 if (addchar(&str, &length, ' ') < 0)
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1342 return -1;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1343 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1344 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1345 if (addchar(&str, &length, ']') < 0)
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1346 return -1;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1347 return 0;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1348 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1349
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1350 size_t qmatrix_string_length(const q_t *m) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1351 assert(m);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1352 if (!qmatrix_is_valid(m))
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1353 return 128; /* space for invalid matrix message */
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1354 const size_t msize = m[LENGTH];
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1355 const size_t r = (msize *
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1356 (32 /*max length if base 2 used)*/
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1357 + 2 /* '-' and '.' */
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1358 + 2 /* space and comma/semi colon separator */
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1359 )) + 16 /* space for extra formatting */;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1360 return r;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1361 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1362
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1363 /* See <https://github.com/jamesbowman/sincos>
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1364 * and "Math Toolkit for Real-Time Programming" by Jack Crenshaw
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1365 *
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1366 * The naming of these functions ('furman_') is incorrect, they do their
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1367 * computation on numbers represented in Furmans but they do not use a 'Furman
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1368 * algorithm'. As I do not have a better name, the name shall stick. */
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1369 static int16_t _sine(const int16_t y) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1370 const int16_t s1 = 0x6487, s3 = -0x2953, s5 = 0x04f8;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1371 const int16_t z = arshift((int32_t)y * y, 12);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1372 int16_t prod = arshift((int32_t)z * s5, 16);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1373 int16_t sum = s3 + prod;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1374 prod = arshift((int32_t)z * sum, 16);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1375 sum = s1 + prod;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1376 return arshift((int32_t)y * sum, 13);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1377 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1378
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1379 static int16_t _cosine(int16_t y) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1380 const int16_t c0 = 0x7fff, c2 = -0x4ee9, c4 = 0x0fbd;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1381 const int16_t z = arshift((int32_t)y * y, 12);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1382 int16_t prod = arshift((int32_t)z * c4, 16);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1383 const int16_t sum = c2 + prod;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1384 prod = arshift((int32_t)z * sum, 15);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1385 return c0 + prod;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1386 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1387
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1388 int16_t furman_sin(int16_t x) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1389 const int16_t n = 3 & arshift(x + 0x2000, 14);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1390 x -= n << 14;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1391 const int16_t r = (n & 1) ? _cosine(x) : _sine(x);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1392 return (n & 2) ? -r : r;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1393 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1394
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1395 int16_t furman_cos(int16_t x) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1396 return furman_sin(x + 0x4000);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1397 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1398
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1399 /* expression evaluator */
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1400
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1401 enum { ASSOCIATE_NONE, ASSOCIATE_LEFT, ASSOCIATE_RIGHT, };
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1402 enum { LEX_NUMBER, LEX_OPERATOR, LEX_END, };
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1403
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1404 int qexpr_init(qexpr_t *e) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1405 assert(e);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1406 e->lpar = qop("(");
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1407 e->rpar = qop(")");
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1408 e->negate = qop("negate");
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1409 e->minus = qop("-");
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1410 e->initialized = 1;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1411 assert(e->lpar && e->rpar && e->negate && e->minus);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1412 return 0;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1413 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1414
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1415 static int error(qexpr_t *e, const char *fmt, ...) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1416 assert(e);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1417 assert(fmt);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1418 if (e->error)
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1419 return 0;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1420 va_list ap;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1421 va_start(ap, fmt);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1422 (void)vsnprintf(e->error_string, sizeof (e->error_string), fmt, ap);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1423 va_end(ap);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1424 e->error = -1;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1425 return -QINT(1);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1426 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1427
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1428 static q_t numberify(const char *s) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1429 assert(s);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1430 q_t q = 0;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1431 (void) qconv(&q, s);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1432 return q;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1433 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1434
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1435 static q_t qbase(q_t b) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1436 int nb = qtoi(b);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1437 if (nb < 2 || nb > 36)
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1438 return -QINT(1);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1439 qconf.base = nb;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1440 return b;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1441 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1442
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1443 static q_t qplaces(q_t places) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1444 /* TODO: Bounds checks given base */
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1445 qconf.dp = qtoi(places);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1446 return places;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1447 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1448
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1449 static q_t check_div0(qexpr_t *e, q_t a, q_t b) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1450 assert(e);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1451 UNUSED(a);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1452 if (!b)
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1453 return error(e, "division by zero");
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1454 return QINT(0);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1455 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1456
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1457 static q_t check_nlz(qexpr_t *e, q_t a) { // Not Less Zero
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1458 assert(e);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1459 if (qless(a, QINT(0)))
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1460 return error(e, "negative argument");
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1461 return QINT(0);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1462 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1463
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1464 static q_t check_nlez(qexpr_t *e, q_t a) { // Not Less Equal Zero
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1465 assert(e);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1466 if (qeqless(a, QINT(0)))
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1467 return error(e, "negative or zero argument");
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1468 return QINT(0);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1469 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1470
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1471 static q_t check_nlo(qexpr_t *e, q_t a) { // Not less than one
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1472 assert(e);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1473 if (qless(a, QINT(1)))
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1474 return error(e, "out of range [1, INF]");
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1475 return QINT(0);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1476 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1477
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1478 static q_t check_alo(qexpr_t *e, q_t a) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1479 assert(e);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1480 if (qmore(qabs(a), QINT(1)))
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1481 return error(e, "out of range [-1, 1]");
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1482 return QINT(0);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1483 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1484
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1485 const qoperations_t *qop(const char *op) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1486 assert(op);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1487 static const qoperations_t ops[] = {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1488 /* Binary Search Table: Use 'LC_ALL="C" sort -k 2 < table' to sort this */
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1489 /* name function check function precedence arity left/right-assoc hidden */
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1490 { "!", .eval.unary = qnot, .check.unary = NULL, 5, 1, ASSOCIATE_RIGHT, 0, },
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1491 { "!=", .eval.binary = qunequal, .check.binary = NULL, 2, 2, ASSOCIATE_LEFT, 0, },
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1492 { "%", .eval.binary = qrem,/*!*/ .check.binary = check_div0, 3, 2, ASSOCIATE_LEFT, 0, },
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1493 { "&", .eval.binary = qand, .check.binary = NULL, 2, 2, ASSOCIATE_LEFT, 0, },
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1494 { "(", .eval.unary = NULL, .check.unary = NULL, 0, 0, ASSOCIATE_NONE, 0, },
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1495 { ")", .eval.unary = NULL, .check.unary = NULL, 0, 0, ASSOCIATE_NONE, 0, },
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1496 { "*", .eval.binary = qmul, .check.binary = NULL, 3, 2, ASSOCIATE_LEFT, 0, },
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1497 { "+", .eval.binary = qadd, .check.binary = NULL, 2, 2, ASSOCIATE_LEFT, 0, },
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1498 { "-", .eval.binary = qsub, .check.binary = NULL, 2, 2, ASSOCIATE_LEFT, 0, },
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1499 { "/", .eval.binary = qdiv, .check.binary = check_div0, 3, 2, ASSOCIATE_LEFT, 0, },
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1500 { "<", .eval.binary = qless, .check.binary = NULL, 2, 2, ASSOCIATE_LEFT, 0, },
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1501 { "<<", .eval.binary = qlls, .check.binary = NULL, 4, 2, ASSOCIATE_RIGHT, 0, },
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1502 { "<=", .eval.binary = qeqless, .check.binary = NULL, 2, 2, ASSOCIATE_LEFT, 0, },
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1503 { "==", .eval.binary = qequal, .check.binary = NULL, 2, 2, ASSOCIATE_LEFT, 0, },
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1504 { ">", .eval.binary = qmore, .check.binary = NULL, 2, 2, ASSOCIATE_LEFT, 0, },
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1505 { ">=", .eval.binary = qeqmore, .check.binary = NULL, 2, 2, ASSOCIATE_LEFT, 0, },
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1506 { ">>", .eval.binary = qlrs, .check.binary = NULL, 4, 2, ASSOCIATE_RIGHT, 0, },
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1507 { "^", .eval.binary = qxor, .check.binary = NULL, 2, 2, ASSOCIATE_LEFT, 0, },
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1508 { "_div", .eval.binary = qcordic_div, .check.binary = NULL, 5, 2, ASSOCIATE_RIGHT, 1, },
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1509 { "_exp", .eval.unary = qcordic_exp, .check.unary = NULL, 5, 1, ASSOCIATE_RIGHT, 1, },
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1510 { "_ln", .eval.unary = qcordic_ln, .check.unary = check_nlez, 5, 1, ASSOCIATE_RIGHT, 1, },
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1511 { "_mul", .eval.binary = qcordic_mul, .check.binary = NULL, 5, 2, ASSOCIATE_RIGHT, 1, },
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1512 { "_sqrt", .eval.unary = qcordic_sqrt, .check.unary = check_nlz, 5, 1, ASSOCIATE_RIGHT, 1, },
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1513 { "abs", .eval.unary = qabs, .check.unary = NULL, 5, 1, ASSOCIATE_RIGHT, 0, },
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1514 { "acos", .eval.unary = qacos, .check.unary = check_alo, 5, 1, ASSOCIATE_RIGHT, 0, },
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1515 { "acosh", .eval.unary = qacosh, .check.unary = check_nlo, 5, 1, ASSOCIATE_RIGHT, 0, },
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1516 { "arshift", .eval.binary = qars, .check.binary = NULL, 4, 2, ASSOCIATE_RIGHT, 1, },
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1517 { "asin", .eval.unary = qasin, .check.unary = check_alo, 5, 1, ASSOCIATE_RIGHT, 0, },
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1518 { "asinh", .eval.unary = qasinh, .check.unary = NULL, 5, 1, ASSOCIATE_RIGHT, 0, },
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1519 { "atan", .eval.unary = qatan, .check.unary = NULL, 5, 1, ASSOCIATE_RIGHT, 0, },
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1520 { "atan2", .eval.binary = qatan2, .check.binary = NULL, 5, 2, ASSOCIATE_RIGHT, 1, },
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1521 { "atanh", .eval.unary = qatanh, .check.unary = check_alo, 5, 1, ASSOCIATE_RIGHT, 0, },
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1522 { "base", .eval.unary = qbase, .check.unary = NULL, 2, 1, ASSOCIATE_RIGHT, 0, },
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1523 { "ceil", .eval.unary = qceil, .check.unary = NULL, 5, 1, ASSOCIATE_RIGHT, 0, },
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1524 { "copysign", .eval.binary = qcopysign, .check.binary = NULL, 4, 2, ASSOCIATE_RIGHT, 1, },
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1525 { "cos", .eval.unary = qcos, .check.unary = NULL, 5, 1, ASSOCIATE_RIGHT, 0, },
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1526 { "cosh", .eval.unary = qcosh, .check.unary = NULL, 5, 1, ASSOCIATE_RIGHT, 0, },
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1527 { "cot", .eval.unary = qcot, .check.unary = NULL, 5, 1, ASSOCIATE_RIGHT, 0, },
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1528 { "deg2rad", .eval.unary = qdeg2rad, .check.unary = NULL, 5, 1, ASSOCIATE_RIGHT, 0, },
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1529 { "even?", .eval.unary = qiseven, .check.unary = NULL, 5, 1, ASSOCIATE_RIGHT, 0, },
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1530 { "exp", .eval.unary = qexp, .check.unary = NULL, 5, 1, ASSOCIATE_RIGHT, 0, },
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1531 { "floor", .eval.unary = qfloor, .check.unary = NULL, 5, 1, ASSOCIATE_RIGHT, 0, },
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1532 { "hypot", .eval.binary = qhypot, .check.binary = NULL, 5, 2, ASSOCIATE_RIGHT, 0, },
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1533 { "int?", .eval.unary = qisinteger, .check.unary = NULL, 5, 1, ASSOCIATE_RIGHT, 0, },
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1534 { "log", .eval.unary = qlog, .check.unary = check_nlez, 5, 1, ASSOCIATE_RIGHT, 0, },
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1535 { "lshift", .eval.binary = qlls, .check.binary = NULL, 4, 2, ASSOCIATE_RIGHT, 1, },
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1536 { "max", .eval.binary = qmax, .check.binary = NULL, 5, 2, ASSOCIATE_RIGHT, 1, },
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1537 { "min", .eval.binary = qmin, .check.binary = NULL, 5, 2, ASSOCIATE_RIGHT, 1, },
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1538 { "mod", .eval.binary = qmod, .check.binary = check_div0, 3, 2, ASSOCIATE_LEFT, 0, },
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1539 { "neg?", .eval.unary = qisnegative, .check.unary = NULL, 5, 1, ASSOCIATE_RIGHT, 0, },
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1540 { "negate", .eval.unary = qnegate, .check.unary = NULL, 5, 1, ASSOCIATE_RIGHT, 0, },
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1541 { "odd?", .eval.unary = qisodd, .check.unary = NULL, 5, 1, ASSOCIATE_RIGHT, 0, },
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1542 { "places", .eval.unary = qplaces, .check.unary = NULL, 2, 1, ASSOCIATE_RIGHT, 0, },
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1543 { "pos?", .eval.unary = qispositive, .check.unary = NULL, 5, 1, ASSOCIATE_RIGHT, 0, },
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1544 { "pow", .eval.binary = qpow, .check.binary = NULL, 5, 2, ASSOCIATE_RIGHT, 0, },
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1545 { "rad2deg", .eval.unary = qrad2deg, .check.unary = NULL, 5, 1, ASSOCIATE_RIGHT, 0, },
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1546 { "rem", .eval.binary = qrem, .check.binary = check_div0, 3, 2, ASSOCIATE_LEFT, 0, },
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1547 { "round", .eval.unary = qround, .check.unary = NULL, 5, 1, ASSOCIATE_RIGHT, 0, },
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1548 { "rshift", .eval.binary = qlrs, .check.binary = NULL, 4, 2, ASSOCIATE_RIGHT, 1, },
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1549 { "sign", .eval.unary = qsign, .check.unary = NULL, 5, 1, ASSOCIATE_RIGHT, 0, },
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1550 { "signum", .eval.unary = qsignum, .check.unary = NULL, 5, 1, ASSOCIATE_RIGHT, 0, },
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1551 { "sin", .eval.unary = qsin, .check.unary = NULL, 5, 1, ASSOCIATE_RIGHT, 0, },
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1552 { "sinh", .eval.unary = qsinh, .check.unary = NULL, 5, 1, ASSOCIATE_RIGHT, 0, },
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1553 { "sqrt", .eval.unary = qsqrt, .check.unary = check_nlz, 5, 1, ASSOCIATE_RIGHT, 0, },
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1554 { "tan", .eval.unary = qtan, .check.unary = NULL, 5, 1, ASSOCIATE_RIGHT, 0, },
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1555 { "tanh", .eval.unary = qtanh, .check.unary = NULL, 5, 1, ASSOCIATE_RIGHT, 0, },
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1556 { "trunc", .eval.unary = qtrunc, .check.unary = NULL, 5, 1, ASSOCIATE_RIGHT, 0, },
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1557 { "|", .eval.binary = qor, .check.binary = NULL, 2, 2, ASSOCIATE_LEFT, 0, },
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1558 { "~", .eval.unary = qinvert, .check.unary = NULL, 5, 1, ASSOCIATE_RIGHT, 0, },
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1559 };
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1560 const size_t length = (sizeof ops / sizeof ops[0]);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1561 size_t l = 0, r = length - 1;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1562 while (l <= r) { // Iterative Binary Search
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1563 size_t m = l + ((r - l)/2u);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1564 assert (m < length);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1565 const int comp = strcmp(ops[m].name, op);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1566 if (comp == 0)
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1567 return &ops[m];
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1568 if (comp < 0)
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1569 l = m + 1;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1570 else
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1571 r = m - 1;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1572 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1573 return NULL;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1574 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1575
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1576 static int number_push(qexpr_t *e, q_t num) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1577 assert(e);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1578 if (e->error)
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1579 return -1;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1580 if (e->numbers_count > (e->numbers_max - 1)) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1581 error(e, "number stack overflow");
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1582 return -1;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1583 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1584 e->numbers[e->numbers_count++] = num;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1585 return 0;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1586 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1587
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1588 static q_t number_pop(qexpr_t *e) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1589 assert(e);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1590 if (e->error)
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1591 return -1;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1592 if (!(e->numbers_count)) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1593 error(e, "number stack empty");
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1594 return -1; /* error handled elsewhere */
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1595 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1596 return e->numbers[--(e->numbers_count)];
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1597 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1598
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1599 static int op_push(qexpr_t *e, const qoperations_t *op) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1600 assert(e);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1601 assert(op);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1602 if (e->error)
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1603 return -1;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1604 if (e->ops_count > (e->ops_max - 1)) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1605 error(e, "operator stack overflow");
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1606 return -1;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1607 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1608 e->ops[e->ops_count++] = op;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1609 return 0;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1610 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1611
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1612 int qexpr_error(qexpr_t *e) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1613 assert(e);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1614 assert(e->initialized);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1615 return e->error;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1616 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1617
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1618 q_t qexpr_result(qexpr_t *e) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1619 assert(e);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1620 assert(e->initialized);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1621 assert(e->error == 0);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1622 assert(e->numbers_count == 1);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1623 return e->numbers[0];
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1624 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1625
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1626 static const qoperations_t *op_pop(qexpr_t *e) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1627 assert(e);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1628 if (e->error)
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1629 return NULL;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1630 if (!(e->ops_count)) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1631 error(e, "operator stack empty");
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1632 return NULL;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1633 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1634 return e->ops[--(e->ops_count)];
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1635 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1636
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1637 static int op_eval(qexpr_t *e) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1638 assert(e);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1639 const qoperations_t *pop = op_pop(e);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1640 if (!pop)
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1641 return -1;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1642 const q_t a = number_pop(e);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1643 const int exists = pop->arity == 1 ? BOOLIFY(pop->eval.unary) : BOOLIFY(pop->eval.binary);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1644 if (!exists) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1645 error(e, "syntax error");
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1646 return -1;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1647 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1648 if (pop->arity == 1) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1649 if (pop->check.unary && pop->check.unary(e, a) < 0) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1650 error(e, "unary check failed");
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1651 return -1;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1652 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1653 return number_push(e, pop->eval.unary(a));
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1654 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1655 const q_t b = number_pop(e);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1656 if (pop->check.binary && pop->check.binary(e, b, a)) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1657 error(e, "binary check failed");
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1658 return -1;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1659 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1660
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1661 return number_push(e, pop->eval.binary(b, a));
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1662 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1663
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1664 static int shunt(qexpr_t *e, const qoperations_t *op) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1665 assert(e);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1666 assert(op);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1667 if (op == e->lpar) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1668 return op_push(e, op);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1669 } else if (op == e->rpar) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1670 while (e->ops_count && e->ops[e->ops_count - 1] != e->lpar)
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1671 if (op_eval(e) < 0 || e->error)
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1672 break;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1673 const qoperations_t *pop = op_pop(e);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1674 if (!pop || (pop != e->lpar)) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1675 e->error = 0; /* clear error so following error is printed */
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1676 error(e, "expected \"(\"");
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1677 return -1;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1678 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1679 return 0;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1680 } else if (op->assocativity == ASSOCIATE_RIGHT) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1681 while (e->ops_count && op->precedence < e->ops[e->ops_count - 1]->precedence)
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1682 if (op_eval(e) < 0 || e->error)
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1683 break;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1684 } else {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1685 while (e->ops_count && op->precedence <= e->ops[e->ops_count - 1]->precedence)
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1686 if (op_eval(e) < 0 || e->error)
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1687 break;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1688 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1689 return op_push(e, op);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1690 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1691
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1692 static int variable_name_is_valid(const char *n) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1693 assert(n);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1694 if (!isalpha(*n) && !(*n == '_'))
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1695 return 0;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1696 for (n++; *n; n++)
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1697 if (!isalnum(*n) && !(*n == '_'))
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1698 return 0;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1699 return 1;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1700 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1701
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1702 static qvariable_t *variable_lookup(qexpr_t *e, const char *name) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1703 assert(e);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1704 assert(name);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1705 for (size_t i = 0; i < e->vars_max; i++) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1706 qvariable_t *v = e->vars[i];
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1707 assert(v->name);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1708 assert(variable_name_is_valid(v->name));
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1709 if (!strcmp(v->name, name))
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1710 return v;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1711 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1712 return NULL;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1713 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1714
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1715 static int lex(qexpr_t *e, const char **expr) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1716 assert(e);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1717 assert(expr && *expr);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1718 int r = 0;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1719 const char *s = *expr;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1720 qvariable_t *v = NULL;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1721 e->id_count = 0;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1722 e->number = 0;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1723 e->op = NULL;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1724 memset(e->id, 0, sizeof (e->id));
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1725 for (; *s && isspace(*s); s++)
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1726 ;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1727 if (!(*s))
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1728 return LEX_END;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1729 if (isalpha(*s) || *s == '_') {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1730 for (; e->id_count < sizeof(e->id) && *s && (isalnum(*s) || *s == '_');)
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1731 e->id[e->id_count++] = *s++;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1732 if ((v = variable_lookup(e, e->id))) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1733 e->number = v->value;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1734 r = LEX_NUMBER;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1735 } else if ((e->op = qop(e->id))) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1736 r = LEX_OPERATOR;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1737 } else {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1738 r = -1;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1739 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1740 } else {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1741 if (ispunct(*s)) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1742 const qoperations_t *op1 = NULL, *op2 = NULL;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1743 int set = 0;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1744 e->id[e->id_count++] = *s++;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1745 op1 = qop(e->id);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1746 if (*s && ispunct(*s)) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1747 set = 1;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1748 e->id[e->id_count++] = *s++;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1749 op2 = qop(e->id);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1750 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1751 r = (op1 || op2) ? LEX_OPERATOR : -1;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1752 e->op = op2 ? op2 : op1;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1753 if (e->op == op1 && set) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1754 s--;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1755 e->id_count--;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1756 e->id[1] = 0;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1757 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1758 } else if (isdigit(*s)) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1759 r = LEX_NUMBER;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1760 int dot = 0;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1761 for (; e->id_count < sizeof(e->id) && *s; s++) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1762 const int ch = *s;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1763 if (!(isdigit(ch) || (ch == '.' && !dot)))
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1764 break;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1765 e->id[e->id_count++] = ch;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1766 if (ch == '.')
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1767 dot = 1;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1768 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1769 e->number = numberify(e->id);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1770 } else {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1771 r = -1;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1772 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1773 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1774 /*printf("id(%d) %d => %s\n", (int)(s - *expr), r, e->id);*/
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1775 *expr = s;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1776 return r;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1777 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1778
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1779 int qexpr(qexpr_t *e, const char *expr) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1780 assert(e);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1781 assert(expr);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1782 int firstop = 1;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1783 const qoperations_t *previous = NULL;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1784 if (e->initialized) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1785 memset(e->error_string, 0, sizeof (e->error_string));
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1786 e->error = 0;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1787 e->ops_count = 0;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1788 e->numbers_count = 0;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1789 e->initialized = 1;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1790 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1791 for (int l = 0; l != LEX_END && !(e->error);) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1792 switch ((l = lex(e, &expr))) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1793 case LEX_NUMBER:
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1794 number_push(e, e->number);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1795 previous = NULL;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1796 firstop = 0;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1797 break;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1798 case LEX_OPERATOR: {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1799 const qoperations_t *op = e->op;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1800 if (CONFIG_Q_HIDE_FUNCS && op->hidden) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1801 error(e, "unknown operator \"%s\"", op->name);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1802 goto end;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1803 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1804 if (firstop || (previous && previous != e->rpar)) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1805 if (e->op == e->minus) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1806 op = e->negate;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1807 } else if (e->op->arity == 1) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1808 /* do nothing */
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1809 } else if (e->op != e->lpar) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1810 assert(e->op);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1811 error(e, "invalid use of \"%s\"", e->op->name);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1812 goto end;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1813 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1814 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1815 shunt(e, op);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1816 previous = op;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1817 firstop = 0;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1818 break;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1819 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1820 case LEX_END: break;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1821 default:
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1822 error(e, "invalid symbol: %s", e->id);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1823 l = LEX_END;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1824 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1825 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1826 while (e->ops_count)
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1827 if (op_eval(e) < 0 || e->error)
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1828 break;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1829 if (e->numbers_count != 1) {
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1830 error(e, "invalid expression: %d", e->numbers_count);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1831 return -1;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1832 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1833 implies(e->error == 0, e->numbers_count == 1);
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1834 end:
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1835 return e->error == 0 ? 0 : -1;
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1836 }
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1837
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1838
388074ff9474 Add fixed point code
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1839