SkFloat.cpp revision c490f801b063a0837501feab3d12b73d71f46312
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
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    {
219        SkDEBUGFAIL("can't sqrt a negative number");
220        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"
271#include "SkFloatingPoint.h"
272
273void SkFloat::UnitTest()
274{
275#ifdef SK_SUPPORT_UNITTEST
276    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);
292    SkDebugf("SkFloat: %d + %d = %d\n", c.getInt(), b.getInt(), d.getInt());
293
294    SkMWCRandom    rand;
295
296    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
391}
392
393#endif
394