| OLD | NEW |
| (Empty) |
| 1 /* libs/corecg/SkCordic.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 "SkCordic.h" | |
| 19 #include "SkMath.h" | |
| 20 #include "Sk64.h" | |
| 21 | |
| 22 // 0x20000000 equals pi / 4 | |
| 23 const int32_t kATanDegrees[] = { 0x20000000, | |
| 24 0x12E4051D, 0x9FB385B, 0x51111D4, 0x28B0D43, 0x145D7E1, 0xA2F61E, 0x517C55, | |
| 25 0x28BE53, 0x145F2E, 0xA2F98, 0x517CC, 0x28BE6, 0x145F3, 0xA2F9, 0x517C, | |
| 26 0x28BE, 0x145F, 0xA2F, 0x517, 0x28B, 0x145, 0xA2, 0x51, 0x28, 0x14, | |
| 27 0xA, 0x5, 0x2, 0x1 }; | |
| 28 | |
| 29 const int32_t kFixedInvGain1 = 0x18bde0bb; // 0.607252935 | |
| 30 | |
| 31 static void SkCircularRotation(int32_t* x0, int32_t* y0, int32_t* z0) | |
| 32 { | |
| 33 int32_t t = 0; | |
| 34 int32_t x = *x0; | |
| 35 int32_t y = *y0; | |
| 36 int32_t z = *z0; | |
| 37 const int32_t* tanPtr = kATanDegrees; | |
| 38 do { | |
| 39 int32_t x1 = y >> t; | |
| 40 int32_t y1 = x >> t; | |
| 41 int32_t tan = *tanPtr++; | |
| 42 if (z >= 0) { | |
| 43 x -= x1; | |
| 44 y += y1; | |
| 45 z -= tan; | |
| 46 } else { | |
| 47 x += x1; | |
| 48 y -= y1; | |
| 49 z += tan; | |
| 50 } | |
| 51 } while (++t < 16); // 30); | |
| 52 *x0 = x; | |
| 53 *y0 = y; | |
| 54 *z0 = z; | |
| 55 } | |
| 56 | |
| 57 SkFixed SkCordicSinCos(SkFixed radians, SkFixed* cosp) | |
| 58 { | |
| 59 int32_t scaledRadians = radians * 0x28be; // scale radians to 65536 / PI() | |
| 60 int quadrant = scaledRadians >> 30; | |
| 61 quadrant += 1; | |
| 62 if (quadrant & 2) | |
| 63 scaledRadians = -scaledRadians + 0x80000000; | |
| 64 /* |a| <= 90 degrees as a 1.31 number */ | |
| 65 SkFixed sin = 0; | |
| 66 SkFixed cos = kFixedInvGain1; | |
| 67 SkCircularRotation(&cos, &sin, &scaledRadians); | |
| 68 Sk64 scaled; | |
| 69 scaled.setMul(sin, 0x6488d); | |
| 70 sin = scaled.fHi; | |
| 71 scaled.setMul(cos, 0x6488d); | |
| 72 if (quadrant & 2) | |
| 73 scaled.fHi = - scaled.fHi; | |
| 74 *cosp = scaled.fHi; | |
| 75 return sin; | |
| 76 } | |
| 77 | |
| 78 SkFixed SkCordicTan(SkFixed a) | |
| 79 { | |
| 80 int32_t cos; | |
| 81 int32_t sin = SkCordicSinCos(a, &cos); | |
| 82 return SkFixedDiv(sin, cos); | |
| 83 } | |
| 84 | |
| 85 static int32_t SkCircularVector(int32_t* y0, int32_t* x0, int32_t vecMode) | |
| 86 { | |
| 87 int32_t x = *x0; | |
| 88 int32_t y = *y0; | |
| 89 int32_t z = 0; | |
| 90 int32_t t = 0; | |
| 91 const int32_t* tanPtr = kATanDegrees; | |
| 92 do { | |
| 93 int32_t x1 = y >> t; | |
| 94 int32_t y1 = x >> t; | |
| 95 int32_t tan = *tanPtr++; | |
| 96 if (y < vecMode) { | |
| 97 x -= x1; | |
| 98 y += y1; | |
| 99 z -= tan; | |
| 100 } else { | |
| 101 x += x1; | |
| 102 y -= y1; | |
| 103 z += tan; | |
| 104 } | |
| 105 } while (++t < 16); // 30 | |
| 106 Sk64 scaled; | |
| 107 scaled.setMul(z, 0x6488d); // scale back into the SkScalar space (0x10000000
0/0x28be) | |
| 108 return scaled.fHi; | |
| 109 } | |
| 110 | |
| 111 SkFixed SkCordicASin(SkFixed a) { | |
| 112 int32_t sign = SkExtractSign(a); | |
| 113 int32_t z = SkFixedAbs(a); | |
| 114 if (z >= SK_Fixed1) | |
| 115 return SkApplySign(SK_FixedPI>>1, sign); | |
| 116 int32_t x = kFixedInvGain1; | |
| 117 int32_t y = 0; | |
| 118 z *= 0x28be; | |
| 119 z = SkCircularVector(&y, &x, z); | |
| 120 z = SkApplySign(z, ~sign); | |
| 121 return z; | |
| 122 } | |
| 123 | |
| 124 SkFixed SkCordicACos(SkFixed a) { | |
| 125 int32_t z = SkCordicASin(a); | |
| 126 z = (SK_FixedPI>>1) - z; | |
| 127 return z; | |
| 128 } | |
| 129 | |
| 130 SkFixed SkCordicATan2(SkFixed y, SkFixed x) { | |
| 131 if ((x | y) == 0) | |
| 132 return 0; | |
| 133 int32_t xsign = SkExtractSign(x); | |
| 134 x = SkFixedAbs(x); | |
| 135 int32_t result = SkCircularVector(&y, &x, 0); | |
| 136 if (xsign) { | |
| 137 int32_t rsign = SkExtractSign(result); | |
| 138 if (y == 0) | |
| 139 rsign = 0; | |
| 140 SkFixed pi = SkApplySign(SK_FixedPI, rsign); | |
| 141 result = pi - result; | |
| 142 } | |
| 143 return result; | |
| 144 } | |
| 145 | |
| 146 const int32_t kATanHDegrees[] = { | |
| 147 0x1661788D, 0xA680D61, 0x51EA6FC, 0x28CBFDD, 0x1460E34, | |
| 148 0xA2FCE8, 0x517D2E, 0x28BE6E, 0x145F32, | |
| 149 0xA2F98, 0x517CC, 0x28BE6, 0x145F3, 0xA2F9, 0x517C, | |
| 150 0x28BE, 0x145F, 0xA2F, 0x517, 0x28B, 0x145, 0xA2, 0x51, 0x28, 0x14, | |
| 151 0xA, 0x5, 0x2, 0x1 }; | |
| 152 | |
| 153 const int32_t kFixedInvGain2 = 0x31330AAA; // 1.207534495 | |
| 154 | |
| 155 static void SkHyperbolic(int32_t* x0, int32_t* y0, int32_t* z0, int mode) | |
| 156 { | |
| 157 int32_t t = 1; | |
| 158 int32_t x = *x0; | |
| 159 int32_t y = *y0; | |
| 160 int32_t z = *z0; | |
| 161 const int32_t* tanPtr = kATanHDegrees; | |
| 162 int k = -3; | |
| 163 do { | |
| 164 int32_t x1 = y >> t; | |
| 165 int32_t y1 = x >> t; | |
| 166 int32_t tan = *tanPtr++; | |
| 167 int count = 2 + (k >> 31); | |
| 168 if (++k == 1) | |
| 169 k = -2; | |
| 170 do { | |
| 171 if (((y >> 31) & mode) | ~((z >> 31) | mode)) { | |
| 172 x += x1; | |
| 173 y += y1; | |
| 174 z -= tan; | |
| 175 } else { | |
| 176 x -= x1; | |
| 177 y -= y1; | |
| 178 z += tan; | |
| 179 } | |
| 180 } while (--count); | |
| 181 } while (++t < 30); | |
| 182 *x0 = x; | |
| 183 *y0 = y; | |
| 184 *z0 = z; | |
| 185 } | |
| 186 | |
| 187 SkFixed SkCordicLog(SkFixed a) { | |
| 188 a *= 0x28be; | |
| 189 int32_t x = a + 0x28BE60DB; // 1.0 | |
| 190 int32_t y = a - 0x28BE60DB; | |
| 191 int32_t z = 0; | |
| 192 SkHyperbolic(&x, &y, &z, -1); | |
| 193 Sk64 scaled; | |
| 194 scaled.setMul(z, 0x6488d); | |
| 195 z = scaled.fHi; | |
| 196 return z << 1; | |
| 197 } | |
| 198 | |
| 199 SkFixed SkCordicExp(SkFixed a) { | |
| 200 int32_t cosh = kFixedInvGain2; | |
| 201 int32_t sinh = 0; | |
| 202 SkHyperbolic(&cosh, &sinh, &a, 0); | |
| 203 return cosh + sinh; | |
| 204 } | |
| 205 | |
| 206 #ifdef SK_DEBUG | |
| 207 | |
| 208 #ifdef SK_CAN_USE_FLOAT | |
| 209 #include "SkFloatingPoint.h" | |
| 210 #endif | |
| 211 | |
| 212 void SkCordic_UnitTest() | |
| 213 { | |
| 214 #if defined(SK_SUPPORT_UNITTEST) && defined(SK_CAN_USE_FLOAT) | |
| 215 float val; | |
| 216 for (float angle = -720; angle < 720; angle += 30) { | |
| 217 float radian = angle * 3.1415925358f / 180.0f; | |
| 218 SkFixed f_angle = (int) (radian * 65536.0f); | |
| 219 // sincos | |
| 220 float sine = sinf(radian); | |
| 221 float cosine = cosf(radian); | |
| 222 SkFixed f_cosine; | |
| 223 SkFixed f_sine = SkCordicSinCos(f_angle, &f_cosine); | |
| 224 float sine2 = (float) f_sine / 65536.0f; | |
| 225 float cosine2 = (float) f_cosine / 65536.0f; | |
| 226 float error = fabsf(sine - sine2); | |
| 227 if (error > 0.001) | |
| 228 SkDebugf("sin error : angle = %g ; sin = %g ; cordic = %g\n", angle,
sine, sine2); | |
| 229 error = fabsf(cosine - cosine2); | |
| 230 if (error > 0.001) | |
| 231 SkDebugf("cos error : angle = %g ; cos = %g ; cordic = %g\n", angle,
cosine, cosine2); | |
| 232 // tan | |
| 233 float _tan = tanf(radian); | |
| 234 SkFixed f_tan = SkCordicTan(f_angle); | |
| 235 float tan2 = (float) f_tan / 65536.0f; | |
| 236 error = fabsf(_tan - tan2); | |
| 237 if (error > 0.05 && fabsf(_tan) < 1e6) | |
| 238 SkDebugf("tan error : angle = %g ; tan = %g ; cordic = %g\n", angle,
_tan, tan2); | |
| 239 } | |
| 240 for (val = -1; val <= 1; val += .1f) { | |
| 241 SkFixed f_val = (int) (val * 65536.0f); | |
| 242 // asin | |
| 243 float arcsine = asinf(val); | |
| 244 SkFixed f_arcsine = SkCordicASin(f_val); | |
| 245 float arcsine2 = (float) f_arcsine / 65536.0f; | |
| 246 float error = fabsf(arcsine - arcsine2); | |
| 247 if (error > 0.001) | |
| 248 SkDebugf("asin error : val = %g ; asin = %g ; cordic = %g\n", val, a
rcsine, arcsine2); | |
| 249 } | |
| 250 #if 1 | |
| 251 for (val = -1; val <= 1; val += .1f) { | |
| 252 #else | |
| 253 val = .5; { | |
| 254 #endif | |
| 255 SkFixed f_val = (int) (val * 65536.0f); | |
| 256 // acos | |
| 257 float arccos = acosf(val); | |
| 258 SkFixed f_arccos = SkCordicACos(f_val); | |
| 259 float arccos2 = (float) f_arccos / 65536.0f; | |
| 260 float error = fabsf(arccos - arccos2); | |
| 261 if (error > 0.001) | |
| 262 SkDebugf("acos error : val = %g ; acos = %g ; cordic = %g\n", val, a
rccos, arccos2); | |
| 263 } | |
| 264 // atan2 | |
| 265 #if 1 | |
| 266 for (val = -1000; val <= 1000; val += 500.f) { | |
| 267 for (float val2 = -1000; val2 <= 1000; val2 += 500.f) { | |
| 268 #else | |
| 269 val = 0; { | |
| 270 float val2 = -1000; { | |
| 271 #endif | |
| 272 SkFixed f_val = (int) (val * 65536.0f); | |
| 273 SkFixed f_val2 = (int) (val2 * 65536.0f); | |
| 274 float arctan = atan2f(val, val2); | |
| 275 SkFixed f_arctan = SkCordicATan2(f_val, f_val2); | |
| 276 float arctan2 = (float) f_arctan / 65536.0f; | |
| 277 float error = fabsf(arctan - arctan2); | |
| 278 if (error > 0.001) | |
| 279 SkDebugf("atan2 error : val = %g ; val2 = %g ; atan2 = %g ; cord
ic = %g\n", val, val2, arctan, arctan2); | |
| 280 } | |
| 281 } | |
| 282 // log | |
| 283 #if 1 | |
| 284 for (val = 0.125f; val <= 8.f; val *= 2.0f) { | |
| 285 #else | |
| 286 val = .5; { | |
| 287 #endif | |
| 288 SkFixed f_val = (int) (val * 65536.0f); | |
| 289 // acos | |
| 290 float log = logf(val); | |
| 291 SkFixed f_log = SkCordicLog(f_val); | |
| 292 float log2 = (float) f_log / 65536.0f; | |
| 293 float error = fabsf(log - log2); | |
| 294 if (error > 0.001) | |
| 295 SkDebugf("log error : val = %g ; log = %g ; cordic = %g\n", val, log
, log2); | |
| 296 } | |
| 297 // exp | |
| 298 #endif | |
| 299 } | |
| 300 | |
| 301 #endif | |
| OLD | NEW |