1 | #ifndef _FIXEDPTC_H_
|
2 | #define _FIXEDPTC_H_
|
3 |
|
4 | /*
|
5 | * fixedptc.h is a 32-bit or 64-bit fixed point numeric library.
|
6 | *
|
7 | * The symbol FIXEDPT_BITS, if defined before this library header file
|
8 | * is included, governs the number of bits in the data type (its "width").
|
9 | * The default width is 32-bit (FIXEDPT_BITS=32) and it can be used
|
10 | * on any recent C99 compiler. The 64-bit precision (FIXEDPT_BITS=64) is
|
11 | * available on compilers which implement 128-bit "long long" types. This
|
12 | * precision has been tested on GCC 4.2+.
|
13 | *
|
14 | * Since the precision in both cases is relatively low, many complex
|
15 | * functions (more complex than div & mul) take a large hit on the precision
|
16 | * of the end result because errors in precision accumulate.
|
17 | * This loss of precision can be lessened by increasing the number of
|
18 | * bits dedicated to the fraction part, but at the loss of range.
|
19 | *
|
20 | * Adventurous users might utilize this library to build two data types:
|
21 | * one which has the range, and one which has the precision, and carefully
|
22 | * convert between them (including adding two number of each type to produce
|
23 | * a simulated type with a larger range and precision).
|
24 | *
|
25 | * The ideas and algorithms have been cherry-picked from a large number
|
26 | * of previous implementations available on the Internet.
|
27 | * Tim Hartrick has contributed cleanup and 64-bit support patches.
|
28 | *
|
29 | * == Special notes for the 32-bit precision ==
|
30 | * Signed 32-bit fixed point numeric library for the 24.8 format.
|
31 | * The specific limits are -8388608.999... to 8388607.999... and the
|
32 | * most precise number is 0.00390625. In practice, you should not count
|
33 | * on working with numbers larger than a million or to the precision
|
34 | * of more than 2 decimal places. Make peace with the fact that PI
|
35 | * is 3.14 here. :)
|
36 | */
|
37 |
|
38 | /*-
|
39 | * Copyright (c) 2010-2012 Ivan Voras <ivoras@freebsd.org>
|
40 | * Copyright (c) 2012 Tim Hartrick <tim@edgecast.com>
|
41 | *
|
42 | * Redistribution and use in source and binary forms, with or without
|
43 | * modification, are permitted provided that the following conditions
|
44 | * are met:
|
45 | * 1. Redistributions of source code must retain the above copyright
|
46 | * notice, this list of conditions and the following disclaimer.
|
47 | * 2. Redistributions in binary form must reproduce the above copyright
|
48 | * notice, this list of conditions and the following disclaimer in the
|
49 | * documentation and/or other materials provided with the distribution.
|
50 | *
|
51 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
52 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
53 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
54 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
55 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
56 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
57 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
58 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
59 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
60 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
61 | * SUCH DAMAGE.
|
62 | */
|
63 |
|
64 | #ifndef FIXEDPT_BITS
|
65 | #define FIXEDPT_BITS 32
|
66 | #endif
|
67 |
|
68 | #if FIXEDPT_BITS == 32
|
69 | typedef int32_t fixedpt;
|
70 | typedef int64_t fixedptd;
|
71 | typedef uint32_t fixedptu;
|
72 | typedef uint64_t fixedptud;
|
73 | #elif FIXEDPT_BITS == 64
|
74 | typedef int64_t fixedpt;
|
75 | typedef __int128_t fixedptd;
|
76 | typedef uint64_t fixedptu;
|
77 | typedef __uint128_t fixedptud;
|
78 | #else
|
79 | #error "FIXEDPT_BITS must be equal to 32 or 64"
|
80 | #endif
|
81 |
|
82 | #ifndef FIXEDPT_WBITS
|
83 | #define FIXEDPT_WBITS 24
|
84 | #endif
|
85 |
|
86 | #if FIXEDPT_WBITS >= FIXEDPT_BITS
|
87 | #error "FIXEDPT_WBITS must be less than or equal to FIXEDPT_BITS"
|
88 | #endif
|
89 |
|
90 | #define FIXEDPT_VCSID "$Id: fixedptc.h,v 00c74d842389 2012/07/17 23:30:18 ivoras $"
|
91 |
|
92 | #define FIXEDPT_FBITS (FIXEDPT_BITS - FIXEDPT_WBITS)
|
93 | #define FIXEDPT_FMASK (((fixedpt)1 << FIXEDPT_FBITS) - 1)
|
94 |
|
95 | #define fixedpt_rconst(R) ((fixedpt)((R) * (((fixedptd)1 << FIXEDPT_FBITS) \
|
96 | + ((R) >= 0 ? 0.5 : -0.5))))
|
97 | #define fixedpt_fromint(I) ((fixedptd)(I) << FIXEDPT_FBITS)
|
98 | #define fixedpt_toint(F) ((F) >> FIXEDPT_FBITS)
|
99 | #define fixedpt_add(A,B) ((A) + (B))
|
100 | #define fixedpt_sub(A,B) ((A) - (B))
|
101 | #define fixedpt_xmul(A,B) \
|
102 | ((fixedpt)(((fixedptd)(A) * (fixedptd)(B)) >> FIXEDPT_FBITS))
|
103 | #define fixedpt_xdiv(A,B) \
|
104 | ((fixedpt)(((fixedptd)(A) << FIXEDPT_FBITS) / (fixedptd)(B)))
|
105 | #define fixedpt_fracpart(A) ((fixedpt)(A) & FIXEDPT_FMASK)
|
106 |
|
107 | #define FIXEDPT_ONE ((fixedpt)((fixedpt)1 << FIXEDPT_FBITS))
|
108 | #define FIXEDPT_ONE_HALF (FIXEDPT_ONE >> 1)
|
109 | #define FIXEDPT_TWO (FIXEDPT_ONE + FIXEDPT_ONE)
|
110 | #define FIXEDPT_PI fixedpt_rconst(3.14159265358979323846)
|
111 | #define FIXEDPT_TWO_PI fixedpt_rconst(2 * 3.14159265358979323846)
|
112 | #define FIXEDPT_HALF_PI fixedpt_rconst(3.14159265358979323846 / 2)
|
113 | #define FIXEDPT_E fixedpt_rconst(2.7182818284590452354)
|
114 |
|
115 | #define fixedpt_abs(A) ((A) < 0 ? -(A) : (A))
|
116 |
|
117 |
|
118 | /* Multiplies two fixedpt numbers, returns the result. */
|
119 | static inline fixedpt
|
120 | fixedpt_mul(fixedpt A, fixedpt B)
|
121 | {
|
122 | return (((fixedptd)A * (fixedptd)B) >> FIXEDPT_FBITS);
|
123 | }
|
124 |
|
125 |
|
126 | /* Divides two fixedpt numbers, returns the result. */
|
127 | static inline fixedpt
|
128 | fixedpt_div(fixedpt A, fixedpt B)
|
129 | {
|
130 | return (((fixedptd)A << FIXEDPT_FBITS) / (fixedptd)B);
|
131 | }
|
132 |
|
133 | /*
|
134 | * Note: adding and substracting fixedpt numbers can be done by using
|
135 | * the regular integer operators + and -.
|
136 | */
|
137 |
|
138 | /**
|
139 | * Convert the given fixedpt number to a decimal string.
|
140 | * The max_dec argument specifies how many decimal digits to the right
|
141 | * of the decimal point to generate. If set to -1, the "default" number
|
142 | * of decimal digits will be used (2 for 32-bit fixedpt width, 10 for
|
143 | * 64-bit fixedpt width); If set to -2, "all" of the digits will
|
144 | * be returned, meaning there will be invalid, bogus digits outside the
|
145 | * specified precisions.
|
146 | */
|
147 | static inline void
|
148 | fixedpt_str(fixedpt A, char *str, int max_dec)
|
149 | {
|
150 | int ndec = 0, slen = 0;
|
151 | char tmp[12] = {0};
|
152 | fixedptud fr, ip;
|
153 | const fixedptud one = (fixedptud)1 << FIXEDPT_BITS;
|
154 | const fixedptud mask = one - 1;
|
155 |
|
156 | if (max_dec == -1)
|
157 | #if FIXEDPT_BITS == 32
|
158 | max_dec = 2;
|
159 | #elif FIXEDPT_BITS == 64
|
160 | max_dec = 10;
|
161 | #else
|
162 | #error Invalid width
|
163 | #endif
|
164 | else if (max_dec == -2)
|
165 | max_dec = 15;
|
166 |
|
167 | if (A < 0) {
|
168 | str[slen++] = '-';
|
169 | A *= -1;
|
170 | }
|
171 |
|
172 | ip = fixedpt_toint(A);
|
173 | do {
|
174 | tmp[ndec++] = '0' + ip % 10;
|
175 | ip /= 10;
|
176 | } while (ip != 0);
|
177 |
|
178 | while (ndec > 0)
|
179 | str[slen++] = tmp[--ndec];
|
180 | str[slen++] = '.';
|
181 |
|
182 | fr = (fixedpt_fracpart(A) << FIXEDPT_WBITS) & mask;
|
183 | do {
|
184 | fr = (fr & mask) * 10;
|
185 |
|
186 | str[slen++] = '0' + (fr >> FIXEDPT_BITS) % 10;
|
187 | ndec++;
|
188 | } while (fr != 0 && ndec < max_dec);
|
189 |
|
190 | if (ndec > 1 && str[slen-1] == '0')
|
191 | str[slen-1] = '\0'; /* cut off trailing 0 */
|
192 | else
|
193 | str[slen] = '\0';
|
194 | }
|
195 |
|
196 | /* Converts the given fixedpt number into a string, using a static
|
197 | * (non-threadsafe) string buffer */
|
198 | static inline char*
|
199 | fixedpt_cstr(const fixedpt A, const int max_dec)
|
200 | {
|
201 | static char str[25];
|
202 |
|
203 | fixedpt_str(A, str, max_dec);
|
204 | return (str);
|
205 | }
|
206 |
|
207 |
|
208 | /* Returns the square root of the given number, or -1 in case of error */
|
209 | static inline fixedpt
|
210 | fixedpt_sqrt(fixedpt A)
|
211 | {
|
212 | int invert = 0;
|
213 | int iter = FIXEDPT_FBITS;
|
214 | int l, i;
|
215 |
|
216 | if (A < 0)
|
217 | return (-1);
|
218 | if (A == 0 || A == FIXEDPT_ONE)
|
219 | return (A);
|
220 | if (A < FIXEDPT_ONE && A > 6) {
|
221 | invert = 1;
|
222 | A = fixedpt_div(FIXEDPT_ONE, A);
|
223 | }
|
224 | if (A > FIXEDPT_ONE) {
|
225 | int s = A;
|
226 |
|
227 | iter = 0;
|
228 | while (s > 0) {
|
229 | s >>= 2;
|
230 | iter++;
|
231 | }
|
232 | }
|
233 |
|
234 | /* Newton's iterations */
|
235 | l = (A >> 1) + 1;
|
236 | for (i = 0; i < iter; i++)
|
237 | l = (l + fixedpt_div(A, l)) >> 1;
|
238 | if (invert)
|
239 | return (fixedpt_div(FIXEDPT_ONE, l));
|
240 | return (l);
|
241 | }
|
242 |
|
243 |
|
244 | /* Returns the sine of the given fixedpt number.
|
245 | * Note: the loss of precision is extraordinary! */
|
246 | static inline fixedpt
|
247 | fixedpt_sin(fixedpt fp)
|
248 | {
|
249 | int sign = 1;
|
250 | fixedpt sqr, result;
|
251 | const fixedpt SK[2] = {
|
252 | fixedpt_rconst(7.61e-03),
|
253 | fixedpt_rconst(1.6605e-01)
|
254 | };
|
255 |
|
256 | fp %= 2 * FIXEDPT_PI;
|
257 | if (fp < 0)
|
258 | fp = FIXEDPT_PI * 2 + fp;
|
259 | if ((fp > FIXEDPT_HALF_PI) && (fp <= FIXEDPT_PI))
|
260 | fp = FIXEDPT_PI - fp;
|
261 | else if ((fp > FIXEDPT_PI) && (fp <= (FIXEDPT_PI + FIXEDPT_HALF_PI))) {
|
262 | fp = fp - FIXEDPT_PI;
|
263 | sign = -1;
|
264 | } else if (fp > (FIXEDPT_PI + FIXEDPT_HALF_PI)) {
|
265 | fp = (FIXEDPT_PI << 1) - fp;
|
266 | sign = -1;
|
267 | }
|
268 | sqr = fixedpt_mul(fp, fp);
|
269 | result = SK[0];
|
270 | result = fixedpt_mul(result, sqr);
|
271 | result -= SK[1];
|
272 | result = fixedpt_mul(result, sqr);
|
273 | result += FIXEDPT_ONE;
|
274 | result = fixedpt_mul(result, fp);
|
275 | return sign * result;
|
276 | }
|
277 |
|
278 |
|
279 | /* Returns the cosine of the given fixedpt number */
|
280 | static inline fixedpt
|
281 | fixedpt_cos(fixedpt A)
|
282 | {
|
283 | return (fixedpt_sin(FIXEDPT_HALF_PI - A));
|
284 | }
|
285 |
|
286 |
|
287 | /* Returns the tangens of the given fixedpt number */
|
288 | static inline fixedpt
|
289 | fixedpt_tan(fixedpt A)
|
290 | {
|
291 | return fixedpt_div(fixedpt_sin(A), fixedpt_cos(A));
|
292 | }
|
293 |
|
294 |
|
295 | /* Returns the value exp(x), i.e. e^x of the given fixedpt number. */
|
296 | static inline fixedpt
|
297 | fixedpt_exp(fixedpt fp)
|
298 | {
|
299 | fixedpt xabs, k, z, R, xp;
|
300 | const fixedpt LN2 = fixedpt_rconst(0.69314718055994530942);
|
301 | const fixedpt LN2_INV = fixedpt_rconst(1.4426950408889634074);
|
302 | const fixedpt EXP_P[5] = {
|
303 | fixedpt_rconst(1.66666666666666019037e-01),
|
304 | fixedpt_rconst(-2.77777777770155933842e-03),
|
305 | fixedpt_rconst(6.61375632143793436117e-05),
|
306 | fixedpt_rconst(-1.65339022054652515390e-06),
|
307 | fixedpt_rconst(4.13813679705723846039e-08),
|
308 | };
|
309 |
|
310 | if (fp == 0)
|
311 | return (FIXEDPT_ONE);
|
312 | xabs = fixedpt_abs(fp);
|
313 | k = fixedpt_mul(xabs, LN2_INV);
|
314 | k += FIXEDPT_ONE_HALF;
|
315 | k &= ~FIXEDPT_FMASK;
|
316 | if (fp < 0)
|
317 | k = -k;
|
318 | fp -= fixedpt_mul(k, LN2);
|
319 | z = fixedpt_mul(fp, fp);
|
320 | /* Taylor */
|
321 | R = FIXEDPT_TWO +
|
322 | fixedpt_mul(z, EXP_P[0] + fixedpt_mul(z, EXP_P[1] +
|
323 | fixedpt_mul(z, EXP_P[2] + fixedpt_mul(z, EXP_P[3] +
|
324 | fixedpt_mul(z, EXP_P[4])))));
|
325 | xp = FIXEDPT_ONE + fixedpt_div(fixedpt_mul(fp, FIXEDPT_TWO), R - fp);
|
326 | if (k < 0)
|
327 | k = FIXEDPT_ONE >> (-k >> FIXEDPT_FBITS);
|
328 | else
|
329 | k = FIXEDPT_ONE << (k >> FIXEDPT_FBITS);
|
330 | return (fixedpt_mul(k, xp));
|
331 | }
|
332 |
|
333 |
|
334 | /* Returns the natural logarithm of the given fixedpt number. */
|
335 | static inline fixedpt
|
336 | fixedpt_ln(fixedpt x)
|
337 | {
|
338 | fixedpt log2, xi;
|
339 | fixedpt f, s, z, w, R;
|
340 | const fixedpt LN2 = fixedpt_rconst(0.69314718055994530942);
|
341 | const fixedpt LG[7] = {
|
342 | fixedpt_rconst(6.666666666666735130e-01),
|
343 | fixedpt_rconst(3.999999999940941908e-01),
|
344 | fixedpt_rconst(2.857142874366239149e-01),
|
345 | fixedpt_rconst(2.222219843214978396e-01),
|
346 | fixedpt_rconst(1.818357216161805012e-01),
|
347 | fixedpt_rconst(1.531383769920937332e-01),
|
348 | fixedpt_rconst(1.479819860511658591e-01)
|
349 | };
|
350 |
|
351 | if (x < 0)
|
352 | return (0);
|
353 | if (x == 0)
|
354 | return 0xffffffff;
|
355 |
|
356 | log2 = 0;
|
357 | xi = x;
|
358 | while (xi > FIXEDPT_TWO) {
|
359 | xi >>= 1;
|
360 | log2++;
|
361 | }
|
362 | f = xi - FIXEDPT_ONE;
|
363 | s = fixedpt_div(f, FIXEDPT_TWO + f);
|
364 | z = fixedpt_mul(s, s);
|
365 | w = fixedpt_mul(z, z);
|
366 | R = fixedpt_mul(w, LG[1] + fixedpt_mul(w, LG[3]
|
367 | + fixedpt_mul(w, LG[5]))) + fixedpt_mul(z, LG[0]
|
368 | + fixedpt_mul(w, LG[2] + fixedpt_mul(w, LG[4]
|
369 | + fixedpt_mul(w, LG[6]))));
|
370 | return (fixedpt_mul(LN2, (log2 << FIXEDPT_FBITS)) + f
|
371 | - fixedpt_mul(s, f - R));
|
372 | }
|
373 |
|
374 |
|
375 | /* Returns the logarithm of the given base of the given fixedpt number */
|
376 | static inline fixedpt
|
377 | fixedpt_log(fixedpt x, fixedpt base)
|
378 | {
|
379 | return (fixedpt_div(fixedpt_ln(x), fixedpt_ln(base)));
|
380 | }
|
381 |
|
382 |
|
383 | /* Return the power value (n^exp) of the given fixedpt numbers */
|
384 | static inline fixedpt
|
385 | fixedpt_pow(fixedpt n, fixedpt exp)
|
386 | {
|
387 | if (exp == 0)
|
388 | return (FIXEDPT_ONE);
|
389 | if (n < 0)
|
390 | return 0;
|
391 | return (fixedpt_exp(fixedpt_mul(fixedpt_ln(n), exp)));
|
392 | }
|
393 |
|
394 | #endif
|