os/kernelhwsrv/kerneltest/e32test/math/t_roundtrip.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     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 	}