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