Home | History | Annotate | Download | only in core
      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 "SkMath.h"
     12 
     13 #define EXP_BIAS    (127+23)
     14 
     15 static int get_unsigned_exp(uint32_t packed)
     16 {
     17     return (packed << 1 >> 24);
     18 }
     19 
     20 static unsigned get_unsigned_value(uint32_t packed)
     21 {
     22     return (packed << 9 >> 9) | (1 << 23);
     23 }
     24 
     25 static int get_signed_value(int32_t packed)
     26 {
     27     return SkApplySign(get_unsigned_value(packed), SkExtractSign(packed));
     28 }
     29 
     30 /////////////////////////////////////////////////////////////////////////
     31 
     32 int 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 
     60 int32_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 
    116 int32_t SkFloat::Neg(int32_t packed)
    117 {
    118     if (packed)
    119         packed = packed ^ (1 << 31);
    120     return packed;
    121 }
    122 
    123 int32_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 
    161 static 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 
    170 int32_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 
    184 int32_t SkFloat::MulInt(int32_t packed, int n)
    185 {
    186     return Mul(packed, SetShift(n, 0));
    187 }
    188 
    189 int32_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 
    205 int32_t SkFloat::DivInt(int32_t packed, int n)
    206 {
    207     return Div(packed, SetShift(n, 0));
    208 }
    209 
    210 int32_t SkFloat::Invert(int32_t packed)
    211 {
    212     return Div(packed, SetShift(1, 0));
    213 }
    214 
    215 int32_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 
    237 int32_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 
    247 static inline int32_t clear_high_bit(int32_t n)
    248 {
    249     return ((uint32_t)(n << 1)) >> 1;
    250 }
    251 
    252 static inline int int_sign(int32_t a, int32_t b)
    253 {
    254     return a > b ? 1 : (a < b ? -1 : 0);
    255 }
    256 
    257 int 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 #ifdef SK_CAN_USE_FLOAT
    272     #include "SkFloatingPoint.h"
    273 #endif
    274 
    275 void SkFloat::UnitTest()
    276 {
    277 #ifdef SK_SUPPORT_UNITTEST
    278     SkFloat a, b, c, d;
    279     int     n;
    280 
    281     a.setZero();
    282     n = a.getInt();
    283     SkASSERT(n == 0);
    284 
    285     b.setInt(5);
    286     n = b.getInt();
    287     SkASSERT(n == 5);
    288 
    289     c.setInt(-3);
    290     n = c.getInt();
    291     SkASSERT(n == -3);
    292 
    293     d.setAdd(c, b);
    294     SkDebugf("SkFloat: %d + %d = %d\n", c.getInt(), b.getInt(), d.getInt());
    295 
    296     SkRandom    rand;
    297 
    298 #ifdef SK_CAN_USE_FLOAT
    299     int i;
    300     for (i = 0; i < 1000; i++)
    301     {
    302         float fa, fb;
    303         int aa = rand.nextS() >> 14;
    304         int bb = rand.nextS() >> 14;
    305         a.setInt(aa);
    306         b.setInt(bb);
    307         SkASSERT(a.getInt() == aa);
    308         SkASSERT(b.getInt() == bb);
    309 
    310         c.setAdd(a, b);
    311         int cc = c.getInt();
    312         SkASSERT(cc == aa + bb);
    313 
    314         c.setSub(a, b);
    315         cc = c.getInt();
    316         SkASSERT(cc == aa - bb);
    317 
    318         aa >>= 5;
    319         bb >>= 5;
    320         a.setInt(aa);
    321         b.setInt(bb);
    322         c.setMul(a, b);
    323         cc = c.getInt();
    324         SkASSERT(cc == aa * bb);
    325         /////////////////////////////////////
    326 
    327         aa = rand.nextS() >> 11;
    328         a.setFixed(aa);
    329         cc = a.getFixed();
    330         SkASSERT(aa == cc);
    331 
    332         bb = rand.nextS() >> 11;
    333         b.setFixed(bb);
    334         cc = b.getFixed();
    335         SkASSERT(bb == cc);
    336 
    337         cc = SkFixedMul(aa, bb);
    338         c.setMul(a, b);
    339         SkFixed dd = c.getFixed();
    340         int diff = cc - dd;
    341         SkASSERT(SkAbs32(diff) <= 1);
    342 
    343         fa = (float)aa / 65536.0f;
    344         fb = (float)bb / 65536.0f;
    345         a.assertEquals(fa);
    346         b.assertEquals(fb);
    347         fa = a.getFloat();
    348         fb = b.getFloat();
    349 
    350         c.assertEquals(fa * fb, 1);
    351 
    352         c.setDiv(a, b);
    353         cc = SkFixedDiv(aa, bb);
    354         dd = c.getFixed();
    355         diff = cc - dd;
    356         SkASSERT(SkAbs32(diff) <= 3);
    357 
    358         c.assertEquals(fa / fb, 1);
    359 
    360         SkASSERT((aa == bb) == (a == b));
    361         SkASSERT((aa != bb) == (a != b));
    362         SkASSERT((aa < bb) == (a < b));
    363         SkASSERT((aa <= bb) == (a <= b));
    364         SkASSERT((aa > bb) == (a > b));
    365         SkASSERT((aa >= bb) == (a >= b));
    366 
    367         if (aa < 0)
    368         {
    369             aa = -aa;
    370             fa = -fa;
    371         }
    372         a.setFixed(aa);
    373         c.setSqrt(a);
    374         cc = SkFixedSqrt(aa);
    375         dd = c.getFixed();
    376         SkASSERT(dd == cc);
    377 
    378         c.assertEquals(sk_float_sqrt(fa), 2);
    379 
    380         // cuberoot
    381 #if 0
    382         a.setInt(1);
    383         a.cubeRoot();
    384         a.assertEquals(1.0f, 0);
    385         a.setInt(8);
    386         a.cubeRoot();
    387         a.assertEquals(2.0f, 0);
    388         a.setInt(27);
    389         a.cubeRoot();
    390         a.assertEquals(3.0f, 0);
    391 #endif
    392     }
    393 #endif
    394 #endif
    395 }
    396 
    397 #endif
    398