|
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 } |