1 /* EINA - EFL data type library
2 * Copyright (C) 2007-2009 Jorge Luis Zapata Muga, Cedric BAIL
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library;
16 * if not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #ifndef EINA_INLINE_F32P32_X_
20 # define EINA_INLINE_F32P32_X_
21
22 #include <stdlib.h>
23
24 static inline Eina_F32p32
eina_f32p32_add(Eina_F32p32 a,Eina_F32p32 b)25 eina_f32p32_add(Eina_F32p32 a, Eina_F32p32 b)
26 {
27 return a + b;
28 }
29
30 static inline Eina_F32p32
eina_f32p32_sub(Eina_F32p32 a,Eina_F32p32 b)31 eina_f32p32_sub(Eina_F32p32 a, Eina_F32p32 b)
32 {
33 return a - b;
34 }
35
36 static inline Eina_F32p32
eina_f32p32_mul(Eina_F32p32 a,Eina_F32p32 b)37 eina_f32p32_mul(Eina_F32p32 a, Eina_F32p32 b)
38 {
39 /* To prevent overflow during multiplication
40 * we need to reduce the precision of the fraction part
41 * Shift both values to only contain 16 bit of the fraction part
42 * (rounded).
43 * After multiplication we again have a value with a 32-bit
44 * fraction part. See also
45 * http://en.wikipedia.org/wiki/Fixed-point_arithmetic#Operations
46 */
47
48 Eina_F32p32 up;
49 Eina_F32p32 result;
50 uint64_t as, bs;
51 Eina_F32p32 sign;
52
53 sign = a ^ b;
54 as = eina_fp32p32_llabs(a);
55 bs = eina_fp32p32_llabs(b);
56
57 /* Reduce fraction to 16-bit (rounded) */
58 as = (as >> 16) + ((as >> 15) & 0x1);
59 bs = (bs >> 16) + ((bs >> 15) & 0x1);
60
61 up = as * bs;
62
63 result = up;
64
65 return sign < 0 ? - result : result;
66 }
67
68 static inline Eina_F32p32
eina_f32p32_scale(Eina_F32p32 a,int b)69 eina_f32p32_scale(Eina_F32p32 a, int b)
70 {
71 return a * b;
72 }
73
74 static inline Eina_F32p32
eina_f32p32_div(Eina_F32p32 a,Eina_F32p32 b)75 eina_f32p32_div(Eina_F32p32 a, Eina_F32p32 b)
76 {
77 Eina_F32p32 sign;
78 Eina_F32p32 result;
79
80 sign = a ^ b;
81
82 /* FIXME: This should probably map to +/-inf when converting to double
83 or we should abort... */
84 if (b == 0)
85 return sign < 0 ? (Eina_F32p32) 0x8000000000000000ull : (Eina_F32p32) 0x7FFFFFFFFFFFFFFFull;
86
87 result = (eina_f32p32_mul(eina_fp32p32_llabs(a), (((uint64_t) 1 << 62) / ((uint64_t)(eina_fp32p32_llabs(b)) >> 2))));
88
89 return sign < 0 ? - result : result;
90 }
91
92 static inline Eina_F32p32
eina_f32p32_sqrt(Eina_F32p32 a)93 eina_f32p32_sqrt(Eina_F32p32 a)
94 {
95 uint64_t root, remHi, remLo, testDiv, count;
96
97 root = 0; /* Clear root */
98 remHi = 0; /* Clear high part of partial remainder */
99 remLo = a; /* Get argument into low part of partial remainder */
100 count = 32; /* Load loop counter */
101 do {
102 remHi = (remHi << 32) | (remLo >> 32);
103 remLo <<= 2; /* get 2 bits of arg */
104 root <<= 1; /* Get ready for the next bit in the root */
105 testDiv = (root << 1) + 1; /* Test radical */
106 if (remHi >= testDiv) {
107 remHi -= testDiv;
108 root++;
109 }
110 } while (count-- != 0);
111
112 return root;
113 }
114
115 static inline unsigned int
eina_f32p32_fracc_get(Eina_F32p32 v)116 eina_f32p32_fracc_get(Eina_F32p32 v)
117 {
118 return (unsigned int)v;
119 }
120
121 #endif
122