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