First public contribution.
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".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
14 // e32\euser\maths\um_pow.cpp
15 // Raise to the power.
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
26 #ifndef __USE_VFP_MATH
28 LOCAL_D const TUint32 ArtanhCoeffs[] =
30 0x5C17F0BC,0xB8AA3B29,0x80010000, // polynomial approximation to (4/ln2)artanh(x)
31 0xD01FDDD8,0xF6384EE1,0x7FFF0000, // for |x| <= (sqr2-1)/(sqr2+1)
32 0x7D0DDC69,0x93BB6287,0x7FFF0000,
33 0x6564D4F5,0xD30BB153,0x7FFE0000,
34 0x1546C858,0xA4258A33,0x7FFE0000,
35 0xCCE50DA9,0x864D28DF,0x7FFE0000,
36 0x8E1A5DBB,0xE35271A0,0x7FFD0000,
37 0xF5A67D92,0xC3A36B08,0x7FFD0000,
38 0x62D53E02,0xC4A1FFAC,0x7FFD0000
41 LOCAL_D const TUint32 TwoToxCoeffs[] =
43 0x00000000,0x80000000,0x7FFF0000, // polynomial approximation to 2^(x/8) for
44 0xD1CF79AC,0xB17217F7,0x7FFB0000, // 0<=x<=1
45 0x162CF72B,0xF5FDEFFC,0x7FF60000,
46 0x23EC0D04,0xE35846B8,0x7FF10000,
47 0xBDB408D7,0x9D955B7E,0x7FEC0000,
48 0xFDD8A678,0xAEC3FE73,0x7FE60000,
49 0xBD6E3950,0xA184E90A,0x7FE00000,
50 0xC1054DA3,0xFFB259D8,0x7FD90000,
51 0x70893DE4,0xB8BEDE2F,0x7FD30000
54 LOCAL_D const TUint32 TwoToNover8[] =
56 0xEA8BD6E7,0x8B95C1E3,0x7FFF0000, // 2^0.125
57 0x8DB8A96F,0x9837F051,0x7FFF0000, // 2^0.250
58 0xB15138EA,0xA5FED6A9,0x7FFF0000, // 2^0.375
59 0xF9DE6484,0xB504F333,0x7FFF0000, // 2^0.500
60 0x5506DADD,0xC5672A11,0x7FFF0000, // 2^0.625
61 0xD69D6AF4,0xD744FCCA,0x7FFF0000, // 2^0.750
62 0xDD24392F,0xEAC0C6E7,0x7FFF0000 // 2^0.875
65 LOCAL_D const TUint32 Sqr2data[] = {0xF9DE6484,0xB504F333,0x7FFF0000}; // sqr2
66 LOCAL_D const TUint32 Sqr2Invdata[] = {0xF9DE6484,0xB504F333,0x7FFE0000}; // 1/sqr2
67 LOCAL_D const TUint32 Onedata[] = {0x00000000,0x80000000,0x7FFF0000}; // 1.0
69 LOCAL_C void Log2(TRealX& y, TRealX& x)
71 // Calculate log2(x) and write to y
72 // Result to 64-bit precision to allow accurate powers
74 // log2(aSrc)=log2(2^e.m) e=exponent of aSrc, m=mantissa 1<=m<2
75 // log2(aSrc)=e+log2(m)
76 // If e=-1 (0.5<=aSrc<1), let x=aSrc else let x=mantissa(aSrc)
77 // If x>Sqr2, replace x with x/Sqr2
78 // If x<Sqr2/2, replace x with x*Sqr2
79 // Replace x with (x-1)/(x+1)
80 // Use polynomial to calculate artanh(x) for |x| <= (sqr2-1)/(sqr2+1)
81 // ( use identity ln(x) = 2artanh((x-1)/(x+1)) )
83 const TRealX& Sqr2=*(const TRealX*)Sqr2data;
84 const TRealX& Sqr2Inv=*(const TRealX*)Sqr2Invdata;
85 const TRealX& One=*(const TRealX*)Onedata;
87 TInt n=(x.iExp-0x7FFF)<<1;
107 x=(x-One)/(x+One); // ln(x)=2artanh((x-1)/(x+1))
108 Math::PolyX(y,x*x,8,(const TRealX*)ArtanhCoeffs);
117 LOCAL_C TInt TwoTox(TRealX& y, TRealX& x)
119 // Calculate 2^x and write result to y. Result to 64 bit precision.
121 // 2^x = 2^int(x).2^frac(x)
122 // 2^int(x) just adds int(x) to the final result exponent
123 // Reduce frac(x) to the range [0,0.125] (modulo 0.125)
124 // Use polynomial to calculate 2^x for 0<=x<=0.125
125 // Multiply by 2^(n/8) for n=0,1,2,3,4,5,6,7 to give 2^frac(x)
130 if (n<16384 && n>-16384)
135 Math::PolyX(y,x,8,(const TRealX*)TwoToxCoeffs);
136 y.iExp=TUint16(TInt(y.iExp)+(n>>3));
139 y*= (*(const TRealX*)(TwoToNover8+3*n-3));
147 return KErrUnderflow;
160 EXPORT_C TInt Math::Pow(TReal &aTrg,const TReal &aSrc,const TReal &aPower)
162 Calculates the value of x raised to the power of y.
164 The behaviour conforms to that specified for pow() in the
165 ISO C Standard ISO/IEC 9899 (Annex F), although floating-point exceptions
168 @param aTrg A reference containing the result.
169 @param aSrc The x argument of the function.
170 @param aPower The y argument of the function.
172 @return KErrNone if successful;
173 KErrOverflow if the result is +/- infinity;
174 KErrUnderflow if the result is too small to be represented;
175 KErrArgument if the result is not a number (NaN).
178 // Evaluates aSrc raised to the power aPower and places the result in aTrg.
179 // For non-special values algorithm is aTrg=2^(aPower*log2(aSrc))
184 TInt ret2=p.Set(aPower);
185 // pow(x, +/-0) -> 1 for any x, even a NaN
192 TInt ret1=x.Set(aSrc);
193 if (ret1==KErrArgument || ret2==KErrArgument)
195 // pow(+1, y) -> 1 for any y, even a NaN
196 // XXX First test should not be necessary, but on WINS
197 // aSrc == 1.0 is true when aSrc is NaN.
198 if (ret1 != KErrArgument && aSrc == 1.0)
208 if (ret2==KErrOverflow)
210 // figure out which of these cases we have:
212 // pow(x, -INF) -> +INF for |x| < 1 } flag = 0
213 // pow(x, +INF) -> +INF for |x| > 1 }
214 // pow(x, -INF) -> +0 for |x| > 1 } flag = 1
215 // pow(x, +INF) -> +0 for |x| < 1 }
217 // flag = 2 => |x| == 1.0
236 // pow(-1, +/-INF) -> 1
240 // This should never happen (i.e. aSrc is NaN, which
241 // should be taken care of above)
246 // Negative Base raised to a power
251 Math::Int(pint,aPower);
252 if (aPower-pint) // Checks that if aSrc is less than zero, then aPower is integral
254 // pow(-INF, y) -> +0 for y < 0 and not an odd integer
255 // pow(-INF, y) -> +INF for y > 0 and not an odd integer
256 // Since we're here, aPower is not integral, so can't be odd, either
257 if (ret1 == KErrOverflow)
273 TReal powerby2=aPower*0.5;
274 Math::Int(pint,powerby2);
280 // Zero or infinity raised to a power
281 if (x.IsZero() || ret1==KErrOverflow)
283 if (x.IsZero() && p.IsZero())
288 TInt sign=(odd==-1 ? 1 : 0);
289 if ((x.IsZero() && (p.iSign&1)==0) || (ret1==KErrOverflow && (p.iSign&1)))
296 SetInfinite(aTrg,sign);
303 x=y*p; // this cannot overflow or underflow
307 TInt r2=y.GetTReal(aTrg);
308 return (r==KErrNone)?r2:r;
311 #else // __USE_VFP_MATH
313 // definitions come from RVCT math library
314 extern "C" TReal pow(TReal,TReal);
316 EXPORT_C TInt Math::Pow(TReal &aTrg,const TReal &aSrc,const TReal &aPower)
318 aTrg = pow(aSrc,aPower);
319 if (Math::IsZero(aTrg) && !Math::IsZero(aSrc) && !Math::IsInfinite(aSrc) && !Math::IsInfinite(aPower))
320 return KErrUnderflow;
321 if (Math::IsFinite(aTrg))
323 if (Math::IsZero(aPower)) // pow(x, +/-0) -> 1 for any x, even a NaN
328 if (Math::IsInfinite(aTrg))
330 if (aSrc==1.0) // pow(+1, y) -> 1 for any y, even a NaN
335 if (Math::IsInfinite(aPower))
337 if (aSrc == -1.0) // pow(-1, +/-INF) -> 1
342 if (((Abs(aSrc) < 1) && (aPower < 0)) || // pow(x, -INF) -> +INF for |x| < 1
343 ((Abs(aSrc) > 1) && (aPower > 0))) // pow(x, +INF) -> +INF for |x| > 1
349 // pow(-INF, y) -> +INF for y > 0 and not an odd integer
350 if (Math::IsInfinite(aSrc) && (aSrc < 0) && (aPower > 0))
354 Math::Int(pint, aPower);
357 TReal halfPower = aPower * 0.5;
358 Math::Int(pint, halfPower);
359 if (halfPower != pint)