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