kernel/eka/euser/maths/um_atan.cpp
changeset 9 96e5fb8b040d
equal deleted inserted replaced
-1:000000000000 9:96e5fb8b040d
       
     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