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