4 * Copyright (C) 2001-2007 Krzysztof Foltman
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General
17 * Public License along with this program; if not, write to the
18 * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
19 * Boston, MA 02111-1307, USA.
21 #ifndef __CALF_FIXED_POINT_H
22 #define __CALF_FIXED_POINT_H
26 inline uint32_t shr(uint32_t v
, int bits
= 1) { return v
>>bits
; };
27 inline int32_t shr(int32_t v
, int bits
= 1) { return v
>>bits
; };
28 inline uint64_t shr(uint64_t v
, int bits
= 1) { return v
>>bits
; };
29 inline int64_t shr(int64_t v
, int bits
= 1) { return v
>>bits
; };
30 inline float shr(float v
, int bits
= 1) { return v
*(1.0/(1<<bits
)); };
31 inline double shr(double v
, int bits
= 1) { return v
*(1.0/(1<<bits
)); };
32 template<class T
, int FracBits
>
33 inline T
shr(T v
, int bits
= 1) {
38 template<class T
, int FracBits
> class fixed_point
{
40 enum { IntBits
= (sizeof(T
)/8) - FracBits
};
43 /// default constructor, does not initialize the value, just like - say - float doesn't
44 inline fixed_point() {
47 /// copy constructor from any other fixed_point value
48 template<class U
, int FracBits2
> inline fixed_point(const fixed_point
<U
, FracBits2
> &v
) {
49 if (FracBits
== FracBits2
) value
= v
.get();
50 else if (FracBits
> FracBits2
) value
= v
.get() << abs(FracBits
- FracBits2
);
51 else value
= v
.get() >> abs(FracBits
- FracBits2
);
54 /* this would be way too confusing, it wouldn't be obvious if it expects a whole fixed point or an integer part
55 explicit inline fixed_point(T v) {
59 explicit inline fixed_point(double v
) {
63 /// Makes an instance from a representation value (ie. same type of value as is used for internal storage and get/set)
64 static inline fixed_point
from_base(const T
&v
)
71 inline static T
one() {
72 return (T
)(1) << FracBits
;
75 inline void set(T value
) {
79 inline T
get() const {
83 inline operator double() const {
84 return value
* (1.0/one());
87 inline fixed_point
&operator=(double v
) {
92 template<class U
, int FracBits2
> static inline T
rebase(const fixed_point
<U
, FracBits2
> &v
) {
93 if (FracBits
== FracBits2
)
95 if (FracBits
> FracBits2
)
96 return v
.get() << abs(FracBits
- FracBits2
);
97 return v
.get() >> abs(FracBits2
- FracBits
);
100 template<class U
, int FracBits2
> inline fixed_point
&operator=(const fixed_point
<U
, FracBits2
> &v
) {
101 value
= rebase
<U
, FracBits2
>(v
);
105 template<class U
, int FracBits2
> inline fixed_point
&operator+=(const fixed_point
<U
, FracBits2
> &v
) {
106 value
+= rebase
<U
, FracBits2
>(v
);
110 template<class U
, int FracBits2
> inline fixed_point
&operator-=(const fixed_point
<U
, FracBits2
> &v
) {
111 value
-= rebase
<U
, FracBits2
>(v
);
115 template<class U
, int FracBits2
> inline fixed_point
operator+(const fixed_point
<U
, FracBits2
> &v
) const {
117 fpv
.set(value
+ rebase
<U
, FracBits2
>(v
));
121 template<class U
, int FracBits2
> inline fixed_point
operator-(const fixed_point
<U
, FracBits2
> &v
) const {
123 fpv
.set(value
- rebase
<U
, FracBits2
>(v
));
127 /// multiply two fixed point values, using long long int to store the temporary multiplication result
128 template<class U
, int FracBits2
> inline fixed_point
operator*(const fixed_point
<U
, FracBits2
> &v
) const {
130 tmp
.set(((int64_t)value
) * v
.get() >> FracBits2
);
134 /// multiply two fixed point values, using BigType (usually 64-bit int) to store the temporary multiplication result
135 template<class U
, int FracBits2
, class BigType
> inline fixed_point
& operator*=(const fixed_point
<U
, FracBits2
> &v
) {
136 value
= (T
)(((BigType
)value
) * v
.get() >> FracBits2
);
140 inline fixed_point
operator+(int v
) const {
142 tmp
.set(value
+ (v
<< FracBits
));
146 inline fixed_point
operator-(int v
) const {
148 tmp
.set(value
- (v
<< FracBits
));
152 inline fixed_point
operator*(int v
) const {
158 inline fixed_point
& operator+=(int v
) {
159 value
+= (v
<< FracBits
);
163 inline fixed_point
& operator-=(int v
) {
164 value
-= (v
<< FracBits
);
168 inline fixed_point
& operator*=(int v
) {
173 /// return integer part
174 inline T
ipart() const {
175 return value
>> FracBits
;
178 /// return integer part as unsigned int
179 inline unsigned int uipart() const {
180 return ((unsigned)value
) >> FracBits
;
183 /// return integer part as unsigned int
184 inline unsigned int ui64part() const {
185 return ((uint64_t)value
) >> FracBits
;
188 /// return fractional part as 0..(2^FracBits-1)
189 inline T
fpart() const {
190 return value
& ((1 << FracBits
)-1);
193 /// return fractional part as 0..(2^Bits-1)
195 inline T
fpart() const {
196 int fbits
= value
& ((1 << FracBits
)-1);
197 if (Bits
== FracBits
) return fbits
;
198 int shift
= abs(Bits
-FracBits
);
199 return (Bits
< FracBits
) ? (fbits
>> shift
) : (fbits
<< shift
);
202 /// return fractional part as 0..1
203 inline double fpart_as_double() const {
204 return (value
& ((1 << FracBits
)-1)) * (1.0 / (1 << FracBits
));
207 /// use fractional part (either whole or given number of most significant bits) for interpolating between two values
208 /// note that it uses integer arithmetic only, and isn't suitable for floating point or fixed point U!
209 /// @param UseBits can be used when there's a risk of exceeding range of U because max(fpart)*max(v1 or v2) > range of U
210 template<class U
, int UseBits
, class MulType
>
211 inline U
lerp_by_fract_int(U v1
, U v2
) const {
212 int fp
= fpart
<UseBits
>();
213 assert ( fp
>=0 && fp
<= (1<<UseBits
));
215 return v1
+ shr(((MulType
)(v2
-v1
) * fp
), UseBits
);
218 template<class U
, int UseBits
>
219 inline U
lerp_table_lookup_int(U data
[(1<<IntBits
)+1]) const {
220 unsigned int pos
= uipart();
221 return lerp_by_fract_int
<U
, UseBits
>(data
[pos
], data
[pos
+1]);
224 /// Untested... I've started it to get a sin/cos readout for rotaryorgan, but decided to use table-less solution instead
225 /// Do not assume it works, because it most probably doesn't
226 template<class U
, int UseBits
>
227 inline U
lerp_table_lookup_int_shift(U data
[(1<<IntBits
)+1], unsigned int shift
) {
228 unsigned int pos
= (uipart() + shift
) & ((1 << IntBits
) - 1);
229 return lerp_by_fract_int
<U
, UseBits
>(data
[pos
], data
[pos
+1]);
233 inline U
lerp_table_lookup_float(U data
[(1<<IntBits
)+1]) const {
234 unsigned int pos
= uipart();
235 return data
[pos
] + (data
[pos
+1]-data
[pos
]) * fpart_as_double();
239 inline U
lerp_table_lookup_float_mask(U data
[(1<<IntBits
)+1], unsigned int mask
) const {
240 unsigned int pos
= ui64part() & mask
;
241 // printf("full = %lld pos = %d + %f\n", value, pos, fpart_as_double());
242 return data
[pos
] + (data
[pos
+1]-data
[pos
]) * fpart_as_double();
245 template<class U
, int UseBits
, class MulType
>
246 inline U
lerp_ptr_lookup_int(U
*data
) const {
247 unsigned int pos
= ui64part();
248 return lerp_by_fract_int
<U
, UseBits
, MulType
>(data
[pos
], data
[pos
+1]);
252 inline U
lerp_ptr_lookup_float(U
*data
) const {
253 unsigned int pos
= ui64part();
254 return data
[pos
] + (data
[pos
+1]-data
[pos
]) * fpart_as_double();
258 template<class T
, int FractBits
>
259 inline fixed_point
<T
, FractBits
> operator*(int v
, fixed_point
<T
, FractBits
> v2
) {
264 /// wave position (unsigned 64-bit int including 24-bit fractional part)
265 typedef fixed_point
<unsigned long long int, 24> wpos
;