|
1 // Copyright (c) 1995-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
2 // All rights reserved. |
|
3 // This component and the accompanying materials are made available |
|
4 // under the terms of the License "Eclipse Public License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // e32\euser\maths\um_atan.cpp |
|
15 // Floating point arc tangent |
|
16 // |
|
17 // |
|
18 |
|
19 #include "um_std.h" |
|
20 |
|
21 #if defined(__USE_VFP_MATH) && !defined(__CPU_HAS_VFP) |
|
22 #error __USE_VFP_MATH was defined but not __CPU_HAS_VFP - impossible combination, check variant.mmh |
|
23 #endif |
|
24 |
|
25 #ifndef __USE_VFP_MATH |
|
26 |
|
27 LOCAL_D const TUint32 ArctanCoeffs[] = |
|
28 { |
|
29 0x00000000,0x80000000,0x7FFF0000, // polynomial approximation to arctan(x) |
|
30 0xAA84D6EE,0xAAAAAAAA,0x7FFD0001, // for -(sqr2-1) <= x <= (sqr2-1) |
|
31 0x89C77453,0xCCCCCCCC,0x7FFC0000, |
|
32 0xEBC0261C,0x9249247B,0x7FFC0001, |
|
33 0x940BC4DB,0xE38E3121,0x7FFB0000, |
|
34 0x141C32F1,0xBA2DBF36,0x7FFB0001, |
|
35 0xA90615E7,0x9D7C807E,0x7FFB0000, |
|
36 0x1C632E93,0x87F6A873,0x7FFB0001, |
|
37 0x310FCFFD,0xE8BE5D0A,0x7FFA0000, |
|
38 0x92289F15,0xB17B930B,0x7FFA0001, |
|
39 0x546FE7CE,0xABDE562D,0x7FF90000 |
|
40 }; |
|
41 |
|
42 LOCAL_D const TUint32 Sqr2m1data[] = {0xE7799211,0xD413CCCF,0x7FFD0000}; // sqr2-1 |
|
43 LOCAL_D const TUint32 Sqr2p1data[] = {0xFCEF3242,0x9A827999,0x80000000}; // sqr2+1 |
|
44 LOCAL_D const TUint32 Onedata[] = {0x00000000,0x80000000,0x7FFF0000}; // 1.0 |
|
45 LOCAL_D const TUint32 PiBy8data[] = {0x2168C235,0xC90FDAA2,0x7FFD0000}; // pi/8 |
|
46 LOCAL_D const TUint32 PiBy2data[] = {0x2168C235,0xC90FDAA2,0x7FFF0000}; // pi/2 |
|
47 LOCAL_D const TUint32 ThreePiBy8data[] = {0x990E91A8,0x96CBE3F9,0x7FFF0000}; // 3*pi/8 |
|
48 |
|
49 LOCAL_C void Arctan(TRealX& y, TRealX& x) |
|
50 { |
|
51 // Calculate arctan(x), write result to y |
|
52 // Algorithm: |
|
53 // If x>1, replace x with 1/x and subtract result from pi/2 |
|
54 // ( use identity tan(pi/2-x)=1/tan(x) ) |
|
55 // If x>sqr(2)-1, replace x with (x-(sqr(2)-1))/(1-(sqr2-1)x) |
|
56 // ( use identity tan(x-a)=(tanx-tana)/(1-tana.tanx) |
|
57 // where a=pi/8, tan a = sqr2-1 |
|
58 // and add pi/8 to result |
|
59 // Use polynomial approximation to calculate arctan(x) for |
|
60 // x in the interval [0,sqr2-1] |
|
61 |
|
62 const TRealX& Sqr2m1 = *(const TRealX*)Sqr2m1data; |
|
63 const TRealX& Sqr2p1 = *(const TRealX*)Sqr2p1data; |
|
64 const TRealX& One = *(const TRealX*)Onedata; |
|
65 const TRealX& PiBy8 = *(const TRealX*)PiBy8data; |
|
66 const TRealX& PiBy2 = *(const TRealX*)PiBy2data; |
|
67 const TRealX& ThreePiBy8 = *(const TRealX*)ThreePiBy8data; |
|
68 |
|
69 TInt section=0; |
|
70 TInt8 sign=x.iSign; |
|
71 x.iSign=0; |
|
72 if (x>Sqr2p1) |
|
73 { |
|
74 x=One/x; |
|
75 section=3; |
|
76 } |
|
77 else if (x>One) |
|
78 { |
|
79 x=(One-Sqr2m1*x)/(x+Sqr2m1); |
|
80 section=2; |
|
81 } |
|
82 else if (x>Sqr2m1) |
|
83 { |
|
84 x=(x-Sqr2m1)/(One+Sqr2m1*x); |
|
85 section=1; |
|
86 } |
|
87 Math::PolyX(y,x*x,10,(const TRealX*)ArctanCoeffs); |
|
88 y*=x; |
|
89 if (section==1) |
|
90 y+=PiBy8; |
|
91 else if (section==2) |
|
92 y=ThreePiBy8-y; |
|
93 else if (section==3) |
|
94 y=PiBy2-y; |
|
95 y.iSign=sign; |
|
96 } |
|
97 |
|
98 |
|
99 |
|
100 |
|
101 EXPORT_C TInt Math::ATan(TReal& aTrg, const TReal& aSrc) |
|
102 /** |
|
103 Calculates the principal value of the inverse tangent of a number. |
|
104 |
|
105 @param aTrg A reference containing the result in radians, |
|
106 a value between -pi/2 and +pi/2. |
|
107 @param aSrc The argument of the arctan function, |
|
108 a value between +infinity and +infinity. |
|
109 |
|
110 @return KErrNone if successful, otherwise another of |
|
111 the system-wide error codes. |
|
112 */ |
|
113 { |
|
114 TRealX x; |
|
115 TInt r=x.Set(aSrc); |
|
116 if (r==KErrNone) |
|
117 { |
|
118 TRealX y; |
|
119 Arctan(y,x); |
|
120 return y.GetTReal(aTrg); |
|
121 } |
|
122 if (r==KErrArgument) |
|
123 { |
|
124 SetNaN(aTrg); |
|
125 return KErrArgument; |
|
126 } |
|
127 aTrg=KPiBy2; // arctan(+/- infinity) = +/- pi/2 |
|
128 if (x.iSign&1) |
|
129 aTrg=-aTrg; |
|
130 return KErrNone; |
|
131 } |
|
132 |
|
133 LOCAL_D const TUint32 Pidata[] = {0x2168C235,0xC90FDAA2,0x80000000}; |
|
134 LOCAL_D const TUint32 PiBy4data[] = {0x2168C235,0xC90FDAA2,0x7FFE0000}; |
|
135 LOCAL_D const TUint32 MinusPiBy4data[] = {0x2168C235,0xC90FDAA2,0x7FFE0001}; |
|
136 LOCAL_D const TUint32 ThreePiBy4data[] = {0x990E91A8,0x96CBE3F9,0x80000000}; |
|
137 LOCAL_D const TUint32 MinusThreePiBy4data[] = {0x990E91A8,0x96CBE3F9,0x80000001}; |
|
138 LOCAL_D const TUint32 Zerodata[] = {0x00000000,0x00000000,0x00000000}; |
|
139 |
|
140 |
|
141 |
|
142 |
|
143 EXPORT_C TInt Math::ATan(TReal &aTrg,const TReal &aY,const TReal &aX) |
|
144 /** |
|
145 Calculates the angle between the x-axis and a line drawn from the origin |
|
146 to a point represented by its (x,y) co-ordinates. |
|
147 |
|
148 The co-ordinates are passed as arguments to the function. |
|
149 This function returns the same result as arctan(y/x), but: |
|
150 |
|
151 1. it adds +/-pi to the result, if x is negative |
|
152 |
|
153 2. it sets the result to +/-pi/2, if x is zero but y is non-zero. |
|
154 |
|
155 @param aTrg A reference containing the result in radians, |
|
156 a value between -pi exclusive and +pi inclusive. |
|
157 @param aY The y argument of the arctan(y/x) function. |
|
158 @param aX The x argument of the arctan(y/x) function. |
|
159 |
|
160 @return KErrNone if successful, otherwise another of |
|
161 the system-wide error codes. |
|
162 */ |
|
163 { |
|
164 const TRealX& Zero=*(const TRealX*)Zerodata; |
|
165 const TRealX& Pi=*(const TRealX*)Pidata; |
|
166 const TRealX& PiBy4=*(const TRealX*)PiBy4data; |
|
167 const TRealX& MinusPiBy4=*(const TRealX*)MinusPiBy4data; |
|
168 const TRealX& ThreePiBy4=*(const TRealX*)ThreePiBy4data; |
|
169 const TRealX& MinusThreePiBy4=*(const TRealX*)MinusThreePiBy4data; |
|
170 |
|
171 TRealX x, y; |
|
172 TInt rx=x.Set(aX); |
|
173 TInt ry=y.Set(aY); |
|
174 if (rx!=KErrArgument && ry!=KErrArgument) |
|
175 { |
|
176 if (x.iExp==0) |
|
177 x.iSign=0; |
|
178 TRealX q; |
|
179 TInt rq=y.Div(q,x); |
|
180 if (rq!=KErrArgument) |
|
181 { |
|
182 TRealX arg; |
|
183 Arctan(arg,q); |
|
184 if (x<Zero) |
|
185 { |
|
186 if (y>=Zero) |
|
187 arg+=Pi; |
|
188 else |
|
189 arg-=Pi; |
|
190 } |
|
191 aTrg=arg; |
|
192 return KErrNone; |
|
193 } |
|
194 if (!x.IsZero()) |
|
195 { |
|
196 // Both x and y must be infinite |
|
197 TInt quadrant=((y.iSign & 1)<<1) + (x.iSign&1); |
|
198 TRealX arg; |
|
199 if (quadrant==0) |
|
200 arg=PiBy4; |
|
201 else if (quadrant==1) |
|
202 arg=ThreePiBy4; |
|
203 else if (quadrant==3) |
|
204 arg=MinusThreePiBy4; |
|
205 else |
|
206 arg=MinusPiBy4; |
|
207 aTrg=(TReal)arg; |
|
208 return KErrNone; |
|
209 } |
|
210 } |
|
211 SetNaN(aTrg); |
|
212 return KErrArgument; |
|
213 } |
|
214 |
|
215 #else // __USE_VFP_MATH |
|
216 |
|
217 LOCAL_D const TUint32 PiBy4data[] = {0x54442D18,0x3FE921FB}; |
|
218 LOCAL_D const TUint32 MinusPiBy4data[] = {0x54442D18,0xBFE921FB}; |
|
219 LOCAL_D const TUint32 ThreePiBy4data[] = {0x7F3321D2,0x4002D97C}; |
|
220 LOCAL_D const TUint32 MinusThreePiBy4data[] = {0x7F3321D2,0xC002D97C}; |
|
221 |
|
222 // definitions come from RVCT math library |
|
223 extern "C" TReal atan(TReal); |
|
224 extern "C" TReal atan2(TReal,TReal); |
|
225 |
|
226 EXPORT_C TInt Math::ATan(TReal& aTrg, const TReal& aSrc) |
|
227 { |
|
228 aTrg = atan(aSrc); |
|
229 if (Math::IsFinite(aTrg)) |
|
230 return KErrNone; |
|
231 SetNaN(aTrg); |
|
232 return KErrArgument; |
|
233 } |
|
234 |
|
235 EXPORT_C TInt Math::ATan(TReal &aTrg,const TReal &aY,const TReal &aX) |
|
236 { |
|
237 aTrg = atan2(aY,aX); |
|
238 if (Math::IsFinite(aTrg)) |
|
239 return KErrNone; |
|
240 |
|
241 // Return is a NaN, but ARM implementation returns NaN for atan(inf/inf) |
|
242 // whereas implementation above returns multiples of pi/4 - fix up here |
|
243 SReal64 *pY=(SReal64 *)&aY; |
|
244 SReal64 *pX=(SReal64 *)&aX; |
|
245 |
|
246 if ( pY->msm==0 && pY->lsm==0 && pY->exp==KTReal64SpecialExponent |
|
247 && pX->msm==0 && pX->lsm==0 && pX->exp==KTReal64SpecialExponent) |
|
248 { |
|
249 TInt quadrant=((pY->sign)<<1) + (pX->sign); |
|
250 if (quadrant==0) |
|
251 aTrg=*(const TReal*)PiBy4data; |
|
252 else if (quadrant==1) |
|
253 aTrg=*(const TReal*)ThreePiBy4data; |
|
254 else if (quadrant==3) |
|
255 aTrg=*(const TReal*)MinusThreePiBy4data; |
|
256 else |
|
257 aTrg=*(const TReal*)MinusPiBy4data; |
|
258 return KErrNone; |
|
259 } |
|
260 |
|
261 // If we get here then the args weren't inf/inf so one of them must've |
|
262 // been a NaN to start with |
|
263 SetNaN(aTrg); |
|
264 return KErrArgument; |
|
265 } |
|
266 |
|
267 #endif |