-
Notifications
You must be signed in to change notification settings - Fork 9
/
Copy pathfixed_type.h
256 lines (194 loc) · 10.5 KB
/
fixed_type.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
// Copyright (C) 2021-2022 Victor Suarez Rovere <[email protected]>
#ifndef __FIXED_TYPE__
#define __FIXED_TYPE__
#define FIXED_FRACTIONBITS 10
#ifdef LEVELS
#define FIXED_INTBITS 16
#define fixed_basetype int26_t
#else
#define FIXED_INTBITS 12
#define fixed_basetype int22_t
#endif
#define FIXED_TOTALBITS (FIXED_INTBITS+FIXED_FRACTIONBITS)
//#define FIXED_EMULATE_WITH_FLOAT
#ifndef __cplusplus
#define CCOMPILE
#endif
#ifndef CCOMPILE
//inline fixed_basetype fixed_div_impl(fixed_basetype a, fixed_basetype b, unsigned Q);
template<unsigned Q, unsigned INTBITS>
class fixed_t
{
typedef fixed_basetype base_type;
#ifdef FIXED_EMULATE_WITH_FLOAT
float f;
public:
fixed_t(int a = 0) : f(a) {}
fixed_t(short a) : f(a) {}
fixed_t(float a) : f(a) { }
constexpr fixed_t(double a) : f(a) { }
explicit operator float() const { return f; }
fixed_t operator << (int a) const { return float_shift(f, a); }
fixed_t operator >> (int a) const { return float_shift(f, -a); }
#else //not FIXED_EMULATE_WITH_FLOAT
public:
#ifndef FIXED_TOTALBITS//def NO_BIT_EXACT
//U f;
base_type f;
#else
//U f:Q+INT+1; //+1 for sign
base_type f:FIXED_TOTALBITS;
#endif
public:
fixed_t(int a = 0) : f(a << Q) { }
fixed_t(short a) : f(a << Q) {}
constexpr fixed_t(double a) : f(float_shift(a, Q)) { }
fixed_t(const fixed_t& a) : f(a.f) {}
fixed_t operator * (double b) const { fixed_t r; r.f = f * float(b); return r; }
fixed_t operator * (fixed_t b) const { fixed_t r; r.f = (f * b.f) >> Q; return r; }
fixed_t operator + (fixed_t b) const { fixed_t r; r.f = f + b.f; return r; }
fixed_t operator - (fixed_t b) const { fixed_t r; r.f = f - b.f; return r; }
fixed_t operator - () const { fixed_t r; r.f = -f; return r; }
explicit operator float() const { return float_shift(f, -Q); }
explicit operator int() const { return f>>Q; }
explicit operator short() const { return f>>Q; }
bool operator < (fixed_t b) const { return f < b.f; }
bool operator > (fixed_t b) const { return f > b.f; }
fixed_t operator >> (int s) const { fixed_t r; r.f = f >> s; return r; } //NOTE: may have precision issues
fixed_t operator << (int s) const { fixed_t r; r.f = f << s; return r; } //NOTE: may have precision issues
fixed_t operator / (fixed_t b) const { fixed_t r; r.f = (f << Q) / b.f/*fixed_div_impl(f, b.f, Q)*/; return r; }
bool operator == (fixed_t b) const { return f == b.f; }
bool operator != (fixed_t b) const { return f != b.f; }
#endif //FIXED_EMULATE_WITH_FLOAT
};
typedef fixed_t<FIXED_FRACTIONBITS, FIXED_INTBITS> fixed; //main fixed type name
class fixed3
{
public:
typedef fixed type;
fixed3(type a=0) : x(a),y(a),z(a) {}
fixed3(type a1, type a2, type a3) : x(a1),y(a2),z(a3) {}
fixed3(const fixed3& o) : x(o.x),y(o.y),z(o.z) {}
#if 1
union {
struct {type x, y, z; };
struct {type r, g, b; };
};
#else
type x, y, z;
#endif
//FIXME: maybe implicit
explicit operator float3() const { float3 r = { (float) x, (float) y, (float) z }; return r; }
fixed3 operator * (double v) const { fixed3 r = { x*v, y*v, z*v }; return r; }
fixed3 operator * (type v) const { fixed3 r = { x*v, y*v, z*v }; return r; }
fixed3 operator * (fixed3 v) const { fixed3 r = { x*v.x, y*v.y, z*v.z }; return r; }
fixed3 operator + (fixed3 v) const { fixed3 r = { x+v.x, y+v.y, z+v.z }; return r; }
fixed3 operator - (fixed3 v) const { fixed3 r = { x-v.x, y-v.y, z-v.z }; return r; }
};
fixed fixed_shr(fixed a, shift_t shift) { return a >> shift; }
fixed fixed_shl(fixed a, shift_t shift) { return a << shift; }
inline bool fixed_is_negative(fixed x) { return x.f < 0; }
//inline fixed fixed_abs(fixed x) { return fixed_is_negative(x) ? fixed(-x) : x; }
#warning implement unary -
inline fixed fixed_abs(fixed x) { return fixed_is_negative(x) ? fixed(0)-x : x; }
inline fixed fixed_min(fixed a, fixed b) { return a<b?a:b; }
inline fixed fixed_max(fixed a, fixed b) { return a>b?a:b; }
#define fixed_asinteger(x, s) (int)((x.f) >> (FIXED_FRACTIONBITS-(s)))
#define fixed_asshort(x, s) (short)((x.f) >> (FIXED_FRACTIONBITS-(s)))
#else //CCOMPILE = true
#ifndef FIXED_EMULATE_WITH_FLOAT
#ifndef __PIPELINEC__
#warning merge pipelineC implementation
#ifdef FIXED_TOTALBITS
typedef struct { fixed_basetype f:FIXED_TOTALBITS; } fixed;
#else
typedef struct { fixed_basetype f; } fixed;
#endif
inline constexpr fixed fixed_make_from_int(int a) { const fixed r = {fixed_basetype(a << FIXED_FRACTIONBITS)}; return r; }
inline constexpr fixed fixed_make_from_short(short a) { const fixed r = {fixed_basetype(a << FIXED_FRACTIONBITS)}; return r; }
inline constexpr fixed fixed_make_from_float(float a) { fixed r = {(fixed_basetype) (float(a)*(1<<FIXED_FRACTIONBITS))}; return r; }
inline constexpr fixed fixed_make_from_double(double a) { return fixed_make_from_float(a); }
inline float fixed_to_float(fixed a) { return (float) a.f / (1<<FIXED_FRACTIONBITS); }
inline short fixed_to_short(fixed a) { return a.f >> FIXED_FRACTIONBITS; }
#else // __PIPELINEC__ = true
// No logic functions
#pragma FUNC_WIRES fixed_make_from_int
#pragma FUNC_WIRES fixed_make_from_short
#pragma FUNC_WIRES fixed_to_short
#pragma FUNC_WIRES fixed3_make
#pragma FUNC_WIRES fixed3_make_from_fixed
#pragma FUNC_WIRES fixed3_make_from_const_fixed3
#pragma FUNC_WIRES fixed_make_from_double
#pragma FUNC_WIRES fixed_shl_signed_char
#pragma FUNC_WIRES fixed_shr_signed_char
//#warning: base type of fixed should be correctly defined
typedef struct fixed { fixed_basetype f; } fixed;
fixed fixed_make_from_int(int32_t a) { const fixed r = {a << FIXED_FRACTIONBITS}; return r; }
fixed fixed_make_from_short(int16_t a) { const fixed r = {a << FIXED_FRACTIONBITS}; return r; }
fixed fixed_make_from_float(float a) { fixed r = {(fixed_basetype)float_shift(a, FIXED_FRACTIONBITS)}; return r; }
fixed fixed_make_from_double(double a) { fixed r = {(fixed_basetype) float_shift(a, FIXED_FRACTIONBITS)}; return r; } //a gets a cast prior to call
float_type fixed_to_float(fixed a) { return float_shift((float)a.f, -FIXED_FRACTIONBITS); }
int16_t fixed_to_short(fixed a) { return (int16_t)(a.f >> FIXED_FRACTIONBITS); }
//int fixed_asinteger(fixed a, int n) { return FIXED_FRACTIONBITS > n ? (a.f >> (FIXED_FRACTIONBITS-n)) : (a.f << (n-FIXED_FRACTIONBITS)) }
#endif
#ifdef FP_DEBUG
extern perfcount *fixed_perf;
#endif
inline fixed fixed_mul(fixed left, fixed right) { fixed r = { (fixed_basetype)((left.f * right.f)>>FIXED_FRACTIONBITS) }; LOG_PERF2(fixed_perf, mul); return r; }
inline fixed fixed_mul_short(fixed left, short right) { fixed r = { left.f * (fixed_basetype)right}; LOG_PERF2(fixed_perf, mul); return r; }
inline fixed fixed_shl_signed_char(fixed left, shift_t right) { fixed r; r.f = (fixed_basetype)left.f<<right; return r; }
inline fixed fixed_shr_signed_char(fixed left, shift_t right) { fixed r; r.f = (fixed_basetype)left.f>>right; return r; }
#else //FIXED_EMULATE_WITH_FLOAT = true
typedef float fixed_basetype;
typedef struct fixed { fixed_basetype f; } fixed;
inline constexpr fixed fixed_make_from_int(int a) { const fixed r = {(fixed_basetype)a}; return r; }
inline constexpr fixed fixed_make_from_short(short a) { const fixed r = {(fixed_basetype)a}; return r; }
inline constexpr fixed fixed_make_from_float(float a) { const fixed r = {(fixed_basetype)a}; return r; };
inline constexpr fixed fixed_make_from_double(double a) { const fixed r = {(fixed_basetype)a}; return r; };
inline float fixed_to_float(fixed a) { return a.f; }
inline int fixed_to_int(fixed a) { return (int) a.f; }
inline fixed fixed_mul(fixed left, fixed right) { fixed r = { left.f * right.f}; return r; }
//FIXME: shl/shr doesn't need type of 2nd operand in name (always integer)
//#define fixed_shl_int fixed_shl_signed_char
//#define fixed_shr_int fixed_shr_signed_char
#endif //FIXED_EMULATE_WITH_FLOAT
//this is equivalent with ints or floats
inline fixed fixed_add(fixed left, fixed right) { fixed r = { left.f + right.f}; LOG_PERF2(fixed_perf, add); return r; }
inline fixed fixed_sub(fixed left, fixed right) { fixed r = { left.f - right.f}; LOG_PERF2(fixed_perf, sub); return r; }
inline bool fixed_lt(fixed left, fixed right) { LOG_PERF2(fixed_perf, cmp); return left.f < right.f; }
inline bool fixed_gt(fixed left, fixed right) { LOG_PERF2(fixed_perf, cmp); return left.f > right.f; }
inline bool fixed_lte(fixed left, fixed right) { LOG_PERF2(fixed_perf, cmp); return left.f <= right.f; }
inline bool fixed_gte(fixed left, fixed right) { LOG_PERF2(fixed_perf, cmp); return left.f >= right.f; }
inline bool fixed_eq(fixed left, fixed right) { LOG_PERF2(fixed_perf, cmp); return left.f == right.f; }
inline bool fixed_neq(fixed left, fixed right) { LOG_PERF2(fixed_perf, cmp); return left.f != right.f; }
typedef struct fixed3 { fixed x, y, z; } fixed3;
inline fixed3 fixed3_make(fixed x, fixed y, fixed z) { fixed3 r = {x, y, z}; return r; } //constructor
inline fixed3 fixed3_make_from_fixed(fixed left) { fixed3 r = { left, left, left }; return r; }
inline fixed3 fixed3_add(fixed3 left, fixed3 right)
{ fixed3 r = { fixed_add(left.x, right.x), fixed_add(left.y, right.y), fixed_add(left.z, right.z) }; return r; }
inline fixed3 fixed3_sub(fixed3 left, fixed3 right)
{ fixed3 r = { fixed_sub(left.x, right.x), fixed_sub(left.y, right.y), fixed_sub(left.z, right.z) }; return r; }
inline fixed3 fixed3_mul(fixed3 left, fixed3 right)
{ fixed3 r = { fixed_mul(left.x, right.x), fixed_mul(left.y, right.y), fixed_mul(left.z, right.z) }; return r; }
inline fixed3 fixed3_mul_fixed(fixed3 left, fixed right)
{ fixed3 r = { fixed_mul(left.x, right), fixed_mul(left.y, right), fixed_mul(left.z, right) }; return r; }
#ifndef __PIPELINEC__
inline fixed3 const_fixed3_mul_double(fixed3 left, double right)
{ fixed3 r = { fixed_mul(left.x, fixed_make_from_double(right)), fixed_mul(left.y, fixed_make_from_double(right)), fixed_mul(left.z, fixed_make_from_double(right)) }; return r; }
#else
fixed3 const_fixed3_mul_float(fixed3 left, float right)
{ fixed3 r = { fixed_mul(left.x, fixed_make_from_float(right)), fixed_mul(left.y, fixed_make_from_float(right)), fixed_mul(left.z, fixed_make_from_float(right)) }; return r; }
#define const_fixed3_mul_double(left, right) const_fixed3_mul_float(left, (float)right)
#endif
inline fixed3 fixed3_make_from_const_fixed3(fixed3 a) { return a; }
#if 0
#include "fixed_div.h"
#else
#ifndef __PIPELINEC__
inline fixed fixed_div(fixed a, fixed b) { fixed r; r.f = { (a.f<<FIXED_FRACTIONBITS)/b.f }; return r; }
#else
inline fixed fixed_div(fixed a, fixed b) { fixed r = { (a.f<<FIXED_FRACTIONBITS)/b.f }; return r; }
#endif
#endif
#endif //CCOMPILE
#endif //__FIXED_TYPE__