• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2006-2008 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "SkFloat.h"
18 #include "SkMath.h"
19 
20 #define EXP_BIAS    (127+23)
21 
get_unsigned_exp(uint32_t packed)22 static int get_unsigned_exp(uint32_t packed)
23 {
24     return (packed << 1 >> 24);
25 }
26 
get_unsigned_value(uint32_t packed)27 static unsigned get_unsigned_value(uint32_t packed)
28 {
29     return (packed << 9 >> 9) | (1 << 23);
30 }
31 
get_signed_value(int32_t packed)32 static int get_signed_value(int32_t packed)
33 {
34     return SkApplySign(get_unsigned_value(packed), SkExtractSign(packed));
35 }
36 
37 /////////////////////////////////////////////////////////////////////////
38 
GetShift(int32_t packed,int shift)39 int SkFloat::GetShift(int32_t packed, int shift)
40 {
41     if (packed == 0)
42         return 0;
43 
44     int exp = get_unsigned_exp(packed) - EXP_BIAS - shift;
45     int value = get_unsigned_value(packed);
46 
47     if (exp >= 0)
48     {
49         if (exp > 8)    // overflow
50             value = SK_MaxS32;
51         else
52             value <<= exp;
53     }
54     else
55     {
56         exp = -exp;
57         if (exp > 23)   // underflow
58             value = 0;
59         else
60             value >>= exp;
61     }
62     return SkApplySign(value, SkExtractSign(packed));
63 }
64 
65 /////////////////////////////////////////////////////////////////////////////////////
66 
SetShift(int value,int shift)67 int32_t SkFloat::SetShift(int value, int shift)
68 {
69     if (value == 0)
70         return 0;
71 
72     // record the sign and make value positive
73     int sign = SkExtractSign(value);
74     value = SkApplySign(value, sign);
75 
76     if (value >> 24)    // value is too big (has more than 24 bits set)
77     {
78         int bias = 8 - SkCLZ(value);
79         SkASSERT(bias > 0 && bias < 8);
80         value >>= bias;
81         shift += bias;
82     }
83     else
84     {
85         int zeros = SkCLZ(value << 8);
86         SkASSERT(zeros >= 0 && zeros <= 23);
87         value <<= zeros;
88         shift -= zeros;
89     }
90     // now value is left-aligned to 24 bits
91     SkASSERT((value >> 23) == 1);
92 
93     shift += EXP_BIAS;
94     if (shift < 0)  // underflow
95         return 0;
96     else
97     {
98         if (shift > 255)    // overflow
99         {
100             shift = 255;
101             value = 0x00FFFFFF;
102         }
103         int32_t packed = sign << 31;        // set the sign-bit
104         packed |= shift << 23;          // store the packed exponent
105         packed |= ((unsigned)(value << 9) >> 9);    // clear 24th bit of value (its implied)
106 
107 #ifdef SK_DEBUG
108         {
109             int n;
110 
111             n = SkExtractSign(packed);
112             SkASSERT(n == sign);
113             n = get_unsigned_exp(packed);
114             SkASSERT(n == shift);
115             n = get_unsigned_value(packed);
116             SkASSERT(n == value);
117         }
118 #endif
119         return packed;
120     }
121 }
122 
Neg(int32_t packed)123 int32_t SkFloat::Neg(int32_t packed)
124 {
125     if (packed)
126         packed = packed ^ (1 << 31);
127     return packed;
128 }
129 
Add(int32_t packed_a,int32_t packed_b)130 int32_t SkFloat::Add(int32_t packed_a, int32_t packed_b)
131 {
132     if (packed_a == 0)
133         return packed_b;
134     if (packed_b == 0)
135         return packed_a;
136 
137     int exp_a = get_unsigned_exp(packed_a);
138     int exp_b = get_unsigned_exp(packed_b);
139     int exp_diff = exp_a - exp_b;
140 
141     int shift_a = 0, shift_b = 0;
142     int exp;
143 
144     if (exp_diff >= 0)
145     {
146         if (exp_diff > 24)  // B is too small to contribute
147             return packed_a;
148         shift_b = exp_diff;
149         exp = exp_a;
150     }
151     else
152     {
153         exp_diff = -exp_diff;
154         if (exp_diff > 24)  // A is too small to contribute
155             return packed_b;
156         shift_a = exp_diff;
157         exp = exp_b;
158     }
159 
160     int value_a = get_signed_value(packed_a) >> shift_a;
161     int value_b = get_signed_value(packed_b) >> shift_b;
162 
163     return SkFloat::SetShift(value_a + value_b, exp - EXP_BIAS);
164 }
165 
166 #include "Sk64.h"
167 
mul24(int32_t a,int32_t b)168 static inline int32_t mul24(int32_t a, int32_t b)
169 {
170     Sk64 tmp;
171 
172     tmp.setMul(a, b);
173     tmp.roundRight(24);
174     return tmp.get32();
175 }
176 
Mul(int32_t packed_a,int32_t packed_b)177 int32_t SkFloat::Mul(int32_t packed_a, int32_t packed_b)
178 {
179     if (packed_a == 0 || packed_b == 0)
180         return 0;
181 
182     int exp_a = get_unsigned_exp(packed_a);
183     int exp_b = get_unsigned_exp(packed_b);
184 
185     int value_a = get_signed_value(packed_a);
186     int value_b = get_signed_value(packed_b);
187 
188     return SkFloat::SetShift(mul24(value_a, value_b), exp_a + exp_b - 2*EXP_BIAS + 24);
189 }
190 
MulInt(int32_t packed,int n)191 int32_t SkFloat::MulInt(int32_t packed, int n)
192 {
193     return Mul(packed, SetShift(n, 0));
194 }
195 
Div(int32_t packed_n,int32_t packed_d)196 int32_t SkFloat::Div(int32_t packed_n, int32_t packed_d)
197 {
198     SkASSERT(packed_d != 0);
199 
200     if (packed_n == 0)
201         return 0;
202 
203     int exp_n = get_unsigned_exp(packed_n);
204     int exp_d = get_unsigned_exp(packed_d);
205 
206     int value_n = get_signed_value(packed_n);
207     int value_d = get_signed_value(packed_d);
208 
209     return SkFloat::SetShift(SkDivBits(value_n, value_d, 24), exp_n - exp_d - 24);
210 }
211 
DivInt(int32_t packed,int n)212 int32_t SkFloat::DivInt(int32_t packed, int n)
213 {
214     return Div(packed, SetShift(n, 0));
215 }
216 
Invert(int32_t packed)217 int32_t SkFloat::Invert(int32_t packed)
218 {
219     return Div(packed, SetShift(1, 0));
220 }
221 
Sqrt(int32_t packed)222 int32_t SkFloat::Sqrt(int32_t packed)
223 {
224     if (packed < 0)
225     {
226         SkASSERT(!"can't sqrt a negative number");
227         return 0;
228     }
229 
230     int exp = get_unsigned_exp(packed);
231     int value = get_unsigned_value(packed);
232 
233     int nexp = exp - EXP_BIAS;
234     int root = SkSqrtBits(value << (nexp & 1), 26);
235     nexp >>= 1;
236     return SkFloat::SetShift(root, nexp - 11);
237 }
238 
239 #if defined _WIN32 && _MSC_VER >= 1300  // disable warning : unreachable code
240 #pragma warning ( push )
241 #pragma warning ( disable : 4702 )
242 #endif
243 
CubeRoot(int32_t packed)244 int32_t SkFloat::CubeRoot(int32_t packed)
245 {
246     sk_throw();
247     return 0;
248 }
249 
250 #if defined _WIN32 && _MSC_VER >= 1300
251 #pragma warning ( pop )
252 #endif
253 
clear_high_bit(int32_t n)254 static inline int32_t clear_high_bit(int32_t n)
255 {
256     return ((uint32_t)(n << 1)) >> 1;
257 }
258 
int_sign(int32_t a,int32_t b)259 static inline int int_sign(int32_t a, int32_t b)
260 {
261     return a > b ? 1 : (a < b ? -1 : 0);
262 }
263 
Cmp(int32_t packed_a,int32_t packed_b)264 int SkFloat::Cmp(int32_t packed_a, int32_t packed_b)
265 {
266     packed_a = SkApplySign(clear_high_bit(packed_a), SkExtractSign(packed_a));
267     packed_b = SkApplySign(clear_high_bit(packed_b), SkExtractSign(packed_b));
268 
269     return int_sign(packed_a, packed_b);
270 }
271 
272 /////////////////////////////////////////////////////////////////////////////////////
273 /////////////////////////////////////////////////////////////////////////////////////
274 
275 #ifdef SK_DEBUG
276 
277 #include "SkRandom.h"
278 #ifdef SK_CAN_USE_FLOAT
279     #include "SkFloatingPoint.h"
280 #endif
281 
UnitTest()282 void SkFloat::UnitTest()
283 {
284 #ifdef SK_SUPPORT_UNITTEST
285     SkFloat a, b, c, d;
286     int     n;
287 
288     a.setZero();
289     n = a.getInt();
290     SkASSERT(n == 0);
291 
292     b.setInt(5);
293     n = b.getInt();
294     SkASSERT(n == 5);
295 
296     c.setInt(-3);
297     n = c.getInt();
298     SkASSERT(n == -3);
299 
300     d.setAdd(c, b);
301     SkDebugf("SkFloat: %d + %d = %d\n", c.getInt(), b.getInt(), d.getInt());
302 
303     SkRandom    rand;
304 
305 #ifdef SK_CAN_USE_FLOAT
306     int i;
307     for (i = 0; i < 1000; i++)
308     {
309         float fa, fb;
310         int aa = rand.nextS() >> 14;
311         int bb = rand.nextS() >> 14;
312         a.setInt(aa);
313         b.setInt(bb);
314         SkASSERT(a.getInt() == aa);
315         SkASSERT(b.getInt() == bb);
316 
317         c.setAdd(a, b);
318         int cc = c.getInt();
319         SkASSERT(cc == aa + bb);
320 
321         c.setSub(a, b);
322         cc = c.getInt();
323         SkASSERT(cc == aa - bb);
324 
325         aa >>= 5;
326         bb >>= 5;
327         a.setInt(aa);
328         b.setInt(bb);
329         c.setMul(a, b);
330         cc = c.getInt();
331         SkASSERT(cc == aa * bb);
332         /////////////////////////////////////
333 
334         aa = rand.nextS() >> 11;
335         a.setFixed(aa);
336         cc = a.getFixed();
337         SkASSERT(aa == cc);
338 
339         bb = rand.nextS() >> 11;
340         b.setFixed(bb);
341         cc = b.getFixed();
342         SkASSERT(bb == cc);
343 
344         cc = SkFixedMul(aa, bb);
345         c.setMul(a, b);
346         SkFixed dd = c.getFixed();
347         int diff = cc - dd;
348         SkASSERT(SkAbs32(diff) <= 1);
349 
350         fa = (float)aa / 65536.0f;
351         fb = (float)bb / 65536.0f;
352         a.assertEquals(fa);
353         b.assertEquals(fb);
354         fa = a.getFloat();
355         fb = b.getFloat();
356 
357         c.assertEquals(fa * fb, 1);
358 
359         c.setDiv(a, b);
360         cc = SkFixedDiv(aa, bb);
361         dd = c.getFixed();
362         diff = cc - dd;
363         SkASSERT(SkAbs32(diff) <= 3);
364 
365         c.assertEquals(fa / fb, 1);
366 
367         SkASSERT((aa == bb) == (a == b));
368         SkASSERT((aa != bb) == (a != b));
369         SkASSERT((aa < bb) == (a < b));
370         SkASSERT((aa <= bb) == (a <= b));
371         SkASSERT((aa > bb) == (a > b));
372         SkASSERT((aa >= bb) == (a >= b));
373 
374         if (aa < 0)
375         {
376             aa = -aa;
377             fa = -fa;
378         }
379         a.setFixed(aa);
380         c.setSqrt(a);
381         cc = SkFixedSqrt(aa);
382         dd = c.getFixed();
383         SkASSERT(dd == cc);
384 
385         c.assertEquals(sk_float_sqrt(fa), 2);
386 
387         // cuberoot
388 #if 0
389         a.setInt(1);
390         a.cubeRoot();
391         a.assertEquals(1.0f, 0);
392         a.setInt(8);
393         a.cubeRoot();
394         a.assertEquals(2.0f, 0);
395         a.setInt(27);
396         a.cubeRoot();
397         a.assertEquals(3.0f, 0);
398 #endif
399     }
400 #endif
401 #endif
402 }
403 
404 #endif
405