kerneltest/e32test/math/t_roundtrip.cpp
changeset 0 a41df078684a
equal deleted inserted replaced
-1:000000000000 0:a41df078684a
       
     1 // Copyright (c) 2008-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 // e32test\math\t_roundtrip.cpp
       
    15 // Tests round-trip convertibility of double->string->double
       
    16 // 
       
    17 //
       
    18 
       
    19 #define __E32TEST_EXTENSION__
       
    20 #include <e32test.h>
       
    21 #include <e32math.h>
       
    22 
       
    23 //#define __ALWAYS_PRINT__
       
    24 
       
    25 RTest test(_L("T_ROUNDTRIP"));
       
    26 
       
    27 void PrintRealHex(const char* aTitle, const TReal& aIn)
       
    28 	{
       
    29 	volatile TUint32* in = (volatile TUint32*)&aIn;
       
    30 #ifdef __DOUBLE_WORDS_SWAPPED__
       
    31 	TUint32 high = in[0];
       
    32 	TUint32 low = in[1];
       
    33 #else
       
    34 	TUint32 high = in[1];
       
    35 	TUint32 low = in[0];
       
    36 #endif
       
    37 	TBuf<256> title;
       
    38 	if (aTitle)
       
    39 		title.Copy(TPtrC8((const TUint8*)aTitle));
       
    40 	test.Printf(_L("%S%08x %08x\n"), &title, high, low);
       
    41 	}
       
    42 
       
    43 TInt RoundTrip(TReal& aOut, const TReal& aIn)
       
    44 	{
       
    45 	TBuf8<64> text;
       
    46 	TRealFormat fmt;
       
    47 	fmt.iType = KRealFormatExponent | KRealInjectiveLimit | KUseSigFigs | KDoNotUseTriads | KAllowThreeDigitExp;
       
    48 	fmt.iWidth = 32;
       
    49 	fmt.iPlaces = KIEEEDoubleInjectivePrecision;
       
    50 	fmt.iPoint = '.';
       
    51 #ifdef __ALWAYS_PRINT__
       
    52 	PrintRealHex("Input : ", aIn);
       
    53 #endif
       
    54 	TInt r = text.Num(aIn, fmt);
       
    55 	if (r<0)
       
    56 		{
       
    57 		test.Printf(_L("Result %d (Num)\n"), r);
       
    58 		return r;
       
    59 		}
       
    60 #ifdef __ALWAYS_PRINT__
       
    61 	TBuf16<64> text16;
       
    62 	text16.Copy(text);
       
    63 	test.Printf(_L("Text  : %S\n"), &text16);
       
    64 #endif
       
    65 	TLex8 lex(text);
       
    66 	r = lex.Val(aOut);
       
    67 	if (r < 0)
       
    68 		{
       
    69 		test.Printf(_L("Result %d (Val)\n"), r);
       
    70 		return r;
       
    71 		}
       
    72 #ifdef __ALWAYS_PRINT__
       
    73 	PrintRealHex("Output: ", aOut);
       
    74 #endif
       
    75 	volatile TUint32* in = (volatile TUint32*)&aIn;
       
    76 	volatile TUint32* out = (volatile TUint32*)&aOut;
       
    77 	if (in[0]!=out[0] || in[1]!=out[1])
       
    78 		{
       
    79 		test.Printf(_L("Unsuccessful\n"));
       
    80 #ifndef __ALWAYS_PRINT__
       
    81 		PrintRealHex("Input : ", aIn);
       
    82 		TBuf16<64> text16;
       
    83 		text16.Copy(text);
       
    84 		test.Printf(_L("Text  : %S\n"), &text16);
       
    85 		PrintRealHex("Output: ", aOut);
       
    86 #endif
       
    87 		return KErrUnknown;
       
    88 		}
       
    89 	return KErrNone;
       
    90 	}
       
    91 
       
    92 const TUint64 KMantissaOverflow =	UI64LIT(0x20000000000000);	// 2^53
       
    93 const TUint64 KMantissaThreshold =	UI64LIT(0x10000000000000);	// 2^52
       
    94 
       
    95 class R
       
    96 	{
       
    97 public:
       
    98 	enum {EMinExp=0, EMinNormExp=1, EMaxNormExp=2046, EMaxExp=2047};
       
    99 public:
       
   100 	R();
       
   101 	R(const TReal& aIn);
       
   102 	TReal Value() const;
       
   103 	TInt Next();
       
   104 	TInt Prev();
       
   105 public:
       
   106 	TUint64	iMant;		//	if iExp>0 2^52<=iMant<2^53 else 0<=iMant<2^52
       
   107 	TInt	iExp;		//	0 < iExp < 2047
       
   108 	TInt	iSign;
       
   109 	};
       
   110 
       
   111 R::R()
       
   112 	{
       
   113 	iMant = 0;
       
   114 	iExp = 0;
       
   115 	iSign = 0;
       
   116 	}
       
   117 
       
   118 R::R(const TReal& aIn)
       
   119 	{
       
   120 	const volatile TUint32* in = (const volatile TUint32*)&aIn;
       
   121 #ifdef __DOUBLE_WORDS_SWAPPED__
       
   122 	TUint32 high = in[0];
       
   123 	TUint32 low = in[1];
       
   124 #else
       
   125 	TUint32 high = in[1];
       
   126 	TUint32 low = in[0];
       
   127 #endif
       
   128 	iSign = high >> 31;
       
   129 	iExp = (high >> 20) & EMaxExp;
       
   130 	iMant = MAKE_TUINT64(high, low);
       
   131 	iMant <<= 12;
       
   132 	iMant >>= 12;
       
   133 	if (iExp)
       
   134 		iMant += KMantissaThreshold;
       
   135 	}
       
   136 
       
   137 TReal R::Value() const
       
   138 	{
       
   139 	TUint32 high = iSign ? 1 : 0;
       
   140 	high <<= 31;
       
   141 	high |= (iExp<<20);
       
   142 	TUint32 mh = I64HIGH(iMant);
       
   143 	mh <<= 12;
       
   144 	high |= (mh>>12);
       
   145 	TUint32 low = I64LOW(iMant);
       
   146 
       
   147 	union {TReal iReal; TUint32 iX[2];} result;
       
   148 #ifdef __DOUBLE_WORDS_SWAPPED__
       
   149 	result.iX[0] = high;
       
   150 	result.iX[1] = low;
       
   151 #else
       
   152 	result.iX[0] = low;
       
   153 	result.iX[1] = high;
       
   154 #endif
       
   155 	return result.iReal;
       
   156 	}
       
   157 
       
   158 TInt R::Next()
       
   159 	{
       
   160 	if (iExp>0)
       
   161 		{
       
   162 		if (++iMant == KMantissaOverflow)
       
   163 			{
       
   164 			iMant >>= 1;
       
   165 			if (++iExp == EMaxExp)
       
   166 				return KErrOverflow;
       
   167 			}
       
   168 		return KErrNone;
       
   169 		}
       
   170 	if (++iMant == KMantissaThreshold)
       
   171 		iExp = 1;
       
   172 	return KErrNone;
       
   173 	}
       
   174 
       
   175 TInt R::Prev()
       
   176 	{
       
   177 	if (iExp == EMaxExp)
       
   178 		{
       
   179 		if (iMant == KMantissaThreshold)
       
   180 			{
       
   181 			--iExp;
       
   182 			return KErrNone;
       
   183 			}
       
   184 		return KErrGeneral;
       
   185 		}
       
   186 	if (iExp>0)
       
   187 		{
       
   188 		if (--iMant < KMantissaThreshold)
       
   189 			{
       
   190 			if (--iExp)
       
   191 				{
       
   192 				iMant <<= 1;
       
   193 				iMant++;
       
   194 				}
       
   195 			}
       
   196 		return KErrNone;
       
   197 		}
       
   198 	if (iMant==0)
       
   199 		return KErrUnderflow;
       
   200 	--iMant;
       
   201 	return KErrNone;
       
   202 	}
       
   203 
       
   204 void DoTest(R& aR, TInt& aErrorCount)
       
   205 	{
       
   206 	TReal out;
       
   207 	TInt r;
       
   208 	r = RoundTrip(out, aR.Value());
       
   209 	if (r==KErrUnknown)
       
   210 		++aErrorCount;
       
   211 	R R1(aR);
       
   212 	R R2(aR);
       
   213 	if (R1.Next()==KErrNone)
       
   214 		{
       
   215 		r = RoundTrip(out, R1.Value());
       
   216 		if (r==KErrUnknown)
       
   217 			++aErrorCount;
       
   218 		}
       
   219 	if (R2.Prev()==KErrNone)
       
   220 		{
       
   221 		r = RoundTrip(out, R2.Value());
       
   222 		if (r==KErrUnknown)
       
   223 			++aErrorCount;
       
   224 		}
       
   225 	}
       
   226 
       
   227 void DoTest(TInt aExp, TInt& aErrorCount)
       
   228 	{
       
   229 	R x;
       
   230 	x.iExp = aExp;
       
   231 	x.iMant = KMantissaThreshold;
       
   232 	if (aExp==0)
       
   233 		{
       
   234 		do	{
       
   235 			x.iMant >>= 1;
       
   236 			DoTest(x, aErrorCount);
       
   237 			} while (x.iMant);
       
   238 		}
       
   239 	else
       
   240 		{
       
   241 		DoTest(x, aErrorCount);
       
   242 		}
       
   243 	}
       
   244 
       
   245 void DoTestPow10(TInt aPow, TInt& aErrorCount)
       
   246 	{
       
   247 	TReal64 r64;
       
   248 	TInt r = Math::Pow10(r64, aPow);
       
   249 	if (r<0)
       
   250 		return;
       
   251 	R x(r64);
       
   252 	DoTest(x, aErrorCount);
       
   253 	}
       
   254 
       
   255 void DoTestRandom(TInt& aErrorCount)
       
   256 	{
       
   257 	static TInt64 randSeed = I64LIT(0x3333333333333333);
       
   258 	R x;
       
   259 	x.iExp = Math::Rand(randSeed) & R::EMaxExp;
       
   260 	x.iMant = ((TUint64)Math::Rand(randSeed) << 32) | (TUint64)Math::Rand(randSeed);
       
   261 	while (x.iMant > KMantissaThreshold)
       
   262 		x.iMant >>= 1;
       
   263 	x.iSign = Math::Rand(randSeed) & 0x1;
       
   264 	DoTest(x, aErrorCount);
       
   265 	}
       
   266 
       
   267 TInt E32Main()
       
   268 	{
       
   269 	test.Title();
       
   270 	test.Start(_L("Testing conversion from double->string->double"));
       
   271 
       
   272 	TInt exp;
       
   273 	TInt errors = 0;
       
   274 	test.Next(_L("Test the conversion of powers of 2"));
       
   275 	for (exp = 0; exp < 2047; ++exp)
       
   276 		{
       
   277 		DoTest(exp, errors);
       
   278 		}
       
   279 
       
   280 	test.Next(_L("Test the conversion of powers of 10"));
       
   281 	for (exp = -325; exp < 325; ++exp)
       
   282 		{
       
   283 		DoTestPow10(exp, errors);
       
   284 		}
       
   285 
       
   286 	test.Next(_L("Test the conversion of some random numbers"));
       
   287 	for (exp = 0; exp < 100; ++exp)
       
   288 		{
       
   289 		DoTestRandom(errors);
       
   290 		}
       
   291 
       
   292 	test_Equal(0, errors);
       
   293 
       
   294 	test.End();
       
   295 	return KErrNone;
       
   296 	}