| OLD | NEW |
| (Empty) |
| 1 /* libs/corecg/Sk64.cpp | |
| 2 ** | |
| 3 ** Copyright 2006, The Android Open Source Project | |
| 4 ** | |
| 5 ** Licensed under the Apache License, Version 2.0 (the "License"); | |
| 6 ** you may not use this file except in compliance with the License. | |
| 7 ** You may obtain a copy of the License at | |
| 8 ** | |
| 9 ** http://www.apache.org/licenses/LICENSE-2.0 | |
| 10 ** | |
| 11 ** Unless required by applicable law or agreed to in writing, software | |
| 12 ** distributed under the License is distributed on an "AS IS" BASIS, | |
| 13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| 14 ** See the License for the specific language governing permissions and | |
| 15 ** limitations under the License. | |
| 16 */ | |
| 17 | |
| 18 #include "Sk64.h" | |
| 19 | |
| 20 #define shift_left(hi, lo) \ | |
| 21 hi = (hi << 1) | (lo >> 31); \ | |
| 22 lo <<= 1 | |
| 23 | |
| 24 #define shift_left_bits(hi, lo, bits) \ | |
| 25 SkASSERT((unsigned)(bits) < 31); \ | |
| 26 hi = (hi << (bits)) | (lo >> (32 - (bits))); \ | |
| 27 lo <<= (bits) | |
| 28 | |
| 29 ////////////////////////////////////////////////////////////////////// | |
| 30 | |
| 31 int Sk64::getClzAbs() const | |
| 32 { | |
| 33 int32_t hi = fHi; | |
| 34 uint32_t lo = fLo; | |
| 35 | |
| 36 // get abs | |
| 37 if (hi < 0) | |
| 38 { | |
| 39 hi = -hi - Sk32ToBool(lo); | |
| 40 lo = 0 - lo; | |
| 41 } | |
| 42 return hi ? SkCLZ(hi) : SkCLZ(lo) + 32; | |
| 43 } | |
| 44 | |
| 45 void Sk64::shiftLeft(unsigned bits) | |
| 46 { | |
| 47 SkASSERT(bits <= 63); | |
| 48 if (bits == 0) | |
| 49 return; | |
| 50 | |
| 51 if (bits >= 32) | |
| 52 { | |
| 53 fHi = fLo << (bits - 32); | |
| 54 fLo = 0; | |
| 55 } | |
| 56 else | |
| 57 { | |
| 58 fHi = (fHi << bits) | (fLo >> (32 - bits)); | |
| 59 fLo <<= bits; | |
| 60 } | |
| 61 } | |
| 62 | |
| 63 int32_t Sk64::getShiftRight(unsigned bits) const | |
| 64 { | |
| 65 SkASSERT(bits <= 63); | |
| 66 | |
| 67 if (bits == 0) | |
| 68 return fLo; | |
| 69 | |
| 70 if (bits >= 32) | |
| 71 return fHi >> (bits - 32); | |
| 72 else | |
| 73 { | |
| 74 #ifdef SK_DEBUG | |
| 75 int32_t tmp = fHi >> bits; | |
| 76 SkASSERT(tmp == 0 || tmp == -1); | |
| 77 #endif | |
| 78 return (fHi << (32 - bits)) | (fLo >> bits); | |
| 79 } | |
| 80 } | |
| 81 | |
| 82 void Sk64::shiftRight(unsigned bits) | |
| 83 { | |
| 84 SkASSERT(bits <= 63); | |
| 85 if (bits == 0) | |
| 86 return; | |
| 87 | |
| 88 if (bits >= 32) | |
| 89 { | |
| 90 fLo = fHi >> (bits - 32); | |
| 91 fHi >>= 31; | |
| 92 } | |
| 93 else | |
| 94 { | |
| 95 fLo = (fHi << (32 - bits)) | (fLo >> bits); | |
| 96 fHi >>= bits; | |
| 97 } | |
| 98 } | |
| 99 | |
| 100 void Sk64::roundRight(unsigned bits) | |
| 101 { | |
| 102 SkASSERT(bits <= 63); | |
| 103 if (bits) | |
| 104 { | |
| 105 Sk64 one; | |
| 106 one.set(1); | |
| 107 one.shiftLeft(bits - 1); | |
| 108 this->add(one); | |
| 109 this->shiftRight(bits); | |
| 110 } | |
| 111 } | |
| 112 | |
| 113 int Sk64::shiftToMake32() const | |
| 114 { | |
| 115 int32_t hi = fHi; | |
| 116 uint32_t lo = fLo; | |
| 117 | |
| 118 if (hi < 0) // make it positive | |
| 119 { | |
| 120 hi = -hi - Sk32ToBool(lo); | |
| 121 lo = 0 - lo; | |
| 122 } | |
| 123 | |
| 124 if (hi == 0) | |
| 125 return lo >> 31; | |
| 126 else | |
| 127 return 33 - SkCLZ(hi); | |
| 128 } | |
| 129 | |
| 130 void Sk64::negate() | |
| 131 { | |
| 132 fHi = -fHi - Sk32ToBool(fLo); | |
| 133 fLo = 0 - fLo; | |
| 134 } | |
| 135 | |
| 136 void Sk64::abs() | |
| 137 { | |
| 138 if (fHi < 0) | |
| 139 { | |
| 140 fHi = -fHi - Sk32ToBool(fLo); | |
| 141 fLo = 0 - fLo; | |
| 142 } | |
| 143 } | |
| 144 | |
| 145 //////////////////////////////////////////////////////////////// | |
| 146 | |
| 147 static inline int32_t round_right_16(int32_t hi, uint32_t lo) | |
| 148 { | |
| 149 uint32_t sum = lo + (1 << 15); | |
| 150 hi += (sum < lo); | |
| 151 return (hi << 16) | (sum >> 16); | |
| 152 } | |
| 153 | |
| 154 SkBool Sk64::isFixed() const | |
| 155 { | |
| 156 Sk64 tmp = *this; | |
| 157 tmp.roundRight(16); | |
| 158 return tmp.is32(); | |
| 159 } | |
| 160 | |
| 161 SkFract Sk64::getFract() const | |
| 162 { | |
| 163 Sk64 tmp = *this; | |
| 164 tmp.roundRight(30); | |
| 165 return tmp.get32(); | |
| 166 } | |
| 167 | |
| 168 void Sk64::sub(const Sk64& a) | |
| 169 { | |
| 170 fHi = fHi - a.fHi - (fLo < a.fLo); | |
| 171 fLo = fLo - a.fLo; | |
| 172 } | |
| 173 | |
| 174 void Sk64::rsub(const Sk64& a) | |
| 175 { | |
| 176 fHi = a.fHi - fHi - (a.fLo < fLo); | |
| 177 fLo = a.fLo - fLo; | |
| 178 } | |
| 179 | |
| 180 void Sk64::setMul(int32_t a, int32_t b) | |
| 181 { | |
| 182 int sa = a >> 31; | |
| 183 int sb = b >> 31; | |
| 184 // now make them positive | |
| 185 a = (a ^ sa) - sa; | |
| 186 b = (b ^ sb) - sb; | |
| 187 | |
| 188 uint32_t ah = a >> 16; | |
| 189 uint32_t al = a & 0xFFFF; | |
| 190 uint32_t bh = b >> 16; | |
| 191 uint32_t bl = b & 0xFFFF; | |
| 192 | |
| 193 uint32_t A = ah * bh; | |
| 194 uint32_t B = ah * bl + al * bh; | |
| 195 uint32_t C = al * bl; | |
| 196 | |
| 197 /* [ A ] | |
| 198 [ B ] | |
| 199 [ C ] | |
| 200 */ | |
| 201 fLo = C + (B << 16); | |
| 202 fHi = A + (B >>16) + (fLo < C); | |
| 203 | |
| 204 if (sa != sb) | |
| 205 this->negate(); | |
| 206 } | |
| 207 | |
| 208 void Sk64::div(int32_t denom, DivOptions option) | |
| 209 { | |
| 210 SkASSERT(denom); | |
| 211 | |
| 212 int32_t hi = fHi; | |
| 213 uint32_t lo = fLo; | |
| 214 int sign = denom ^ hi; | |
| 215 | |
| 216 denom = SkAbs32(denom); | |
| 217 if (hi < 0) | |
| 218 { | |
| 219 hi = -hi - Sk32ToBool(lo); | |
| 220 lo = 0 - lo; | |
| 221 } | |
| 222 | |
| 223 if (option == kRound_DivOption) // add denom/2 | |
| 224 { | |
| 225 uint32_t newLo = lo + (denom >> 1); | |
| 226 hi += (newLo < lo); | |
| 227 lo = newLo; | |
| 228 } | |
| 229 | |
| 230 if (hi == 0) // fast-case | |
| 231 { | |
| 232 if (lo < (uint32_t)denom) | |
| 233 this->set(0, 0); | |
| 234 else | |
| 235 { | |
| 236 this->set(0, lo / denom); | |
| 237 if (sign < 0) | |
| 238 this->negate(); | |
| 239 } | |
| 240 return; | |
| 241 } | |
| 242 | |
| 243 int bits; | |
| 244 | |
| 245 { | |
| 246 int dbits = SkCLZ(denom); | |
| 247 int nbits = SkCLZ(hi); | |
| 248 | |
| 249 bits = 32 + dbits - nbits; | |
| 250 SkASSERT(bits <= 63); | |
| 251 if (bits <= 0) | |
| 252 { | |
| 253 this->set(0, 0); | |
| 254 return; | |
| 255 } | |
| 256 denom <<= (dbits - 1); | |
| 257 shift_left_bits(hi, lo, nbits - 1); | |
| 258 } | |
| 259 | |
| 260 int32_t rhi = 0; | |
| 261 uint32_t rlo = 0; | |
| 262 | |
| 263 do { | |
| 264 shift_left(rhi, rlo); | |
| 265 #ifdef SK_CPU_HAS_CONDITIONAL_INSTR | |
| 266 if ((uint32_t)denom <= (uint32_t)hi) | |
| 267 { | |
| 268 hi -= denom; | |
| 269 rlo |= 1; | |
| 270 } | |
| 271 #else | |
| 272 int32_t diff = (denom - hi - 1) >> 31; | |
| 273 hi -= denom & diff; | |
| 274 rlo -= diff; | |
| 275 #endif | |
| 276 shift_left(hi, lo); | |
| 277 } while (--bits >= 0); | |
| 278 SkASSERT(rhi >= 0); | |
| 279 | |
| 280 fHi = rhi; | |
| 281 fLo = rlo; | |
| 282 if (sign < 0) | |
| 283 this->negate(); | |
| 284 } | |
| 285 | |
| 286 #define shift_left_2(a, b, c) \ | |
| 287 a = (a << 2) | (b >> 30); \ | |
| 288 b = (b << 2) | (c >> 30); \ | |
| 289 c <<= 2 | |
| 290 | |
| 291 int32_t Sk64::getSqrt() const | |
| 292 { | |
| 293 SkASSERT(!this->isNeg()); | |
| 294 | |
| 295 uint32_t hi = fHi; | |
| 296 uint32_t lo = fLo; | |
| 297 uint32_t sqr = 0; | |
| 298 uint32_t root = 0; | |
| 299 int count = 31; | |
| 300 | |
| 301 do { | |
| 302 root <<= 1; | |
| 303 shift_left_2(sqr, hi, lo); | |
| 304 | |
| 305 uint32_t testDiv = (root << 1) + 1; | |
| 306 if (sqr >= testDiv) | |
| 307 { | |
| 308 sqr -= testDiv; | |
| 309 root++; | |
| 310 } | |
| 311 } while (--count >= 0); | |
| 312 SkASSERT((int32_t)root >= 0); | |
| 313 | |
| 314 return root; | |
| 315 } | |
| 316 | |
| 317 #ifdef SkLONGLONG | |
| 318 SkLONGLONG Sk64::getLongLong() const | |
| 319 { | |
| 320 SkLONGLONG value = fHi; | |
| 321 value <<= 32; | |
| 322 return value | fLo; | |
| 323 } | |
| 324 #endif | |
| 325 | |
| 326 SkFixed Sk64::getFixedDiv(const Sk64& denom) const | |
| 327 { | |
| 328 Sk64 N = *this; | |
| 329 Sk64 D = denom; | |
| 330 int32_t sign = SkExtractSign(N.fHi ^ D.fHi); | |
| 331 SkFixed result; | |
| 332 | |
| 333 N.abs(); | |
| 334 D.abs(); | |
| 335 | |
| 336 // need to knock D down to just 31 bits | |
| 337 // either by rounding it to the right, or shifting N to the left | |
| 338 // then we can just call 64/32 div | |
| 339 | |
| 340 int nclz = N.fHi ? SkCLZ(N.fHi) : 32; | |
| 341 int dclz = D.fHi ? SkCLZ(D.fHi) : (33 - (D.fLo >> 31)); | |
| 342 | |
| 343 int shiftN = nclz - 1; | |
| 344 SkASSERT(shiftN >= 0); | |
| 345 int shiftD = 33 - dclz; | |
| 346 SkASSERT(shiftD >= 0); | |
| 347 | |
| 348 if (shiftD + shiftN < 16) | |
| 349 shiftD = 16 - shiftN; | |
| 350 else | |
| 351 shiftN = 16 - shiftD; | |
| 352 | |
| 353 D.roundRight(shiftD); | |
| 354 if (D.isZero()) | |
| 355 result = SK_MaxS32; | |
| 356 else | |
| 357 { | |
| 358 if (shiftN >= 0) | |
| 359 N.shiftLeft(shiftN); | |
| 360 else | |
| 361 N.roundRight(-shiftN); | |
| 362 N.div(D.get32(), Sk64::kTrunc_DivOption); | |
| 363 if (N.is32()) | |
| 364 result = N.get32(); | |
| 365 else | |
| 366 result = SK_MaxS32; | |
| 367 } | |
| 368 return SkApplySign(result, sign); | |
| 369 } | |
| 370 | |
| 371 /////////////////////////////////////////////////////////////////////// | |
| 372 | |
| 373 #ifdef SK_DEBUG | |
| 374 | |
| 375 #include "SkRandom.h" | |
| 376 #include <math.h> | |
| 377 | |
| 378 #ifdef SK_SUPPORT_UNITTEST | |
| 379 struct BoolTable { | |
| 380 int8_t zero, pos, neg, toBool, sign; | |
| 381 }; | |
| 382 | |
| 383 static void bool_table_test(const Sk64& a, const BoolTable& table) | |
| 384 { | |
| 385 SkASSERT(a.isZero() != a.nonZero()); | |
| 386 | |
| 387 SkASSERT(!a.isZero() == !table.zero); | |
| 388 SkASSERT(!a.isPos() == !table.pos); | |
| 389 SkASSERT(!a.isNeg() == !table.neg); | |
| 390 SkASSERT(a.sign() == table.sign); | |
| 391 } | |
| 392 | |
| 393 #ifdef SkLONGLONG | |
| 394 static SkLONGLONG asLL(const Sk64& a) | |
| 395 { | |
| 396 return ((SkLONGLONG)a.fHi << 32) | a.fLo; | |
| 397 } | |
| 398 #endif | |
| 399 #endif | |
| 400 | |
| 401 void Sk64::UnitTest() | |
| 402 { | |
| 403 #ifdef SK_SUPPORT_UNITTEST | |
| 404 enum BoolTests { | |
| 405 kZero_BoolTest, | |
| 406 kPos_BoolTest, | |
| 407 kNeg_BoolTest | |
| 408 }; | |
| 409 static const BoolTable gBoolTable[] = { | |
| 410 { 1, 0, 0, 0, 0 }, | |
| 411 { 0, 1, 0, 1, 1 }, | |
| 412 { 0, 0, 1, 1, -1 } | |
| 413 }; | |
| 414 | |
| 415 Sk64 a, b, c; | |
| 416 | |
| 417 a.fHi = a.fLo = 0; | |
| 418 b.set(0); | |
| 419 c.setZero(); | |
| 420 SkASSERT(a == b); | |
| 421 SkASSERT(a == c); | |
| 422 bool_table_test(a, gBoolTable[kZero_BoolTest]); | |
| 423 | |
| 424 a.fHi = 0; a.fLo = 5; | |
| 425 b.set(5); | |
| 426 SkASSERT(a == b); | |
| 427 SkASSERT(a.is32() && a.get32() == 5 && !a.is64()); | |
| 428 bool_table_test(a, gBoolTable[kPos_BoolTest]); | |
| 429 | |
| 430 a.fHi = -1; a.fLo = (uint32_t)-5; | |
| 431 b.set(-5); | |
| 432 SkASSERT(a == b); | |
| 433 SkASSERT(a.is32() && a.get32() == -5 && !a.is64()); | |
| 434 bool_table_test(a, gBoolTable[kNeg_BoolTest]); | |
| 435 | |
| 436 a.setZero(); | |
| 437 b.set(6); | |
| 438 c.set(-6); | |
| 439 SkASSERT(a != b && b != c && a != c); | |
| 440 SkASSERT(!(a == b) && !(a == b) && !(a == b)); | |
| 441 SkASSERT(a < b && b > a && a <= b && b >= a); | |
| 442 SkASSERT(c < a && a > c && c <= a && a >= c); | |
| 443 SkASSERT(c < b && b > c && c <= b && b >= c); | |
| 444 | |
| 445 // Now test add/sub | |
| 446 | |
| 447 SkRandom rand; | |
| 448 int i; | |
| 449 | |
| 450 for (i = 0; i < 1000; i++) | |
| 451 { | |
| 452 int aa = rand.nextS() >> 1; | |
| 453 int bb = rand.nextS() >> 1; | |
| 454 a.set(aa); | |
| 455 b.set(bb); | |
| 456 SkASSERT(a.get32() == aa && b.get32() == bb); | |
| 457 c = a; c.add(bb); | |
| 458 SkASSERT(c.get32() == aa + bb); | |
| 459 c = a; c.add(-bb); | |
| 460 SkASSERT(c.get32() == aa - bb); | |
| 461 c = a; c.add(b); | |
| 462 SkASSERT(c.get32() == aa + bb); | |
| 463 c = a; c.sub(b); | |
| 464 SkASSERT(c.get32() == aa - bb); | |
| 465 } | |
| 466 | |
| 467 #ifdef SkLONGLONG | |
| 468 for (i = 0; i < 1000; i++) | |
| 469 { | |
| 470 rand.next64(&a); //a.fHi >>= 1; // avoid overflow | |
| 471 rand.next64(&b); //b.fHi >>= 1; // avoid overflow | |
| 472 | |
| 473 if (!(i & 3)) // want to explicitly test these cases | |
| 474 { | |
| 475 a.fLo = 0; | |
| 476 b.fLo = 0; | |
| 477 } | |
| 478 else if (!(i & 7)) // want to explicitly test these cases | |
| 479 { | |
| 480 a.fHi = 0; | |
| 481 b.fHi = 0; | |
| 482 } | |
| 483 | |
| 484 SkLONGLONG aa = asLL(a); | |
| 485 SkLONGLONG bb = asLL(b); | |
| 486 | |
| 487 SkASSERT((a < b) == (aa < bb)); | |
| 488 SkASSERT((a <= b) == (aa <= bb)); | |
| 489 SkASSERT((a > b) == (aa > bb)); | |
| 490 SkASSERT((a >= b) == (aa >= bb)); | |
| 491 SkASSERT((a == b) == (aa == bb)); | |
| 492 SkASSERT((a != b) == (aa != bb)); | |
| 493 | |
| 494 c = a; c.add(b); | |
| 495 SkASSERT(asLL(c) == aa + bb); | |
| 496 c = a; c.sub(b); | |
| 497 SkASSERT(asLL(c) == aa - bb); | |
| 498 c = a; c.rsub(b); | |
| 499 SkASSERT(asLL(c) == bb - aa); | |
| 500 c = a; c.negate(); | |
| 501 SkASSERT(asLL(c) == -aa); | |
| 502 | |
| 503 int bits = rand.nextU() & 63; | |
| 504 c = a; c.shiftLeft(bits); | |
| 505 SkASSERT(asLL(c) == (aa << bits)); | |
| 506 c = a; c.shiftRight(bits); | |
| 507 SkASSERT(asLL(c) == (aa >> bits)); | |
| 508 c = a; c.roundRight(bits); | |
| 509 | |
| 510 SkLONGLONG tmp; | |
| 511 | |
| 512 tmp = aa; | |
| 513 if (bits > 0) | |
| 514 tmp += (SkLONGLONG)1 << (bits - 1); | |
| 515 SkASSERT(asLL(c) == (tmp >> bits)); | |
| 516 | |
| 517 c.setMul(a.fHi, b.fHi); | |
| 518 tmp = (SkLONGLONG)a.fHi * b.fHi; | |
| 519 SkASSERT(asLL(c) == tmp); | |
| 520 } | |
| 521 | |
| 522 | |
| 523 for (i = 0; i < 100000; i++) | |
| 524 { | |
| 525 Sk64 wide; | |
| 526 int32_t denom = rand.nextS(); | |
| 527 | |
| 528 while (denom == 0) | |
| 529 denom = rand.nextS(); | |
| 530 wide.setMul(rand.nextS(), rand.nextS()); | |
| 531 SkLONGLONG check = wide.getLongLong(); | |
| 532 | |
| 533 wide.div(denom, Sk64::kTrunc_DivOption); | |
| 534 check /= denom; | |
| 535 SkLONGLONG w = wide.getLongLong(); | |
| 536 | |
| 537 SkASSERT(check == w); | |
| 538 | |
| 539 #ifdef SK_CAN_USE_FLOATx | |
| 540 wide.setMul(rand.nextS(), rand.nextS()); | |
| 541 wide.abs(); | |
| 542 denom = wide.getSqrt(); | |
| 543 int32_t ck = (int32_t)sqrt((double)wide.getLongLong()); | |
| 544 int diff = denom - ck; | |
| 545 SkASSERT(SkAbs32(diff) <= 1); | |
| 546 | |
| 547 wide.setMul(rand.nextS(), rand.nextS()); | |
| 548 Sk64 dwide; | |
| 549 dwide.setMul(rand.nextS(), rand.nextS()); | |
| 550 SkFixed fixdiv = wide.getFixedDiv(dwide); | |
| 551 double dnumer = (double)wide.getLongLong(); | |
| 552 double ddenom = (double)dwide.getLongLong(); | |
| 553 double ddiv = dnumer / ddenom; | |
| 554 SkFixed dfixdiv; | |
| 555 if (ddiv >= (double)SK_MaxS32 / (double)SK_Fixed1) | |
| 556 dfixdiv = SK_MaxS32; | |
| 557 else if (ddiv <= -(double)SK_MaxS32 / (double)SK_Fixed1) | |
| 558 dfixdiv = SK_MinS32; | |
| 559 else | |
| 560 dfixdiv = SkFloatToFixed(dnumer / ddenom); | |
| 561 diff = fixdiv - dfixdiv; | |
| 562 | |
| 563 if (SkAbs32(diff) > 1) { | |
| 564 SkDebugf(" %d === numer %g denom %g div %g xdiv %x fxdiv %x\n", | |
| 565 i, dnumer, ddenom, ddiv, dfixdiv, fixdiv); | |
| 566 } | |
| 567 // SkASSERT(SkAbs32(diff) <= 1); | |
| 568 #endif | |
| 569 } | |
| 570 #endif | |
| 571 #endif | |
| 572 } | |
| 573 | |
| 574 #endif | |
| 575 | |
| OLD | NEW |