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 |