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 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 static inline int32_t mul24(int32_t a, int32_t b) { 160 int64_t tmp = (sk_64_mul(a, b) + (1 << 23)) >> 24; 161 return sk_64_asS32(tmp); 162 } 163 164 int32_t SkFloat::Mul(int32_t packed_a, int32_t packed_b) 165 { 166 if (packed_a == 0 || packed_b == 0) 167 return 0; 168 169 int exp_a = get_unsigned_exp(packed_a); 170 int exp_b = get_unsigned_exp(packed_b); 171 172 int value_a = get_signed_value(packed_a); 173 int value_b = get_signed_value(packed_b); 174 175 return SkFloat::SetShift(mul24(value_a, value_b), exp_a + exp_b - 2*EXP_BIAS + 24); 176 } 177 178 int32_t SkFloat::MulInt(int32_t packed, int n) 179 { 180 return Mul(packed, SetShift(n, 0)); 181 } 182 183 int32_t SkFloat::Div(int32_t packed_n, int32_t packed_d) 184 { 185 SkASSERT(packed_d != 0); 186 187 if (packed_n == 0) 188 return 0; 189 190 int exp_n = get_unsigned_exp(packed_n); 191 int exp_d = get_unsigned_exp(packed_d); 192 193 int value_n = get_signed_value(packed_n); 194 int value_d = get_signed_value(packed_d); 195 196 return SkFloat::SetShift(SkDivBits(value_n, value_d, 24), exp_n - exp_d - 24); 197 } 198 199 int32_t SkFloat::DivInt(int32_t packed, int n) 200 { 201 return Div(packed, SetShift(n, 0)); 202 } 203 204 int32_t SkFloat::Invert(int32_t packed) 205 { 206 return Div(packed, SetShift(1, 0)); 207 } 208 209 int32_t SkFloat::Sqrt(int32_t packed) 210 { 211 if (packed < 0) 212 { 213 SkDEBUGFAIL("can't sqrt a negative number"); 214 return 0; 215 } 216 217 int exp = get_unsigned_exp(packed); 218 int value = get_unsigned_value(packed); 219 220 int nexp = exp - EXP_BIAS; 221 int root = SkSqrtBits(value << (nexp & 1), 26); 222 nexp >>= 1; 223 return SkFloat::SetShift(root, nexp - 11); 224 } 225 226 #if defined _WIN32 && _MSC_VER >= 1300 // disable warning : unreachable code 227 #pragma warning ( push ) 228 #pragma warning ( disable : 4702 ) 229 #endif 230 231 int32_t SkFloat::CubeRoot(int32_t packed) 232 { 233 sk_throw(); 234 return 0; 235 } 236 237 #if defined _WIN32 && _MSC_VER >= 1300 238 #pragma warning ( pop ) 239 #endif 240 241 static inline int32_t clear_high_bit(int32_t n) 242 { 243 return ((uint32_t)(n << 1)) >> 1; 244 } 245 246 static inline int int_sign(int32_t a, int32_t b) 247 { 248 return a > b ? 1 : (a < b ? -1 : 0); 249 } 250 251 int SkFloat::Cmp(int32_t packed_a, int32_t packed_b) 252 { 253 packed_a = SkApplySign(clear_high_bit(packed_a), SkExtractSign(packed_a)); 254 packed_b = SkApplySign(clear_high_bit(packed_b), SkExtractSign(packed_b)); 255 256 return int_sign(packed_a, packed_b); 257 } 258 259 ///////////////////////////////////////////////////////////////////////////////////// 260 ///////////////////////////////////////////////////////////////////////////////////// 261 262 #ifdef SK_DEBUG 263 264 #include "SkRandom.h" 265 #include "SkFloatingPoint.h" 266 267 void SkFloat::UnitTest() 268 { 269 #if 0 // def SK_SUPPORT_UNITTEST 270 SkFloat a, b, c, d; 271 int n; 272 273 a.setZero(); 274 n = a.getInt(); 275 SkASSERT(n == 0); 276 277 b.setInt(5); 278 n = b.getInt(); 279 SkASSERT(n == 5); 280 281 c.setInt(-3); 282 n = c.getInt(); 283 SkASSERT(n == -3); 284 285 d.setAdd(c, b); 286 SkDebugf("SkFloat: %d + %d = %d\n", c.getInt(), b.getInt(), d.getInt()); 287 288 SkRandom rand; 289 290 int i; 291 for (i = 0; i < 1000; i++) 292 { 293 float fa, fb; 294 int aa = rand.nextS() >> 14; 295 int bb = rand.nextS() >> 14; 296 a.setInt(aa); 297 b.setInt(bb); 298 SkASSERT(a.getInt() == aa); 299 SkASSERT(b.getInt() == bb); 300 301 c.setAdd(a, b); 302 int cc = c.getInt(); 303 SkASSERT(cc == aa + bb); 304 305 c.setSub(a, b); 306 cc = c.getInt(); 307 SkASSERT(cc == aa - bb); 308 309 aa >>= 5; 310 bb >>= 5; 311 a.setInt(aa); 312 b.setInt(bb); 313 c.setMul(a, b); 314 cc = c.getInt(); 315 SkASSERT(cc == aa * bb); 316 ///////////////////////////////////// 317 318 aa = rand.nextS() >> 11; 319 a.setFixed(aa); 320 cc = a.getFixed(); 321 SkASSERT(aa == cc); 322 323 bb = rand.nextS() >> 11; 324 b.setFixed(bb); 325 cc = b.getFixed(); 326 SkASSERT(bb == cc); 327 328 cc = SkFixedMul(aa, bb); 329 c.setMul(a, b); 330 SkFixed dd = c.getFixed(); 331 int diff = cc - dd; 332 SkASSERT(SkAbs32(diff) <= 1); 333 334 fa = (float)aa / 65536.0f; 335 fb = (float)bb / 65536.0f; 336 a.assertEquals(fa); 337 b.assertEquals(fb); 338 fa = a.getFloat(); 339 fb = b.getFloat(); 340 341 c.assertEquals(fa * fb, 1); 342 343 c.setDiv(a, b); 344 cc = SkFixedDiv(aa, bb); 345 dd = c.getFixed(); 346 diff = cc - dd; 347 SkASSERT(SkAbs32(diff) <= 3); 348 349 c.assertEquals(fa / fb, 1); 350 351 SkASSERT((aa == bb) == (a == b)); 352 SkASSERT((aa != bb) == (a != b)); 353 SkASSERT((aa < bb) == (a < b)); 354 SkASSERT((aa <= bb) == (a <= b)); 355 SkASSERT((aa > bb) == (a > b)); 356 SkASSERT((aa >= bb) == (a >= b)); 357 358 if (aa < 0) 359 { 360 aa = -aa; 361 fa = -fa; 362 } 363 a.setFixed(aa); 364 c.setSqrt(a); 365 cc = SkFixedSqrt(aa); 366 dd = c.getFixed(); 367 SkASSERT(dd == cc); 368 369 c.assertEquals(sk_float_sqrt(fa), 2); 370 371 // cuberoot 372 #if 0 373 a.setInt(1); 374 a.cubeRoot(); 375 a.assertEquals(1.0f, 0); 376 a.setInt(8); 377 a.cubeRoot(); 378 a.assertEquals(2.0f, 0); 379 a.setInt(27); 380 a.cubeRoot(); 381 a.assertEquals(3.0f, 0); 382 #endif 383 } 384 #endif 385 } 386 387 #endif 388