--- /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 <e32test.h>
+#include <e32math.h>
+
+//#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;
+ }