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