blob: a6c476284154d8fc020e251da715dc959d0c66a0 [file] [log] [blame]
Benny Prijonoef010c52007-03-30 10:49:46 +00001/* Copyright (C) 2005 Jean-Marc Valin */
2/**
3 @file pseudofloat.h
4 @brief Pseudo-floating point
5 * This header file provides a lightweight floating point type for
6 * use on fixed-point platforms when a large dynamic range is
7 * required. The new type is not compatible with the 32-bit IEEE format,
8 * it is not even remotely as accurate as 32-bit floats, and is not
9 * even guaranteed to produce even remotely correct results for code
10 * other than Speex. It makes all kinds of shortcuts that are acceptable
11 * for Speex, but may not be acceptable for your application. You're
12 * quite welcome to reuse this code and improve it, but don't assume
13 * it works out of the box. Most likely, it doesn't.
14 */
15/*
16 Redistribution and use in source and binary forms, with or without
17 modification, are permitted provided that the following conditions
18 are met:
19
20 - Redistributions of source code must retain the above copyright
21 notice, this list of conditions and the following disclaimer.
22
23 - Redistributions in binary form must reproduce the above copyright
24 notice, this list of conditions and the following disclaimer in the
25 documentation and/or other materials provided with the distribution.
26
27 - Neither the name of the Xiph.org Foundation nor the names of its
28 contributors may be used to endorse or promote products derived from
29 this software without specific prior written permission.
30
31 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32 ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
34 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
35 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
36 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
37 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
38 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
39 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
40 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
41 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
42*/
43
44#ifndef PSEUDOFLOAT_H
45#define PSEUDOFLOAT_H
46
47#include "misc.h"
48#include "math_approx.h"
49#include <math.h>
50
51#ifdef FIXED_POINT
52
53typedef struct {
54 spx_int16_t m;
55 spx_int16_t e;
56} spx_float_t;
57
58static const spx_float_t FLOAT_ZERO = {0,0};
59static const spx_float_t FLOAT_ONE = {16384,-14};
60static const spx_float_t FLOAT_HALF = {16384,-15};
61
62#define MIN(a,b) ((a)<(b)?(a):(b))
63static inline spx_float_t PSEUDOFLOAT(spx_int32_t x)
64{
65 int e=0;
66 int sign=0;
67 if (x<0)
68 {
69 sign = 1;
70 x = -x;
71 }
72 if (x==0)
73 {
74 spx_float_t r = {0,0};
75 return r;
76 }
77 e = spx_ilog2(ABS32(x))-14;
78 x = VSHR32(x, e);
79 if (sign)
80 {
81 spx_float_t r;
82 r.m = -x;
83 r.e = e;
84 return r;
85 }
86 else
87 {
88 spx_float_t r;
89 r.m = x;
90 r.e = e;
91 return r;
92 }
93}
94
95
96static inline spx_float_t FLOAT_ADD(spx_float_t a, spx_float_t b)
97{
98 spx_float_t r;
99 if (a.m==0)
100 return b;
101 else if (b.m==0)
102 return a;
103 if ((a).e > (b).e)
104 {
105 r.m = ((a).m>>1) + ((b).m>>MIN(15,(a).e-(b).e+1));
106 r.e = (a).e+1;
107 }
108 else
109 {
110 r.m = ((b).m>>1) + ((a).m>>MIN(15,(b).e-(a).e+1));
111 r.e = (b).e+1;
112 }
113 if (r.m>0)
114 {
115 if (r.m<16384)
116 {
117 r.m<<=1;
118 r.e-=1;
119 }
120 } else {
121 if (r.m>-16384)
122 {
123 r.m<<=1;
124 r.e-=1;
125 }
126 }
127 /*printf ("%f + %f = %f\n", REALFLOAT(a), REALFLOAT(b), REALFLOAT(r));*/
128 return r;
129}
130
131static inline spx_float_t FLOAT_SUB(spx_float_t a, spx_float_t b)
132{
133 spx_float_t r;
134 if (a.m==0)
135 return b;
136 else if (b.m==0)
137 return a;
138 if ((a).e > (b).e)
139 {
140 r.m = ((a).m>>1) - ((b).m>>MIN(15,(a).e-(b).e+1));
141 r.e = (a).e+1;
142 }
143 else
144 {
145 r.m = ((a).m>>MIN(15,(b).e-(a).e+1)) - ((b).m>>1);
146 r.e = (b).e+1;
147 }
148 if (r.m>0)
149 {
150 if (r.m<16384)
151 {
152 r.m<<=1;
153 r.e-=1;
154 }
155 } else {
156 if (r.m>-16384)
157 {
158 r.m<<=1;
159 r.e-=1;
160 }
161 }
162 /*printf ("%f + %f = %f\n", REALFLOAT(a), REALFLOAT(b), REALFLOAT(r));*/
163 return r;
164}
165
166static inline int FLOAT_LT(spx_float_t a, spx_float_t b)
167{
168 if (a.m==0)
169 return b.m>0;
170 else if (b.m==0)
171 return a.m<0;
172 if ((a).e > (b).e)
173 return ((a).m>>1) < ((b).m>>MIN(15,(a).e-(b).e+1));
174 else
175 return ((b).m>>1) > ((a).m>>MIN(15,(b).e-(a).e+1));
176
177}
178
179static inline int FLOAT_GT(spx_float_t a, spx_float_t b)
180{
181 return FLOAT_LT(b,a);
182}
183
184static inline spx_float_t FLOAT_MULT(spx_float_t a, spx_float_t b)
185{
186 spx_float_t r;
187 r.m = (spx_int16_t)((spx_int32_t)(a).m*(b).m>>15);
188 r.e = (a).e+(b).e+15;
189 if (r.m>0)
190 {
191 if (r.m<16384)
192 {
193 r.m<<=1;
194 r.e-=1;
195 }
196 } else {
197 if (r.m>-16384)
198 {
199 r.m<<=1;
200 r.e-=1;
201 }
202 }
203 /*printf ("%f * %f = %f\n", REALFLOAT(a), REALFLOAT(b), REALFLOAT(r));*/
204 return r;
205}
206
207static inline spx_float_t FLOAT_AMULT(spx_float_t a, spx_float_t b)
208{
209 spx_float_t r;
210 r.m = (spx_int16_t)((spx_int32_t)(a).m*(b).m>>15);
211 r.e = (a).e+(b).e+15;
212 return r;
213}
214
215
216static inline spx_float_t FLOAT_SHL(spx_float_t a, int b)
217{
218 spx_float_t r;
219 r.m = a.m;
220 r.e = a.e+b;
221 return r;
222}
223
224static inline spx_int16_t FLOAT_EXTRACT16(spx_float_t a)
225{
226 if (a.e<0)
227 return EXTRACT16((EXTEND32(a.m)+(EXTEND32(1)<<(-a.e-1)))>>-a.e);
228 else
229 return a.m<<a.e;
230}
231
232static inline spx_int32_t FLOAT_EXTRACT32(spx_float_t a)
233{
234 if (a.e<0)
235 return (EXTEND32(a.m)+(EXTEND32(1)<<(-a.e-1)))>>-a.e;
236 else
237 return EXTEND32(a.m)<<a.e;
238}
239
240static inline spx_int32_t FLOAT_MUL32(spx_float_t a, spx_word32_t b)
241{
242 return VSHR32(MULT16_32_Q15(a.m, b),-a.e-15);
243}
244
245static inline spx_float_t FLOAT_MUL32U(spx_word32_t a, spx_word32_t b)
246{
247 int e1, e2;
248 spx_float_t r;
249 if (a==0 || b==0)
250 {
251 return FLOAT_ZERO;
252 }
253 e1 = spx_ilog2(ABS32(a));
254 a = VSHR32(a, e1-14);
255 e2 = spx_ilog2(ABS32(b));
256 b = VSHR32(b, e2-14);
257 r.m = MULT16_16_Q15(a,b);
258 r.e = e1+e2-13;
259 return r;
260}
261
262/* Do NOT attempt to divide by a negative number */
263static inline spx_float_t FLOAT_DIV32_FLOAT(spx_word32_t a, spx_float_t b)
264{
265 int e=0;
266 spx_float_t r;
267 if (a==0)
268 {
269 return FLOAT_ZERO;
270 }
271 e = spx_ilog2(ABS32(a))-spx_ilog2(b.m-1)-15;
272 a = VSHR32(a, e);
273 if (ABS32(a)>=SHL32(EXTEND32(b.m-1),15))
274 {
275 a >>= 1;
276 e++;
277 }
278 r.m = DIV32_16(a,b.m);
279 r.e = e-b.e;
280 return r;
281}
282
283
284/* Do NOT attempt to divide by a negative number */
285static inline spx_float_t FLOAT_DIV32(spx_word32_t a, spx_word32_t b)
286{
287 int e0=0,e=0;
288 spx_float_t r;
289 if (a==0)
290 {
291 return FLOAT_ZERO;
292 }
293 if (b>32767)
294 {
295 e0 = spx_ilog2(b)-14;
296 b = VSHR32(b, e0);
297 e0 = -e0;
298 }
299 e = spx_ilog2(ABS32(a))-spx_ilog2(b-1)-15;
300 a = VSHR32(a, e);
301 if (ABS32(a)>=SHL32(EXTEND32(b-1),15))
302 {
303 a >>= 1;
304 e++;
305 }
306 e += e0;
307 r.m = DIV32_16(a,b);
308 r.e = e;
309 return r;
310}
311
312/* Do NOT attempt to divide by a negative number */
313static inline spx_float_t FLOAT_DIVU(spx_float_t a, spx_float_t b)
314{
315 int e=0;
316 spx_int32_t num;
317 spx_float_t r;
318 if (b.m<=0)
319 {
320 speex_warning_int("Attempted to divide by", b.m);
321 return FLOAT_ONE;
322 }
323 num = a.m;
324 a.m = ABS16(a.m);
325 while (a.m >= b.m)
326 {
327 e++;
328 a.m >>= 1;
329 }
330 num = num << (15-e);
331 r.m = DIV32_16(num,b.m);
332 r.e = a.e-b.e-15+e;
333 return r;
334}
335
336static inline spx_float_t FLOAT_SQRT(spx_float_t a)
337{
338 spx_float_t r;
339 spx_int32_t m;
340 m = SHL32(EXTEND32(a.m), 14);
341 r.e = a.e - 14;
342 if (r.e & 1)
343 {
344 r.e -= 1;
345 m <<= 1;
346 }
347 r.e >>= 1;
348 r.m = spx_sqrt(m);
349 return r;
350}
351
352#else
353
354#define spx_float_t float
355#define FLOAT_ZERO 0.f
356#define FLOAT_ONE 1.f
357#define FLOAT_HALF 0.5f
358#define PSEUDOFLOAT(x) (x)
359#define FLOAT_MULT(a,b) ((a)*(b))
360#define FLOAT_AMULT(a,b) ((a)*(b))
361#define FLOAT_MUL32(a,b) ((a)*(b))
362#define FLOAT_DIV32(a,b) ((a)/(b))
363#define FLOAT_EXTRACT16(a) (a)
364#define FLOAT_EXTRACT32(a) (a)
365#define FLOAT_ADD(a,b) ((a)+(b))
366#define FLOAT_SUB(a,b) ((a)-(b))
367#define REALFLOAT(x) (x)
368#define FLOAT_DIV32_FLOAT(a,b) ((a)/(b))
369#define FLOAT_MUL32U(a,b) ((a)*(b))
370#define FLOAT_SHL(a,b) (a)
371#define FLOAT_LT(a,b) ((a)<(b))
372#define FLOAT_GT(a,b) ((a)>(b))
373#define FLOAT_DIVU(a,b) ((a)/(b))
374#define FLOAT_SQRT(a) (spx_sqrt(a))
375
376#endif
377
378#endif