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