diff -r 000000000000 -r a41df078684a kerneltest/e32test/math/t_roundtrip.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kerneltest/e32test/math/t_roundtrip.cpp Mon Oct 19 15:55:17 2009 +0100 @@ -0,0 +1,296 @@ +// Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of the License "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// e32test\math\t_roundtrip.cpp +// Tests round-trip convertibility of double->string->double +// +// + +#define __E32TEST_EXTENSION__ +#include +#include + +//#define __ALWAYS_PRINT__ + +RTest test(_L("T_ROUNDTRIP")); + +void PrintRealHex(const char* aTitle, const TReal& aIn) + { + volatile TUint32* in = (volatile TUint32*)&aIn; +#ifdef __DOUBLE_WORDS_SWAPPED__ + TUint32 high = in[0]; + TUint32 low = in[1]; +#else + TUint32 high = in[1]; + TUint32 low = in[0]; +#endif + TBuf<256> title; + if (aTitle) + title.Copy(TPtrC8((const TUint8*)aTitle)); + test.Printf(_L("%S%08x %08x\n"), &title, high, low); + } + +TInt RoundTrip(TReal& aOut, const TReal& aIn) + { + TBuf8<64> text; + TRealFormat fmt; + fmt.iType = KRealFormatExponent | KRealInjectiveLimit | KUseSigFigs | KDoNotUseTriads | KAllowThreeDigitExp; + fmt.iWidth = 32; + fmt.iPlaces = KIEEEDoubleInjectivePrecision; + fmt.iPoint = '.'; +#ifdef __ALWAYS_PRINT__ + PrintRealHex("Input : ", aIn); +#endif + TInt r = text.Num(aIn, fmt); + if (r<0) + { + test.Printf(_L("Result %d (Num)\n"), r); + return r; + } +#ifdef __ALWAYS_PRINT__ + TBuf16<64> text16; + text16.Copy(text); + test.Printf(_L("Text : %S\n"), &text16); +#endif + TLex8 lex(text); + r = lex.Val(aOut); + if (r < 0) + { + test.Printf(_L("Result %d (Val)\n"), r); + return r; + } +#ifdef __ALWAYS_PRINT__ + PrintRealHex("Output: ", aOut); +#endif + volatile TUint32* in = (volatile TUint32*)&aIn; + volatile TUint32* out = (volatile TUint32*)&aOut; + if (in[0]!=out[0] || in[1]!=out[1]) + { + test.Printf(_L("Unsuccessful\n")); +#ifndef __ALWAYS_PRINT__ + PrintRealHex("Input : ", aIn); + TBuf16<64> text16; + text16.Copy(text); + test.Printf(_L("Text : %S\n"), &text16); + PrintRealHex("Output: ", aOut); +#endif + return KErrUnknown; + } + return KErrNone; + } + +const TUint64 KMantissaOverflow = UI64LIT(0x20000000000000); // 2^53 +const TUint64 KMantissaThreshold = UI64LIT(0x10000000000000); // 2^52 + +class R + { +public: + enum {EMinExp=0, EMinNormExp=1, EMaxNormExp=2046, EMaxExp=2047}; +public: + R(); + R(const TReal& aIn); + TReal Value() const; + TInt Next(); + TInt Prev(); +public: + TUint64 iMant; // if iExp>0 2^52<=iMant<2^53 else 0<=iMant<2^52 + TInt iExp; // 0 < iExp < 2047 + TInt iSign; + }; + +R::R() + { + iMant = 0; + iExp = 0; + iSign = 0; + } + +R::R(const TReal& aIn) + { + const volatile TUint32* in = (const volatile TUint32*)&aIn; +#ifdef __DOUBLE_WORDS_SWAPPED__ + TUint32 high = in[0]; + TUint32 low = in[1]; +#else + TUint32 high = in[1]; + TUint32 low = in[0]; +#endif + iSign = high >> 31; + iExp = (high >> 20) & EMaxExp; + iMant = MAKE_TUINT64(high, low); + iMant <<= 12; + iMant >>= 12; + if (iExp) + iMant += KMantissaThreshold; + } + +TReal R::Value() const + { + TUint32 high = iSign ? 1 : 0; + high <<= 31; + high |= (iExp<<20); + TUint32 mh = I64HIGH(iMant); + mh <<= 12; + high |= (mh>>12); + TUint32 low = I64LOW(iMant); + + union {TReal iReal; TUint32 iX[2];} result; +#ifdef __DOUBLE_WORDS_SWAPPED__ + result.iX[0] = high; + result.iX[1] = low; +#else + result.iX[0] = low; + result.iX[1] = high; +#endif + return result.iReal; + } + +TInt R::Next() + { + if (iExp>0) + { + if (++iMant == KMantissaOverflow) + { + iMant >>= 1; + if (++iExp == EMaxExp) + return KErrOverflow; + } + return KErrNone; + } + if (++iMant == KMantissaThreshold) + iExp = 1; + return KErrNone; + } + +TInt R::Prev() + { + if (iExp == EMaxExp) + { + if (iMant == KMantissaThreshold) + { + --iExp; + return KErrNone; + } + return KErrGeneral; + } + if (iExp>0) + { + if (--iMant < KMantissaThreshold) + { + if (--iExp) + { + iMant <<= 1; + iMant++; + } + } + return KErrNone; + } + if (iMant==0) + return KErrUnderflow; + --iMant; + return KErrNone; + } + +void DoTest(R& aR, TInt& aErrorCount) + { + TReal out; + TInt r; + r = RoundTrip(out, aR.Value()); + if (r==KErrUnknown) + ++aErrorCount; + R R1(aR); + R R2(aR); + if (R1.Next()==KErrNone) + { + r = RoundTrip(out, R1.Value()); + if (r==KErrUnknown) + ++aErrorCount; + } + if (R2.Prev()==KErrNone) + { + r = RoundTrip(out, R2.Value()); + if (r==KErrUnknown) + ++aErrorCount; + } + } + +void DoTest(TInt aExp, TInt& aErrorCount) + { + R x; + x.iExp = aExp; + x.iMant = KMantissaThreshold; + if (aExp==0) + { + do { + x.iMant >>= 1; + DoTest(x, aErrorCount); + } while (x.iMant); + } + else + { + DoTest(x, aErrorCount); + } + } + +void DoTestPow10(TInt aPow, TInt& aErrorCount) + { + TReal64 r64; + TInt r = Math::Pow10(r64, aPow); + if (r<0) + return; + R x(r64); + DoTest(x, aErrorCount); + } + +void DoTestRandom(TInt& aErrorCount) + { + static TInt64 randSeed = I64LIT(0x3333333333333333); + R x; + x.iExp = Math::Rand(randSeed) & R::EMaxExp; + x.iMant = ((TUint64)Math::Rand(randSeed) << 32) | (TUint64)Math::Rand(randSeed); + while (x.iMant > KMantissaThreshold) + x.iMant >>= 1; + x.iSign = Math::Rand(randSeed) & 0x1; + DoTest(x, aErrorCount); + } + +TInt E32Main() + { + test.Title(); + test.Start(_L("Testing conversion from double->string->double")); + + TInt exp; + TInt errors = 0; + test.Next(_L("Test the conversion of powers of 2")); + for (exp = 0; exp < 2047; ++exp) + { + DoTest(exp, errors); + } + + test.Next(_L("Test the conversion of powers of 10")); + for (exp = -325; exp < 325; ++exp) + { + DoTestPow10(exp, errors); + } + + test.Next(_L("Test the conversion of some random numbers")); + for (exp = 0; exp < 100; ++exp) + { + DoTestRandom(errors); + } + + test_Equal(0, errors); + + test.End(); + return KErrNone; + }