1 /* 2 * Copyright 2008 The Android Open Source Project 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 "SkMathPriv.h" 9 #include "SkFloatBits.h" 10 #include "SkFloatingPoint.h" 11 #include "SkScalar.h" 12 13 const uint32_t gIEEENotANumber = 0x7FFFFFFF; 14 const uint32_t gIEEEInfinity = 0x7F800000; 15 const uint32_t gIEEENegativeInfinity = 0xFF800000; 16 17 #define sub_shift(zeros, x, n) \ 18 zeros -= n; \ 19 x >>= n 20 21 int SkCLZ_portable(uint32_t x) { 22 if (x == 0) { 23 return 32; 24 } 25 26 int zeros = 31; 27 if (x & 0xFFFF0000) { 28 sub_shift(zeros, x, 16); 29 } 30 if (x & 0xFF00) { 31 sub_shift(zeros, x, 8); 32 } 33 if (x & 0xF0) { 34 sub_shift(zeros, x, 4); 35 } 36 if (x & 0xC) { 37 sub_shift(zeros, x, 2); 38 } 39 if (x & 0x2) { 40 sub_shift(zeros, x, 1); 41 } 42 43 return zeros; 44 } 45 46 /////////////////////////////////////////////////////////////////////////////// 47 48 #define DIVBITS_ITER(n) \ 49 case n: \ 50 if ((numer = (numer << 1) - denom) >= 0) \ 51 result |= 1 << (n - 1); else numer += denom 52 53 int32_t SkDivBits(int32_t numer, int32_t denom, int shift_bias) { 54 SkASSERT(denom != 0); 55 if (numer == 0) { 56 return 0; 57 } 58 59 // make numer and denom positive, and sign hold the resulting sign 60 int32_t sign = SkExtractSign(numer ^ denom); 61 numer = SkAbs32(numer); 62 denom = SkAbs32(denom); 63 64 int nbits = SkCLZ(numer) - 1; 65 int dbits = SkCLZ(denom) - 1; 66 int bits = shift_bias - nbits + dbits; 67 68 if (bits < 0) { // answer will underflow 69 return 0; 70 } 71 if (bits > 31) { // answer will overflow 72 return SkApplySign(SK_MaxS32, sign); 73 } 74 75 denom <<= dbits; 76 numer <<= nbits; 77 78 SkFixed result = 0; 79 80 // do the first one 81 if ((numer -= denom) >= 0) { 82 result = 1; 83 } else { 84 numer += denom; 85 } 86 87 // Now fall into our switch statement if there are more bits to compute 88 if (bits > 0) { 89 // make room for the rest of the answer bits 90 result <<= bits; 91 switch (bits) { 92 DIVBITS_ITER(31); DIVBITS_ITER(30); DIVBITS_ITER(29); 93 DIVBITS_ITER(28); DIVBITS_ITER(27); DIVBITS_ITER(26); 94 DIVBITS_ITER(25); DIVBITS_ITER(24); DIVBITS_ITER(23); 95 DIVBITS_ITER(22); DIVBITS_ITER(21); DIVBITS_ITER(20); 96 DIVBITS_ITER(19); DIVBITS_ITER(18); DIVBITS_ITER(17); 97 DIVBITS_ITER(16); DIVBITS_ITER(15); DIVBITS_ITER(14); 98 DIVBITS_ITER(13); DIVBITS_ITER(12); DIVBITS_ITER(11); 99 DIVBITS_ITER(10); DIVBITS_ITER( 9); DIVBITS_ITER( 8); 100 DIVBITS_ITER( 7); DIVBITS_ITER( 6); DIVBITS_ITER( 5); 101 DIVBITS_ITER( 4); DIVBITS_ITER( 3); DIVBITS_ITER( 2); 102 // we merge these last two together, makes GCC make better ARM 103 default: 104 DIVBITS_ITER( 1); 105 } 106 } 107 108 if (result < 0) { 109 result = SK_MaxS32; 110 } 111 return SkApplySign(result, sign); 112 } 113 114 /* www.worldserver.com/turk/computergraphics/FixedSqrt.pdf 115 */ 116 int32_t SkSqrtBits(int32_t x, int count) { 117 SkASSERT(x >= 0 && count > 0 && (unsigned)count <= 30); 118 119 uint32_t root = 0; 120 uint32_t remHi = 0; 121 uint32_t remLo = x; 122 123 do { 124 root <<= 1; 125 126 remHi = (remHi<<2) | (remLo>>30); 127 remLo <<= 2; 128 129 uint32_t testDiv = (root << 1) + 1; 130 if (remHi >= testDiv) { 131 remHi -= testDiv; 132 root++; 133 } 134 } while (--count >= 0); 135 136 return root; 137 } 138 139 /////////////////////////////////////////////////////////////////////////////// 140 141 float SkScalarSinCos(float radians, float* cosValue) { 142 float sinValue = sk_float_sin(radians); 143 144 if (cosValue) { 145 *cosValue = sk_float_cos(radians); 146 if (SkScalarNearlyZero(*cosValue)) { 147 *cosValue = 0; 148 } 149 } 150 151 if (SkScalarNearlyZero(sinValue)) { 152 sinValue = 0; 153 } 154 return sinValue; 155 } 156