OLD | NEW |
| (Empty) |
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 | |
22 static int get_unsigned_exp(uint32_t packed) | |
23 { | |
24 return (packed << 1 >> 24); | |
25 } | |
26 | |
27 static unsigned get_unsigned_value(uint32_t packed) | |
28 { | |
29 return (packed << 9 >> 9) | (1 << 23); | |
30 } | |
31 | |
32 static int get_signed_value(int32_t packed) | |
33 { | |
34 return SkApplySign(get_unsigned_value(packed), SkExtractSign(packed)); | |
35 } | |
36 | |
37 ///////////////////////////////////////////////////////////////////////// | |
38 | |
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 | |
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 | |
123 int32_t SkFloat::Neg(int32_t packed) | |
124 { | |
125 if (packed) | |
126 packed = packed ^ (1 << 31); | |
127 return packed; | |
128 } | |
129 | |
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 | |
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 | |
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 | |
191 int32_t SkFloat::MulInt(int32_t packed, int n) | |
192 { | |
193 return Mul(packed, SetShift(n, 0)); | |
194 } | |
195 | |
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 | |
212 int32_t SkFloat::DivInt(int32_t packed, int n) | |
213 { | |
214 return Div(packed, SetShift(n, 0)); | |
215 } | |
216 | |
217 int32_t SkFloat::Invert(int32_t packed) | |
218 { | |
219 return Div(packed, SetShift(1, 0)); | |
220 } | |
221 | |
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 | |
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 | |
254 static inline int32_t clear_high_bit(int32_t n) | |
255 { | |
256 return ((uint32_t)(n << 1)) >> 1; | |
257 } | |
258 | |
259 static inline int int_sign(int32_t a, int32_t b) | |
260 { | |
261 return a > b ? 1 : (a < b ? -1 : 0); | |
262 } | |
263 | |
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 | |
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 | |
OLD | NEW |