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