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