Home | History | Annotate | Download | only in core
      1 /*
      2  * Copyright 2011 Google Inc.
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 #include "SkFloatBits.h"
      9 #include "SkMathPriv.h"
     10 
     11 /******************************************************************************
     12     SkFloatBits_toInt[Floor, Round, Ceil] are identical except for what they
     13     do right before they return ... >> exp;
     14     Floor - adds nothing
     15     Round - adds 1 << (exp - 1)
     16     Ceil - adds (1 << exp) - 1
     17 
     18     Floor and Cast are very similar, but Cast applies its sign after all other
     19     computations on value. Also, Cast does not need to check for negative zero,
     20     as that value (0x80000000) "does the right thing" for Ceil. Note that it
     21     doesn't for Floor/Round/Ceil, hence the explicit check.
     22 ******************************************************************************/
     23 
     24 #define EXP_BIAS            (127+23)
     25 #define MATISSA_MAGIC_BIG   (1 << 23)
     26 
     27 static inline int unpack_exp(uint32_t packed) {
     28     return (packed << 1 >> 24);
     29 }
     30 
     31 #if 0
     32 // the ARM compiler generates an extra BIC, so I use the dirty version instead
     33 static inline int unpack_matissa(uint32_t packed) {
     34     // we could mask with 0x7FFFFF, but that is harder for ARM to encode
     35     return (packed & ~0xFF000000) | MATISSA_MAGIC_BIG;
     36 }
     37 #endif
     38 
     39 // returns the low 24-bits, so we need to OR in the magic_bit afterwards
     40 static inline int unpack_matissa_dirty(uint32_t packed) {
     41     return packed & ~0xFF000000;
     42 }
     43 
     44 // same as (int)float
     45 int32_t SkFloatBits_toIntCast(int32_t packed) {
     46     int exp = unpack_exp(packed) - EXP_BIAS;
     47     int value = unpack_matissa_dirty(packed) | MATISSA_MAGIC_BIG;
     48 
     49     if (exp >= 0) {
     50         if (exp > 7) {    // overflow
     51             value = SK_MaxS32;
     52         } else {
     53             value <<= exp;
     54         }
     55     } else {
     56         exp = -exp;
     57         if (exp > 25) {   // underflow
     58             exp = 25;
     59         }
     60         value >>= exp;
     61     }
     62     return SkApplySign(value, SkExtractSign(packed));
     63 }
     64 
     65 // same as (int)floor(float)
     66 int32_t SkFloatBits_toIntFloor(int32_t packed) {
     67     // curse you negative 0
     68     if (SkLeftShift(packed, 1) == 0) {
     69         return 0;
     70     }
     71 
     72     int exp = unpack_exp(packed) - EXP_BIAS;
     73     int value = unpack_matissa_dirty(packed) | MATISSA_MAGIC_BIG;
     74 
     75     if (exp >= 0) {
     76         if (exp > 7) {    // overflow
     77             value = SK_MaxS32;
     78         } else {
     79             value <<= exp;
     80         }
     81         // apply the sign after we check for overflow
     82         return SkApplySign(value, SkExtractSign(packed));
     83     } else {
     84         // apply the sign before we right-shift
     85         value = SkApplySign(value, SkExtractSign(packed));
     86         exp = -exp;
     87         if (exp > 25) {   // underflow
     88 #ifdef SK_CPU_FLUSH_TO_ZERO
     89         // The iOS ARM processor discards small denormalized numbers to go faster.
     90         // The comparision below empirically causes the result to agree with the
     91         // tests in MathTest test_float_floor
     92             if (exp > 149) {
     93                 return 0;
     94             }
     95 #else
     96             exp = 25;
     97 #endif
     98         }
     99         // int add = 0;
    100         return value >> exp;
    101     }
    102 }
    103 
    104 // same as (int)floor(float + 0.5)
    105 int32_t SkFloatBits_toIntRound(int32_t packed) {
    106     // curse you negative 0
    107     if (SkLeftShift(packed, 1) == 0) {
    108         return 0;
    109     }
    110 
    111     int exp = unpack_exp(packed) - EXP_BIAS;
    112     int value = unpack_matissa_dirty(packed) | MATISSA_MAGIC_BIG;
    113 
    114     if (exp >= 0) {
    115         if (exp > 7) {    // overflow
    116             value = SK_MaxS32;
    117         } else {
    118             value <<= exp;
    119         }
    120         // apply the sign after we check for overflow
    121         return SkApplySign(value, SkExtractSign(packed));
    122     } else {
    123         // apply the sign before we right-shift
    124         value = SkApplySign(value, SkExtractSign(packed));
    125         exp = -exp;
    126         if (exp > 25) {   // underflow
    127             exp = 25;
    128         }
    129         int add = 1 << (exp - 1);
    130         return (value + add) >> exp;
    131     }
    132 }
    133 
    134 // same as (int)ceil(float)
    135 int32_t SkFloatBits_toIntCeil(int32_t packed) {
    136     // curse you negative 0
    137     if (SkLeftShift(packed, 1) == 0) {
    138         return 0;
    139     }
    140 
    141     int exp = unpack_exp(packed) - EXP_BIAS;
    142     int value = unpack_matissa_dirty(packed) | MATISSA_MAGIC_BIG;
    143 
    144     if (exp >= 0) {
    145         if (exp > 7) {    // overflow
    146             value = SK_MaxS32;
    147         } else {
    148             value <<= exp;
    149         }
    150         // apply the sign after we check for overflow
    151         return SkApplySign(value, SkExtractSign(packed));
    152     } else {
    153         // apply the sign before we right-shift
    154         value = SkApplySign(value, SkExtractSign(packed));
    155         exp = -exp;
    156         if (exp > 25) {   // underflow
    157 #ifdef SK_CPU_FLUSH_TO_ZERO
    158         // The iOS ARM processor discards small denormalized numbers to go faster.
    159         // The comparision below empirically causes the result to agree with the
    160         // tests in MathTest test_float_ceil
    161             if (exp > 149) {
    162                 return 0;
    163             }
    164             return 0 < value;
    165 #else
    166             exp = 25;
    167 #endif
    168         }
    169         int add = (1 << exp) - 1;
    170         return (value + add) >> exp;
    171     }
    172 }
    173 
    174 float SkIntToFloatCast(int32_t value) {
    175     if (0 == value) {
    176         return 0;
    177     }
    178 
    179     int shift = EXP_BIAS;
    180 
    181     // record the sign and make value positive
    182     int sign = SkExtractSign(value);
    183     value = SkApplySign(value, sign);
    184 
    185     if (value >> 24) {    // value is too big (has more than 24 bits set)
    186         int bias = 8 - SkCLZ(value);
    187         SkDebugf("value = %d, bias = %d\n", value, bias);
    188         SkASSERT(bias > 0 && bias < 8);
    189         value >>= bias; // need to round?
    190         shift += bias;
    191     } else {
    192         int zeros = SkCLZ(value << 8);
    193         SkASSERT(zeros >= 0 && zeros <= 23);
    194         value <<= zeros;
    195         shift -= zeros;
    196     }
    197 
    198     // now value is left-aligned to 24 bits
    199     SkASSERT((value >> 23) == 1);
    200     SkASSERT(shift >= 0 && shift <= 255);
    201 
    202     SkFloatIntUnion data;
    203     data.fSignBitInt = SkLeftShift(sign, 31) | SkLeftShift(shift, 23) | (value & ~MATISSA_MAGIC_BIG);
    204     return data.fFloat;
    205 }
    206