blob: 42194ed54506c1c88b80184087e9519a160a02a6 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
reed@android.com8a1c16f2008-12-17 15:59:43 +00002/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00003 * Copyright 2008 The Android Open Source Project
reed@android.com8a1c16f2008-12-17 15:59:43 +00004 *
epoger@google.comec3ed6a2011-07-28 14:26:00 +00005 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
reed@android.com8a1c16f2008-12-17 15:59:43 +00007 */
8
epoger@google.comec3ed6a2011-07-28 14:26:00 +00009
reed@android.com8a1c16f2008-12-17 15:59:43 +000010#include "SkFloat.h"
reed@google.com4b163ed2012-08-07 21:35:13 +000011#include "SkMathPriv.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000012
13#define EXP_BIAS (127+23)
14
15static int get_unsigned_exp(uint32_t packed)
16{
17 return (packed << 1 >> 24);
18}
19
20static unsigned get_unsigned_value(uint32_t packed)
21{
22 return (packed << 9 >> 9) | (1 << 23);
23}
24
25static int get_signed_value(int32_t packed)
26{
27 return SkApplySign(get_unsigned_value(packed), SkExtractSign(packed));
28}
29
30/////////////////////////////////////////////////////////////////////////
31
32int 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
60int32_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
116int32_t SkFloat::Neg(int32_t packed)
117{
118 if (packed)
119 packed = packed ^ (1 << 31);
120 return packed;
121}
122
123int32_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#include "Sk64.h"
160
161static inline int32_t mul24(int32_t a, int32_t b)
162{
163 Sk64 tmp;
164
165 tmp.setMul(a, b);
166 tmp.roundRight(24);
167 return tmp.get32();
168}
169
170int32_t SkFloat::Mul(int32_t packed_a, int32_t packed_b)
171{
172 if (packed_a == 0 || packed_b == 0)
173 return 0;
174
175 int exp_a = get_unsigned_exp(packed_a);
176 int exp_b = get_unsigned_exp(packed_b);
177
178 int value_a = get_signed_value(packed_a);
179 int value_b = get_signed_value(packed_b);
180
181 return SkFloat::SetShift(mul24(value_a, value_b), exp_a + exp_b - 2*EXP_BIAS + 24);
182}
183
184int32_t SkFloat::MulInt(int32_t packed, int n)
185{
186 return Mul(packed, SetShift(n, 0));
187}
188
189int32_t SkFloat::Div(int32_t packed_n, int32_t packed_d)
190{
191 SkASSERT(packed_d != 0);
192
193 if (packed_n == 0)
194 return 0;
195
196 int exp_n = get_unsigned_exp(packed_n);
197 int exp_d = get_unsigned_exp(packed_d);
198
199 int value_n = get_signed_value(packed_n);
200 int value_d = get_signed_value(packed_d);
201
202 return SkFloat::SetShift(SkDivBits(value_n, value_d, 24), exp_n - exp_d - 24);
203}
204
205int32_t SkFloat::DivInt(int32_t packed, int n)
206{
207 return Div(packed, SetShift(n, 0));
208}
209
210int32_t SkFloat::Invert(int32_t packed)
211{
212 return Div(packed, SetShift(1, 0));
213}
214
215int32_t SkFloat::Sqrt(int32_t packed)
216{
217 if (packed < 0)
218 {
tomhudson@google.com0c00f212011-12-28 14:59:50 +0000219 SkDEBUGFAIL("can't sqrt a negative number");
reed@android.com8a1c16f2008-12-17 15:59:43 +0000220 return 0;
221 }
222
223 int exp = get_unsigned_exp(packed);
224 int value = get_unsigned_value(packed);
225
226 int nexp = exp - EXP_BIAS;
227 int root = SkSqrtBits(value << (nexp & 1), 26);
228 nexp >>= 1;
229 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
237int32_t SkFloat::CubeRoot(int32_t packed)
238{
239 sk_throw();
240 return 0;
241}
242
243#if defined _WIN32 && _MSC_VER >= 1300
244#pragma warning ( pop )
245#endif
246
247static inline int32_t clear_high_bit(int32_t n)
248{
249 return ((uint32_t)(n << 1)) >> 1;
250}
251
252static inline int int_sign(int32_t a, int32_t b)
253{
254 return a > b ? 1 : (a < b ? -1 : 0);
255}
256
257int SkFloat::Cmp(int32_t packed_a, int32_t packed_b)
258{
259 packed_a = SkApplySign(clear_high_bit(packed_a), SkExtractSign(packed_a));
260 packed_b = SkApplySign(clear_high_bit(packed_b), SkExtractSign(packed_b));
261
262 return int_sign(packed_a, packed_b);
263}
264
265/////////////////////////////////////////////////////////////////////////////////////
266/////////////////////////////////////////////////////////////////////////////////////
267
268#ifdef SK_DEBUG
269
270#include "SkRandom.h"
reed@google.com7886ad32012-06-11 21:21:26 +0000271#include "SkFloatingPoint.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +0000272
273void SkFloat::UnitTest()
274{
robertphillips@google.com385afd82013-12-19 23:17:56 +0000275#if 0 // def SK_SUPPORT_UNITTEST
reed@android.com8a1c16f2008-12-17 15:59:43 +0000276 SkFloat a, b, c, d;
277 int n;
278
279 a.setZero();
280 n = a.getInt();
281 SkASSERT(n == 0);
282
283 b.setInt(5);
284 n = b.getInt();
285 SkASSERT(n == 5);
286
287 c.setInt(-3);
288 n = c.getInt();
289 SkASSERT(n == -3);
290
291 d.setAdd(c, b);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000292 SkDebugf("SkFloat: %d + %d = %d\n", c.getInt(), b.getInt(), d.getInt());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000293
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +0000294 SkRandom rand;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000295
reed@android.com8a1c16f2008-12-17 15:59:43 +0000296 int i;
297 for (i = 0; i < 1000; i++)
298 {
299 float fa, fb;
300 int aa = rand.nextS() >> 14;
301 int bb = rand.nextS() >> 14;
302 a.setInt(aa);
303 b.setInt(bb);
304 SkASSERT(a.getInt() == aa);
305 SkASSERT(b.getInt() == bb);
306
307 c.setAdd(a, b);
308 int cc = c.getInt();
309 SkASSERT(cc == aa + bb);
310
311 c.setSub(a, b);
312 cc = c.getInt();
313 SkASSERT(cc == aa - bb);
314
315 aa >>= 5;
316 bb >>= 5;
317 a.setInt(aa);
318 b.setInt(bb);
319 c.setMul(a, b);
320 cc = c.getInt();
321 SkASSERT(cc == aa * bb);
322 /////////////////////////////////////
323
324 aa = rand.nextS() >> 11;
325 a.setFixed(aa);
326 cc = a.getFixed();
327 SkASSERT(aa == cc);
328
329 bb = rand.nextS() >> 11;
330 b.setFixed(bb);
331 cc = b.getFixed();
332 SkASSERT(bb == cc);
333
334 cc = SkFixedMul(aa, bb);
335 c.setMul(a, b);
336 SkFixed dd = c.getFixed();
337 int diff = cc - dd;
338 SkASSERT(SkAbs32(diff) <= 1);
339
340 fa = (float)aa / 65536.0f;
341 fb = (float)bb / 65536.0f;
342 a.assertEquals(fa);
343 b.assertEquals(fb);
344 fa = a.getFloat();
345 fb = b.getFloat();
346
347 c.assertEquals(fa * fb, 1);
348
349 c.setDiv(a, b);
350 cc = SkFixedDiv(aa, bb);
351 dd = c.getFixed();
352 diff = cc - dd;
353 SkASSERT(SkAbs32(diff) <= 3);
354
355 c.assertEquals(fa / fb, 1);
356
357 SkASSERT((aa == bb) == (a == b));
358 SkASSERT((aa != bb) == (a != b));
359 SkASSERT((aa < bb) == (a < b));
360 SkASSERT((aa <= bb) == (a <= b));
361 SkASSERT((aa > bb) == (a > b));
362 SkASSERT((aa >= bb) == (a >= b));
363
364 if (aa < 0)
365 {
366 aa = -aa;
367 fa = -fa;
368 }
369 a.setFixed(aa);
370 c.setSqrt(a);
371 cc = SkFixedSqrt(aa);
372 dd = c.getFixed();
373 SkASSERT(dd == cc);
374
375 c.assertEquals(sk_float_sqrt(fa), 2);
376
377 // cuberoot
378#if 0
379 a.setInt(1);
380 a.cubeRoot();
381 a.assertEquals(1.0f, 0);
382 a.setInt(8);
383 a.cubeRoot();
384 a.assertEquals(2.0f, 0);
385 a.setInt(27);
386 a.cubeRoot();
387 a.assertEquals(3.0f, 0);
388#endif
389 }
390#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000391}
392
393#endif