1 /* Copyright (C) 2005 Jean-Marc Valin */
2 /**
3 @file pseudofloat.h
4 @brief Pseudo-floating point
5 */
6 /*
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions
9 are met:
10
11 - Redistributions of source code must retain the above copyright
12 notice, this list of conditions and the following disclaimer.
13
14 - Redistributions in binary form must reproduce the above copyright
15 notice, this list of conditions and the following disclaimer in the
16 documentation and/or other materials provided with the distribution.
17
18 - Neither the name of the Xiph.org Foundation nor the names of its
19 contributors may be used to endorse or promote products derived from
20 this software without specific prior written permission.
21
22 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
26 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
27 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
29 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
30 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
31 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 */
34
35 #ifndef PSEUDOFLOAT_H
36 #define PSEUDOFLOAT_H
37
38 #include "misc.h"
39 #include <math.h>
40
41 #ifdef FIXED_POINT
42
43 typedef struct {
44 spx_int16_t m;
45 spx_int16_t e;
46 } spx_float_t;
47
48 #define FLOAT_ZERO ((spx_float_t){0,0})
49 #define FLOAT_ONE ((spx_float_t){16384,-14})
50 #define FLOAT_HALF ((spx_float_t){16384,-15})
51
52 #define MIN(a,b) ((a)<(b)?(a):(b))
PSEUDOFLOAT(spx_int32_t x)53 static inline spx_float_t PSEUDOFLOAT(spx_int32_t x)
54 {
55 int e=0;
56 int sign=0;
57 if (x<0)
58 {
59 sign = 1;
60 x = -x;
61 }
62 if (x==0)
63 return (spx_float_t) {0,0};
64 while (x>32767)
65 {
66 x >>= 1;
67 /*x *= .5;*/
68 e++;
69 }
70 while (x<16383)
71 {
72 x <<= 1;
73 /*x *= 2;*/
74 e--;
75 }
76 if (sign)
77 return (spx_float_t) {-x,e};
78 else
79 return (spx_float_t) {x,e};
80 }
81
REALFLOAT(spx_float_t a)82 static inline float REALFLOAT(spx_float_t a)
83 {
84 return a.m * pow(2,a.e);
85 }
86
FLOAT_ADD(spx_float_t a,spx_float_t b)87 static spx_float_t FLOAT_ADD(spx_float_t a, spx_float_t b)
88 {
89 if (a.m==0)
90 return b;
91 else if (b.m==0)
92 return a;
93 spx_float_t r = (a).e > (b).e ? (spx_float_t) {((a).m>>1) + ((b).m>>MIN(15,(a).e-(b).e+1)),(a).e+1} : (spx_float_t) {((b).m>>1) + ((a).m>>MIN(15,(b).e-(a).e+1)),(b).e+1};
94 if (r.m>0)
95 {
96 if (r.m<16384)
97 {
98 r.m<<=1;
99 r.e-=1;
100 }
101 } else {
102 if (r.m>-16384)
103 {
104 r.m<<=1;
105 r.e-=1;
106 }
107 }
108 /*printf ("%f + %f = %f\n", REALFLOAT(a), REALFLOAT(b), REALFLOAT(r));*/
109 return r;
110 }
111
FLOAT_SUB(spx_float_t a,spx_float_t b)112 static spx_float_t FLOAT_SUB(spx_float_t a, spx_float_t b)
113 {
114 if (a.m==0)
115 return b;
116 else if (b.m==0)
117 return a;
118 spx_float_t r = (a).e > (b).e ? (spx_float_t) {((a).m>>1) - ((b).m>>MIN(15,(a).e-(b).e+1)),(a).e+1} : (spx_float_t) {((a).m>>MIN(15,(b).e-(a).e+1)) - ((b).m>>1) ,(b).e+1};
119 if (r.m>0)
120 {
121 if (r.m<16384)
122 {
123 r.m<<=1;
124 r.e-=1;
125 }
126 } else {
127 if (r.m>-16384)
128 {
129 r.m<<=1;
130 r.e-=1;
131 }
132 }
133 /*printf ("%f + %f = %f\n", REALFLOAT(a), REALFLOAT(b), REALFLOAT(r));*/
134 return r;
135 }
136
FLOAT_LT(spx_float_t a,spx_float_t b)137 static inline int FLOAT_LT(spx_float_t a, spx_float_t b)
138 {
139 if (a.m==0)
140 return b.m<0;
141 else if (b.m==0)
142 return a.m>0;
143 if ((a).e > (b).e)
144 return ((a).m>>1) < ((b).m>>MIN(15,(a).e-(b).e+1));
145 else
146 return ((b).m>>1) > ((a).m>>MIN(15,(b).e-(a).e+1));
147
148 }
149
FLOAT_GT(spx_float_t a,spx_float_t b)150 static inline int FLOAT_GT(spx_float_t a, spx_float_t b)
151 {
152 return FLOAT_LT(b,a);
153 }
154
FLOAT_MULT(spx_float_t a,spx_float_t b)155 static inline spx_float_t FLOAT_MULT(spx_float_t a, spx_float_t b)
156 {
157 spx_float_t r = (spx_float_t) {(spx_int16_t)((spx_int32_t)(a).m*(b).m>>15), (a).e+(b).e+15};
158 if (r.m>0)
159 {
160 if (r.m<16384)
161 {
162 r.m<<=1;
163 r.e-=1;
164 }
165 } else {
166 if (r.m>-16384)
167 {
168 r.m<<=1;
169 r.e-=1;
170 }
171 }
172 /*printf ("%f * %f = %f\n", REALFLOAT(a), REALFLOAT(b), REALFLOAT(r));*/
173 return r;
174 }
175
FLOAT_SHR(spx_float_t a,int b)176 static inline spx_float_t FLOAT_SHR(spx_float_t a, int b)
177 {
178 return (spx_float_t) {a.m,a.e-b};
179 }
180
FLOAT_SHL(spx_float_t a,int b)181 static inline spx_float_t FLOAT_SHL(spx_float_t a, int b)
182 {
183 return (spx_float_t) {a.m,a.e+b};
184 }
185
FLOAT_EXTRACT16(spx_float_t a)186 static inline spx_int16_t FLOAT_EXTRACT16(spx_float_t a)
187 {
188 if (a.e<0)
189 return (a.m+(1<<(-a.e-1)))>>-a.e;
190 else
191 return a.m<<a.e;
192 }
193
FLOAT_EXTRACT32(spx_float_t a)194 static inline spx_int32_t FLOAT_EXTRACT32(spx_float_t a)
195 {
196 if (a.e<0)
197 return ((spx_int32_t)a.m+(1<<(-a.e-1)))>>-a.e;
198 else
199 return ((spx_int32_t)a.m)<<a.e;
200 }
201
FLOAT_MUL32(spx_float_t a,spx_word32_t b)202 static inline spx_int32_t FLOAT_MUL32(spx_float_t a, spx_word32_t b)
203 {
204 if (a.e<-15)
205 return SHR32(MULT16_32_Q15(a.m, b),-a.e-15);
206 else
207 return SHL32(MULT16_32_Q15(a.m, b),15+a.e);
208 }
209
FLOAT_MUL32U(spx_word32_t a,spx_word32_t b)210 static inline spx_float_t FLOAT_MUL32U(spx_word32_t a, spx_word32_t b)
211 {
212 int e=0;
213 /* FIXME: Handle the sign */
214 if (a==0)
215 return (spx_float_t) {0,0};
216 while (a>32767)
217 {
218 a >>= 1;
219 e++;
220 }
221 while (a<16384)
222 {
223 a <<= 1;
224 e--;
225 }
226 while (b>32767)
227 {
228 b >>= 1;
229 e++;
230 }
231 while (b<16384)
232 {
233 b <<= 1;
234 e--;
235 }
236 return (spx_float_t) {MULT16_16_Q15(a,b),e+15};
237 }
238
FLOAT_DIV32_FLOAT(spx_word32_t a,spx_float_t b)239 static inline spx_float_t FLOAT_DIV32_FLOAT(spx_word32_t a, spx_float_t b)
240 {
241 int e=0;
242 /* FIXME: Handle the sign */
243 if (a==0)
244 return (spx_float_t) {0,0};
245 while (a<SHL32(b.m,14))
246 {
247 a <<= 1;
248 e--;
249 }
250 while (a>=SHL32(b.m-1,15))
251 {
252 a >>= 1;
253 e++;
254 }
255 return (spx_float_t) {DIV32_16(a,b.m),e-b.e};
256 }
257
258
FLOAT_DIV32(spx_word32_t a,spx_word32_t b)259 static inline spx_float_t FLOAT_DIV32(spx_word32_t a, spx_word32_t b)
260 {
261 int e=0;
262 /* FIXME: Handle the sign */
263 if (a==0)
264 return (spx_float_t) {0,0};
265 while (b>32767)
266 {
267 b >>= 1;
268 e--;
269 }
270 while (a<SHL32(b,14))
271 {
272 a <<= 1;
273 e--;
274 }
275 while (a>=SHL32(b-1,15))
276 {
277 a >>= 1;
278 e++;
279 }
280 return (spx_float_t) {DIV32_16(a,b),e};
281 }
282
FLOAT_DIVU(spx_float_t a,spx_float_t b)283 static inline spx_float_t FLOAT_DIVU(spx_float_t a, spx_float_t b)
284 {
285 int e=0;
286 spx_int32_t num;
287 num = a.m;
288 while (a.m >= b.m)
289 {
290 e++;
291 a.m >>= 1;
292 }
293 num = num << (15-e);
294 return (spx_float_t) {DIV32_16(num,b.m),a.e-b.e-15+e};
295 }
296
297 #else
298
299 #define spx_float_t float
300 #define FLOAT_ZERO 0.f
301 #define FLOAT_ONE 1.f
302 #define FLOAT_HALF 0.5f
303 #define PSEUDOFLOAT(x) (x)
304 #define FLOAT_MULT(a,b) ((a)*(b))
305 #define FLOAT_MUL32(a,b) ((a)*(b))
306 #define FLOAT_DIV32(a,b) ((a)/(b))
307 #define FLOAT_EXTRACT16(a) (a)
308 #define FLOAT_ADD(a,b) ((a)+(b))
309 #define FLOAT_SUB(a,b) ((a)-(b))
310 #define REALFLOAT(x) (x)
311 #define FLOAT_DIV32_FLOAT(a,b) ((a)/(b))
312 #define FLOAT_MUL32U(a,b) ((a)*(b))
313 #define FLOAT_SHL(a,b) (a)
314 #define FLOAT_LT(a,b) ((a)<(b))
315 #define FLOAT_GT(a,b) ((a)>(b))
316 #define FLOAT_DIVU(a,b) ((a)/(b))
317
318 #endif
319
320 #endif
321