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