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