|
1 // Copyright (c) 1995-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 "Symbian Foundation License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.symbianfoundation.org/legal/sfl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // e32\euser\maths\um_rtod.cpp |
|
15 // |
|
16 // |
|
17 |
|
18 #include "um_std.h" |
|
19 |
|
20 #include <e32debug.h> |
|
21 |
|
22 #define KNeedsRounding 0x1000 |
|
23 #if (KRealFormatTypeFlagsMask| KRealFormatTypesMask) & KNeedsRounding |
|
24 #error KNeedsRounding already uses 0x1000 |
|
25 #endif |
|
26 |
|
27 const TInt KMinThreeDigitExponent=100; |
|
28 |
|
29 _LIT8(KLit8Plus,"+"); |
|
30 _LIT8(KLit8Minus,"-"); |
|
31 _LIT8(KLit8Zero,"0"); |
|
32 _LIT8(KLit8Inf,"Inf"); |
|
33 _LIT8(KLit8Nan,"NaN"); |
|
34 |
|
35 LOCAL_C TInt round(const TText8* aBuf, const TInt aLen) |
|
36 // |
|
37 // Round number in buffer depending on digit at aBuf[aLen]. |
|
38 // Return value is carry from most significant digit. |
|
39 // |
|
40 { |
|
41 __ASSERT_DEBUG(aLen>=0,Panic(EMathUnexpectedError1)); |
|
42 TText8* pB=(TText8*)aBuf+aLen; |
|
43 if (*pB<'5') |
|
44 return 0; // round down |
|
45 while(--pB>=aBuf) |
|
46 { |
|
47 TText8 d=*pB; |
|
48 if (d<'9') |
|
49 { |
|
50 ++d; |
|
51 *pB=d; |
|
52 return 0; |
|
53 } |
|
54 *pB='0'; |
|
55 } |
|
56 // carry propagates to exponent |
|
57 *++pB='1'; |
|
58 if (aLen>0) |
|
59 pB[aLen]='0'; |
|
60 return 1; |
|
61 } |
|
62 |
|
63 TUint mult10(TUint64& a) |
|
64 // |
|
65 // Multiply a 64-bit binary fraction in a (MSB=2^-1) by 10 |
|
66 // Return the fractional part in a, the integer part in the return value. |
|
67 // |
|
68 { |
|
69 const TUint64 ten = 10; |
|
70 TUint64 high; |
|
71 Math::UMul64(a, ten, high, a); |
|
72 return static_cast<TUint>(high); |
|
73 } |
|
74 |
|
75 LOCAL_C TInt fDigLim(TDes8& aTrg, const TReal& aSrc, TInt& aExp, const TBool aLimit) |
|
76 // |
|
77 // Convert the TReal at address aSrc to a decimal form suitable for use by a |
|
78 // formatting routine. Writes the result into the descriptor at aTrg and the |
|
79 // exponent in aExp. Returns the length of the string or a negative error number. |
|
80 // |
|
81 // AnnW, November 1996 - changed to handle all numbers in TReal64/96 range. |
|
82 // |
|
83 // The first character in aBuf is one of: |
|
84 // |
|
85 // '0' - indicates that aSrc is exactly zero. |
|
86 // |
|
87 // '+' - indicates a positive number and is followed by between 1 and KMaxPrecision |
|
88 // decimal digits representing a mantissa in the range 0.1 to less than 1.0 which |
|
89 // corresponds to the decimal exponent returned in aExp. |
|
90 // |
|
91 // '-' - indicates a negative mantissa and is otherwise the same as for '+'. |
|
92 // |
|
93 // If aLimit is ETrue then the format is limited to KPrecisionLimit significant digits |
|
94 // |
|
95 { |
|
96 |
|
97 TRealX x; |
|
98 TInt r=x.Set(aSrc); |
|
99 |
|
100 if (x.IsZero()) |
|
101 { |
|
102 aTrg=KLit8Zero(); |
|
103 return 1; |
|
104 } |
|
105 else // sets sign in all cases, including specials |
|
106 aTrg=(x.iSign ? KLit8Minus() : KLit8Plus()); |
|
107 |
|
108 if (r!=KErrNone) |
|
109 return r; |
|
110 |
|
111 x.iSign=0; |
|
112 TInt e=TInt(x.iExp)-0x7fff; // 2^e<=Abs(x)<2^(e+1) |
|
113 e*=19728; // log10(2)*65536 = 19728.301796... |
|
114 // max error due to omission of fractional part is 9889 (towards zero) |
|
115 e-=9889; // account for error, e may be too small by up to 19778 |
|
116 // Now have 10^(e/65536)<=Abs(x)<4.007*10^(e/65536) |
|
117 e>>=16; // Divide by 65536 - this always rounds towards -infinity |
|
118 // Now have 10^e<=Abs(x)<40.07*10^e |
|
119 e+=1; // Now have 0.1<=Abs(x)/10^e<4.07 |
|
120 Math::MultPow10X(x,-e); // x*=10^-e so now 0.1<=x<4.07 |
|
121 if (x.iExp>=0x7fff) |
|
122 { |
|
123 ++e; |
|
124 Math::MultPow10X(x,-1); // if x>=1, multiply x by 10^-1 and increment e |
|
125 } |
|
126 |
|
127 TUint64 mantissa = MAKE_TUINT64(x.iMantHi, x.iMantLo); |
|
128 |
|
129 if (x.iExp<0x7ffe) |
|
130 mantissa >>= (0x7ffe - x.iExp); // shift to make exponent 0x7ffe, i.e. mantissa in range 0.1<=m<1 |
|
131 |
|
132 TInt prec=aLimit?KPrecisionLimit:KMaxPrecision; |
|
133 |
|
134 while ( mantissa && (aTrg.Length() < (prec + 2)) ) |
|
135 { |
|
136 TUint d = mult10(mantissa); |
|
137 aTrg.Append(d+'0'); |
|
138 } |
|
139 if (aTrg.Length()>=prec+2) |
|
140 { |
|
141 e+=round(aTrg.Ptr()+1,prec); |
|
142 aTrg.SetLength(prec+1); |
|
143 } |
|
144 aExp=e; |
|
145 return aTrg.Length(); |
|
146 } |
|
147 |
|
148 LOCAL_C TInt doExponent(TDes8* This, TDes8& aDigBuf, const TInt afDigLimSize, TInt aExp, |
|
149 const TInt aNumPlcs, const TInt aNumSpace, const TText aPoint, const TUint flags) |
|
150 // |
|
151 // Convert the intermediate number represented in aDigBuf into its exponential representation |
|
152 // and place into aTrg. |
|
153 // This representation ensures that numbers are displayed to aNumDecPlcs+1 significant figures, |
|
154 // but this is NOT a constant value in KTRealFormatGeneral mode. |
|
155 // |
|
156 // AnnW, November 1996 - changed to be able to take three-figure exponents if allowed by flags. |
|
157 // |
|
158 { |
|
159 |
|
160 TInt err; |
|
161 TInt expSpace; |
|
162 TInt useSigFigs=flags & KUseSigFigs; |
|
163 TInt nDig=(useSigFigs ? Min(aNumPlcs,afDigLimSize) : aNumPlcs+1); |
|
164 TInt threeDigitExp=flags & KAllowThreeDigitExp; |
|
165 |
|
166 if ((flags & KNeedsRounding) && afDigLimSize>nDig) |
|
167 aExp+=round(aDigBuf.Ptr()+1,nDig); |
|
168 |
|
169 if (useSigFigs) // discard trailing zeros |
|
170 { |
|
171 while(nDig>1 && aDigBuf[nDig]=='0') |
|
172 { |
|
173 nDig--; |
|
174 } |
|
175 } |
|
176 |
|
177 if (aDigBuf[0]!='0') |
|
178 // 100.5 is stored in aDigBuf as +1005 with and exp of 3, but it is to be displayed |
|
179 // as 1.005 so exp must be decremented to 2 |
|
180 aExp--; |
|
181 |
|
182 // Added by AnnW |
|
183 if (threeDigitExp) |
|
184 { |
|
185 expSpace=(Abs(aExp)>=KMinThreeDigitExponent)?5:4; |
|
186 } |
|
187 else |
|
188 { |
|
189 err=(aExp<=-KMinThreeDigitExponent ? KErrUnderflow : (aExp>=KMinThreeDigitExponent ? KErrOverflow : KErrNone)); |
|
190 if (err!=KErrNone) |
|
191 return(err); |
|
192 expSpace=4; |
|
193 } |
|
194 |
|
195 // Check that number will fit in aNumSpace |
|
196 if (aNumSpace<(expSpace+nDig+(nDig>1?1:0))) |
|
197 // exponent + significant figures + point(if necessary) |
|
198 return(KErrGeneral); |
|
199 // end of added |
|
200 |
|
201 if (aDigBuf[0]=='0') // number to be converted is 0 |
|
202 { |
|
203 This->Append('0'); |
|
204 if (nDig>1 && !useSigFigs) |
|
205 { |
|
206 This->Append(aPoint); |
|
207 This->AppendFill('0',aNumPlcs); |
|
208 } |
|
209 } |
|
210 else |
|
211 { |
|
212 This->Append(TChar(aDigBuf[1])); |
|
213 if (nDig>1) |
|
214 { |
|
215 This->Append(aPoint); |
|
216 for (TInt ii=2; ii<=nDig; ii++) |
|
217 { |
|
218 if (!useSigFigs) |
|
219 // pad with zeros |
|
220 This->Append(TChar(ii<aDigBuf.Length() ? aDigBuf[ii]:'0')); |
|
221 else |
|
222 // do not pad with zeros |
|
223 This->Append(TChar(aDigBuf[ii])); |
|
224 } |
|
225 } |
|
226 } |
|
227 |
|
228 This->Append('E'); |
|
229 if (aExp<0) |
|
230 { |
|
231 aExp=-aExp; |
|
232 This->Append('-'); |
|
233 } |
|
234 else |
|
235 This->Append('+'); |
|
236 |
|
237 // Added by AnnW |
|
238 TInt tempExp; |
|
239 if (threeDigitExp && aExp>99) |
|
240 { |
|
241 This->Append(aExp/100+'0'); |
|
242 tempExp=aExp%100; |
|
243 } |
|
244 else |
|
245 tempExp = aExp; |
|
246 // end of added |
|
247 |
|
248 This->Append(tempExp/10+'0'); |
|
249 This->Append(tempExp%10+'0'); |
|
250 return(KErrNone); |
|
251 } |
|
252 |
|
253 LOCAL_C TInt doFixed(TDes8 *This,TDes8 &aDigBuf,const TInt afDigLimSize,TInt aExp,const TInt aNumDecPlcs, |
|
254 const TInt aNumSpace,const TRealFormat &aFormat,const TUint flags) |
|
255 // |
|
256 // Convert the intermediate number represented in aDigBuf into its fixed representation and |
|
257 // place into aTrg |
|
258 // |
|
259 // AnnW, November 1996 - changed to allow extra space to be left for potential sign, so that |
|
260 // positive and negative numbers of the same exponent are displayed to the same precision. |
|
261 // |
|
262 { |
|
263 |
|
264 TInt err; |
|
265 TInt doNotUseTriads=flags & KDoNotUseTriads; |
|
266 TInt newNumSpace=aNumSpace; |
|
267 // To allow positive and negative numbers with the same exponent to have the same number of |
|
268 // significant figures. |
|
269 if ((flags & KExtraSpaceForSign) && (aDigBuf[0]!='-')) |
|
270 newNumSpace--; |
|
271 |
|
272 TInt roundOffset = aNumDecPlcs+aExp; |
|
273 if (roundOffset>=0 && afDigLimSize>roundOffset && (flags & KNeedsRounding)) |
|
274 aExp+=round(aDigBuf.Ptr()+1,roundOffset); |
|
275 |
|
276 if (newNumSpace<((aExp>0?aExp:1)+(aNumDecPlcs?aNumDecPlcs+1:0)+(!doNotUseTriads && aFormat.iTriLen && (aExp>(TInt)aFormat.iTriLen)?(aExp-1)/3:0))) |
|
277 // exponent +ve and space < space needed for (digits before point + point + decimal places + triads) |
|
278 { |
|
279 err=(aExp>0 ? KErrOverflow : KErrGeneral); |
|
280 return(err); |
|
281 } |
|
282 |
|
283 if (aExp<=0) // hence number is of the form 0.NNNN |
|
284 { |
|
285 This->Append('0'); |
|
286 if (aNumDecPlcs) |
|
287 { |
|
288 aExp=-aExp; |
|
289 TInt nDig=aNumDecPlcs-aExp; // number of digits required from aDigBuf |
|
290 This->Append(aFormat.iPoint); |
|
291 if (aExp>aNumDecPlcs) |
|
292 aExp=aNumDecPlcs; |
|
293 This->AppendFill('0',aExp); |
|
294 if (nDig>0) |
|
295 { |
|
296 for (TInt ii=1; ii<nDig+1; ii++) |
|
297 This->Append(TChar(ii<aDigBuf.Length() ? aDigBuf[ii]:'0')); |
|
298 } |
|
299 } |
|
300 else // no decimal places |
|
301 { |
|
302 if (aDigBuf[0]=='-') |
|
303 { |
|
304 This->Delete(0,2); // delete -0 from This |
|
305 This->Append('0'); |
|
306 } |
|
307 } |
|
308 } |
|
309 else // aExp > 0 hence number is of the form NNNN.NNNN |
|
310 { |
|
311 for (TInt jj=1,ii=aExp; ii; ii--,jj++) |
|
312 { |
|
313 if (!doNotUseTriads && aFormat.iTriLen && aExp>(TInt)aFormat.iTriLen && !(ii%3) && ii!=aExp) |
|
314 This->Append(aFormat.iTriad); |
|
315 This->Append(TChar(jj>=aDigBuf.Length() ? '0' : aDigBuf[jj])); |
|
316 } |
|
317 if (aNumDecPlcs>0) |
|
318 { |
|
319 This->Append(aFormat.iPoint); |
|
320 for (TInt ii=aExp+1; ii<aNumDecPlcs+aExp+1; ii++) |
|
321 This->Append(TChar(ii<aDigBuf.Length() ? aDigBuf[ii] : '0')); |
|
322 } |
|
323 } |
|
324 |
|
325 return(KErrNone); |
|
326 } |
|
327 |
|
328 LOCAL_C TInt doNoExponent(TDes8 *This, TDes8 &aDigBuf,const TInt afDigLimSize,TInt aExp, |
|
329 const TInt aMaxSigFigs,const TInt aNumSpace, const TRealFormat &aFormat,const TUint flags) |
|
330 // |
|
331 // Added by AnnW, November 1996 |
|
332 // Convert the intermediate number represented in aDigBuf into its no exponent representation |
|
333 // and place into aTrg |
|
334 // Changed April 1997 - If there is not enough space for the number of s.f., zeros, points, triads, |
|
335 // etc, then the number of significant figs is reduced to fit. Overflow if too big to fit and |
|
336 // underflow if no significance can be seen. |
|
337 // |
|
338 { |
|
339 |
|
340 TInt doNotUseTriads=flags & KDoNotUseTriads; |
|
341 TInt numSpace=aNumSpace; |
|
342 if ((flags & KExtraSpaceForSign) && (aDigBuf[0]!='-')) |
|
343 numSpace--; |
|
344 |
|
345 TInt nTriadSeps=(!doNotUseTriads && aFormat.iTriLen && (aExp>(TInt)aFormat.iTriLen))?(aExp-1)/3:0; |
|
346 TInt maxDig=Min(aMaxSigFigs,afDigLimSize); |
|
347 TInt maxSpace=numSpace-(aExp<=0?(2-aExp):((aExp<maxDig?1:aExp-maxDig)+nTriadSeps)); |
|
348 TInt nDig=Min(maxSpace,maxDig); |
|
349 if (afDigLimSize>nDig && nDig<15 && nDig>=0 && (flags & KNeedsRounding) && round(aDigBuf.Ptr()+1,nDig)) |
|
350 aExp++; |
|
351 |
|
352 if (aDigBuf[0]=='0') // do zero first (numSpace>=0 so OK) |
|
353 This->Append('0'); |
|
354 else |
|
355 { |
|
356 // check for overflow/underflow |
|
357 if ((aExp+nTriadSeps)>numSpace) |
|
358 return(KErrOverflow); |
|
359 if (nDig<=0) |
|
360 return(KErrUnderflow); |
|
361 |
|
362 if ((flags&(TUint)KRealFormatTypesMask)!=(TUint)KRealFormatCalculator && aExp>aMaxSigFigs) |
|
363 return(KErrOverflow); |
|
364 |
|
365 TInt nDecPlcs=nDig-aExp; |
|
366 while(nDecPlcs>0 && aDigBuf[nDig]=='0') |
|
367 { // discard trailing zeros (already done in calculator) |
|
368 nDecPlcs--; |
|
369 nDig--; |
|
370 } |
|
371 |
|
372 if (aExp<=0) // hence number is of the form 0.NNNN |
|
373 { |
|
374 This->Append('0'); |
|
375 aExp=-aExp; |
|
376 // if (nDecPlcs<=0) do nothing |
|
377 if (nDecPlcs>0) |
|
378 { |
|
379 This->Append(aFormat.iPoint); |
|
380 This->AppendFill('0',aExp); |
|
381 for (TInt ii=1; ii<=nDig; ii++) |
|
382 This->Append(TChar(aDigBuf[ii])); |
|
383 } |
|
384 } |
|
385 else // aExp > 0 hence number is of the form NNNN.NNNN |
|
386 { |
|
387 for (TInt jj=1,ii=aExp; ii; ii--,jj++) |
|
388 { |
|
389 if (!doNotUseTriads && aFormat.iTriLen && aExp>(TInt)aFormat.iTriLen && !(ii%3) && ii!=aExp) |
|
390 This->Append(aFormat.iTriad); |
|
391 This->Append(TChar(jj<=nDig ? aDigBuf[jj] : '0')); |
|
392 } |
|
393 if (nDecPlcs>0) |
|
394 { |
|
395 This->Append(aFormat.iPoint); |
|
396 for (TInt ii=aExp+1; ii<=nDig; ii++) |
|
397 This->Append(TChar(aDigBuf[ii])); |
|
398 } |
|
399 } |
|
400 } |
|
401 |
|
402 return(KErrNone); |
|
403 } |
|
404 |
|
405 LOCAL_C TInt doGeneral(TDes8 *This,TReal aSrc,TDes8 &aDigBuf,const TInt afDigLimSize,TInt aExp, |
|
406 TInt aNumDecPlcs,const TInt aNumSpace,const TRealFormat &aFormat,TUint flags) __SOFTFP |
|
407 // |
|
408 // Convert the intermediate number represented in aDigBuf into either its fixed representation or |
|
409 // its exponential representation as appropriate and place the result in aTrg |
|
410 // |
|
411 // Annw, November 1996 - changed to allow space for sign in fixed mode, three-figure exponent. |
|
412 { |
|
413 |
|
414 TBool rounded=((flags & KNeedsRounding)==0); |
|
415 TInt nDig=aDigBuf.Length()-1; // no of digits without sign |
|
416 TInt type; |
|
417 |
|
418 // Set up tempNumSpace to allow for leaving one space free for +ve nos in fixed format |
|
419 TInt fixedNumSpace=aNumSpace; |
|
420 if ((flags & KExtraSpaceForSign) && (aDigBuf[0]!='-')) |
|
421 fixedNumSpace--; |
|
422 if (fixedNumSpace<=0) |
|
423 return(KErrGeneral); |
|
424 |
|
425 FOREVER |
|
426 { |
|
427 // If aNumSpace < 5 cannot use exponential format, i.e. not enough space for XE+NN. |
|
428 // If the exponent >= -3 (i.e. aExp >= -2), it is always more (or equally) efficient |
|
429 // to use non-exponential format for negative exponents, i.e. XE-03 takes same no of |
|
430 // spaces as 0.00X, and for positive exponents use fixed form as far as possible. |
|
431 |
|
432 // for Java do not used fixed format for exponents >=7 |
|
433 // expMax=Min(fixedNumSpace,7) |
|
434 // and replace "fixednumSpace" with "expMax" in next line |
|
435 |
|
436 if (aNumSpace<5 || (aExp>=-2 && aExp<=fixedNumSpace)) |
|
437 { |
|
438 type=KRealFormatFixed; |
|
439 |
|
440 // if there is at least one digit before decimal point or no. is zero |
|
441 if (aExp>0 || !aSrc) |
|
442 { |
|
443 if (nDig!=aExp) |
|
444 // nDig is the number of digits which will be used |
|
445 // a decimal point needed if exponent < digits in digbuf and numspace < nDig, |
|
446 // so nDig is one less than otherwise |
|
447 nDig=((nDig-aExp)>0 && fixedNumSpace>aExp)?Min(fixedNumSpace-1,nDig):Min(fixedNumSpace,nDig); |
|
448 aNumDecPlcs=nDig-aExp; |
|
449 } |
|
450 else |
|
451 { |
|
452 // need space for "0." and to avoid white spaces |
|
453 aNumDecPlcs=Min(fixedNumSpace-2,nDig-aExp); |
|
454 // need space for "0.0...0" before any digits used |
|
455 nDig=aNumDecPlcs+aExp; |
|
456 if (nDig<0) |
|
457 return KErrGeneral; |
|
458 } |
|
459 } |
|
460 else |
|
461 { |
|
462 type=KRealFormatExponent; // Do NOT use significant figures |
|
463 // Need to allow space for exponent |
|
464 TInt tempNumSpace=aNumSpace-4; // 4 = E+NN |
|
465 if ((flags & KAllowThreeDigitExp) && (Abs(aExp-1)>=100)) |
|
466 tempNumSpace--; // 5 = E+NNN |
|
467 // if more than one digit available and enough digits to fill space, need to reduce |
|
468 // number of digits to allow for '.' |
|
469 if (((nDig=Min(tempNumSpace,nDig))>1) && nDig==tempNumSpace) |
|
470 nDig--; |
|
471 // in any case, aNumDecPlcs is one less that the number of digits, |
|
472 // i.e. one digit before the point |
|
473 aNumDecPlcs=nDig-1; |
|
474 } |
|
475 // if too many digbuf chars to fit then we need to round |
|
476 // round() returns 1 if had to carry from msdigit |
|
477 if ((afDigLimSize>nDig && !rounded) && ((rounded=round(aDigBuf.Ptr()+1,nDig))!=0)) |
|
478 aExp++; |
|
479 else |
|
480 break; |
|
481 } |
|
482 while(aNumDecPlcs>0 && aDigBuf[nDig]=='0') |
|
483 { // discard trailing zeros |
|
484 aNumDecPlcs--; |
|
485 nDig--; |
|
486 } |
|
487 flags=flags & ~KNeedsRounding; |
|
488 |
|
489 if (type==KRealFormatExponent) |
|
490 return(doExponent(This,aDigBuf,afDigLimSize,aExp,aNumDecPlcs,aNumSpace,(TText)aFormat.iPoint,flags)); |
|
491 return(doFixed(This,aDigBuf,afDigLimSize,aExp,aNumDecPlcs,aNumSpace,aFormat,flags)); |
|
492 } |
|
493 |
|
494 LOCAL_C TInt doCalculator(TDes8 *This,TDes8 &aDigBuf,const TInt afDigLimSize,TInt aExp, |
|
495 TInt aMaxSigFigs,const TInt aMaxSpace,const TRealFormat &aFormat, TUint flags) |
|
496 // |
|
497 // Added by AnnW, November 1996 |
|
498 // Convert the intermediate number represented in aDigBuf into either its no exponent or its |
|
499 // exponential representation with a fixed number of significant figures and place the result |
|
500 // in aTrg |
|
501 // |
|
502 { |
|
503 |
|
504 TBool threeDigExp=((flags & KAllowThreeDigitExp)!=0); |
|
505 |
|
506 // first check that enough space has been allowed for all the possible characters |
|
507 // point + sign + all sig figs + exponent |
|
508 if (aMaxSpace<(2+aMaxSigFigs+(threeDigExp?5:4))) |
|
509 return(KErrGeneral); |
|
510 |
|
511 // now discard trailing zeros |
|
512 TInt nDig=afDigLimSize; |
|
513 while(nDig>1 && aDigBuf[nDig]=='0') |
|
514 { |
|
515 nDig--; |
|
516 } |
|
517 |
|
518 TInt maxDig=Min(aMaxSigFigs,nDig); // max digs available |
|
519 TBool rounded=((flags & KNeedsRounding)==0); |
|
520 TInt type; |
|
521 TBool useNoExp; |
|
522 |
|
523 FOREVER |
|
524 { |
|
525 useNoExp=ETrue; |
|
526 nDig=maxDig; |
|
527 |
|
528 // use no exponent for all numbers which will not use > aMaxSigFigs digits |
|
529 if (aExp>aMaxSigFigs || (aExp<=0 && (1-aExp+nDig)>aMaxSigFigs)) |
|
530 useNoExp=EFalse; |
|
531 |
|
532 if (useNoExp) |
|
533 type=KRealFormatNoExponent; |
|
534 else |
|
535 { |
|
536 type=KRealFormatExponent; |
|
537 threeDigExp=((Abs(aExp-1)>=KMinThreeDigitExponent && threeDigExp)!=0); |
|
538 TInt temp=aMaxSpace-(threeDigExp?5:4); |
|
539 nDig=Min(maxDig,temp-((temp>1 && maxDig>1)?1:0)); |
|
540 } |
|
541 |
|
542 // if too many digbuf chars to fit then we need to round |
|
543 // round() returns 1 if had to carry from msdigit |
|
544 if ((afDigLimSize>nDig && !rounded) && ((rounded=round(aDigBuf.Ptr()+1,nDig))!=0)) |
|
545 { |
|
546 aExp++; |
|
547 maxDig=1; |
|
548 } |
|
549 else |
|
550 break; |
|
551 } |
|
552 |
|
553 TInt numSpace=aMaxSpace-(aDigBuf[0]=='-'?1:0); |
|
554 flags=flags & ~KNeedsRounding; |
|
555 |
|
556 if (type==KRealFormatExponent) |
|
557 return(doExponent(This,aDigBuf,afDigLimSize,aExp,nDig,numSpace,(TText)aFormat.iPoint,flags)); |
|
558 else |
|
559 { |
|
560 flags|=KExtraSpaceForSign; |
|
561 return(doNoExponent(This,aDigBuf,afDigLimSize,aExp,nDig,numSpace,aFormat,flags)); |
|
562 } |
|
563 } |
|
564 |
|
565 TInt ProcessErrors(TDes8* aDes, TInt anError) |
|
566 { |
|
567 if (anError==KErrNone) |
|
568 return aDes->Length(); |
|
569 if (anError==KErrUnderflow) |
|
570 aDes->Append(TChar('0')); |
|
571 if (anError==KErrOverflow) |
|
572 aDes->Append(KLit8Inf()); |
|
573 if (anError==KErrArgument) |
|
574 aDes->Append(KLit8Nan()); |
|
575 return anError; |
|
576 } |
|
577 |
|
578 LOCAL_C TInt rtob(TDes8 *This,TReal aVal,const TRealFormat &aFormat) __SOFTFP |
|
579 // |
|
580 // Converts the real at aSrc. Returns the length of the converted string or an error number |
|
581 // if the buffer is too small, the number is out of range or there is insufficient KMaxPrecision |
|
582 // to represent the number. |
|
583 // |
|
584 // The conversion format is interpreted as follows: |
|
585 // KRealFormatFixed - ndec decimal places (including zero), negative values with a leading minus |
|
586 // sign, triad separators are available and a space may be left in front of positive numbers to |
|
587 // allow negative positve numbers to be given to the same precision. |
|
588 // KRealFormatExponent - exponent notation specifying either decimal places or significant |
|
589 // figures in the mantissa and a signed exponent given to a maximum of two or three digits, |
|
590 // and no triad separator. |
|
591 // KTRealFormatGeneral - converts either as fixed or exponent to make best use of the available |
|
592 // width. The number of decimal spaces is chosen automatically as a function of width |
|
593 // (ndec is ignored), no triad. |
|
594 // KRealFormatNoExponent - as KRealForamtFixed, but specifying maximum significant figures and |
|
595 // not introducing trailing zeros. |
|
596 // KRealFormatCalculator - as KRealFormatGeneral, but behaves as a conventional calculator. A |
|
597 // maximum number of significant figures is specified and the number is displayed without an |
|
598 // exponent whenever possible, with no trailing zeros and no triads. |
|
599 // |
|
600 // If an error value other than KErrGeneral is returned the real is converted to some string: |
|
601 // "+/-Inf" if the error is KErrOverflow, "NaN" if the error is KErrArgument or "0" if it is |
|
602 // KErrUnderflow. |
|
603 // |
|
604 { |
|
605 if (aFormat.iWidth>This->MaxLength()) |
|
606 return(KErrGeneral); |
|
607 TBuf8<0x20> digbuf; |
|
608 TInt exp=0; |
|
609 TInt numspace=aFormat.iWidth; |
|
610 TInt maxspace=numspace; |
|
611 TInt ret=fDigLim(digbuf,aVal,exp,((aFormat.iType & KGeneralLimit)!=0)); |
|
612 digbuf.ZeroTerminate(); |
|
613 TInt type, flags; |
|
614 |
|
615 if (digbuf[0]=='0') |
|
616 exp=0; |
|
617 else |
|
618 { |
|
619 if (digbuf[0]=='-' && ret!=KErrArgument) // NaN has no sign |
|
620 { |
|
621 This->Append('-'); |
|
622 numspace--; |
|
623 } |
|
624 if (ret<0) |
|
625 return ProcessErrors(This, ret); |
|
626 else |
|
627 ret--; |
|
628 } |
|
629 |
|
630 //Added by AnnW |
|
631 if (numspace<=0) |
|
632 return(KErrGeneral); |
|
633 if (aFormat.iType & ~KRealFormatTypesMask & ~KRealFormatTypeFlagsMask) |
|
634 return(KErrGeneral); |
|
635 type=aFormat.iType & KRealFormatTypesMask; |
|
636 flags=((aFormat.iType & KRealFormatTypeFlagsMask)| KNeedsRounding); |
|
637 // end of added |
|
638 |
|
639 switch(type) |
|
640 { |
|
641 case KRealFormatFixed: |
|
642 flags=flags & ~KUseSigFigs; // if flag is NOT set and iTriLen!=0, uses triads |
|
643 ret=doFixed(This,digbuf,ret,exp,aFormat.iPlaces,numspace,aFormat,flags); |
|
644 break; |
|
645 case KRealFormatExponent: |
|
646 ret=doExponent(This,digbuf,ret,exp,aFormat.iPlaces,numspace,(TText)aFormat.iPoint,flags); |
|
647 break; |
|
648 case KRealFormatGeneral: |
|
649 flags=(flags & ~KUseSigFigs) | KDoNotUseTriads; |
|
650 ret=doGeneral(This,aVal,digbuf,ret,exp,aFormat.iPlaces,numspace,aFormat,flags); |
|
651 break; |
|
652 case KRealFormatNoExponent: |
|
653 flags=flags | KUseSigFigs; // if flag is NOT set and iTriLen!=0, uses triads |
|
654 ret=doNoExponent(This,digbuf,ret,exp,aFormat.iPlaces,numspace,aFormat,flags); |
|
655 break; |
|
656 case KRealFormatCalculator: |
|
657 flags=(flags | KUseSigFigs) | KDoNotUseTriads | KRealFormatCalculator; |
|
658 ret=doCalculator(This,digbuf,ret,exp,aFormat.iPlaces,maxspace,aFormat,flags); |
|
659 break; |
|
660 default: |
|
661 return(KErrGeneral); |
|
662 } |
|
663 return ProcessErrors(This, ret); |
|
664 } |
|
665 |
|
666 |
|
667 |
|
668 |
|
669 EXPORT_C TRealFormat::TRealFormat() |
|
670 /** |
|
671 Default constructor. |
|
672 |
|
673 The public data members of the constructed object are assigned |
|
674 the following values: |
|
675 |
|
676 TRealFormat::iType - set to KRealFormatGeneral |
|
677 |
|
678 TRealFormat::iWidth - set to KDefaultRealWidth |
|
679 |
|
680 TRealFormat::iPlaces - set to 0 |
|
681 |
|
682 TRealFormat::iPoint - set to the decimal separator character defined in |
|
683 a TLocale object and returned by the DecimalSeparator() |
|
684 member function of that class. |
|
685 |
|
686 TRealFormat::iTriad - set to the character used to delimit groups of three |
|
687 digits in the integer portion of a number; the character |
|
688 is defined in a TLocale object and returned by the |
|
689 ThousandsSeparator() member function of that class. |
|
690 |
|
691 TRealFormat::iTriLen - set to 1 |
|
692 |
|
693 @see TLocale::DecimalSeparator |
|
694 @see TLocale::ThousandsSeparator |
|
695 */ |
|
696 { |
|
697 |
|
698 iType=KRealFormatGeneral; |
|
699 iWidth=KDefaultRealWidth; |
|
700 iPlaces=0; |
|
701 TLocale locale; |
|
702 iPoint=locale.DecimalSeparator(); |
|
703 iTriad=locale.ThousandsSeparator(); |
|
704 iTriLen=1; |
|
705 } |
|
706 |
|
707 |
|
708 |
|
709 |
|
710 EXPORT_C TRealFormat::TRealFormat(TInt aWidth) |
|
711 /** |
|
712 Constructs the object taking the width of the character representation. |
|
713 |
|
714 The remaining public data members of the constructed object are assigned |
|
715 the following values: |
|
716 |
|
717 TRealFormat::iType - set to KRealFormatGeneral |
|
718 |
|
719 TRealFormat::iWidth - set to the aWidth argument |
|
720 |
|
721 TRealFormat::iPlaces - set to 0 |
|
722 |
|
723 TRealFormat::iPoint - set to the decimal separator character defined in |
|
724 a TLocale object and returned by the DecimalSeparator() |
|
725 member function of that class. |
|
726 |
|
727 TRealFormat::iTriad - set to the character used to delimit groups of three |
|
728 digits in the integer portion of a number; the character |
|
729 is defined in a TLocale object and returned by the |
|
730 ThousandsSeparator() member function of that class. |
|
731 |
|
732 TRealFormat::iTriLen - set to 1 |
|
733 |
|
734 @param aWidth The width of the character representation of the real number. |
|
735 |
|
736 @see TLocale::DecimalSeparator |
|
737 @see TLocale::ThousandsSeparator |
|
738 */ |
|
739 { |
|
740 |
|
741 iType=KRealFormatGeneral; |
|
742 iWidth=aWidth; |
|
743 iPlaces=0; |
|
744 TLocale locale; |
|
745 iPoint=locale.DecimalSeparator(); |
|
746 iTriad=locale.ThousandsSeparator(); |
|
747 iTriLen=1; |
|
748 } |
|
749 |
|
750 |
|
751 |
|
752 |
|
753 EXPORT_C TRealFormat::TRealFormat(TInt aWidth,TInt aDecimals) |
|
754 /** |
|
755 Constructs the object taking the width of the character representation |
|
756 and a value which is interpreted as the number of digits to follow |
|
757 the decimal point. |
|
758 |
|
759 The remaining public data members of the constructed object are assigned |
|
760 the following values: |
|
761 |
|
762 TRealFormat::iType - set to KRealFormatFixed |
|
763 |
|
764 TRealFormat::iWidth - set to the aWidth argument |
|
765 |
|
766 TRealFormat::iPlaces - set to the aDecimals argument |
|
767 |
|
768 TRealFormat::iPoint - set to the decimal separator character defined in |
|
769 a TLocale object and returned by the DecimalSeparator() |
|
770 member function of that class. |
|
771 |
|
772 TRealFormat::iTriad - set to the character used to delimit groups of three |
|
773 digits in the integer portion of a number; the character |
|
774 is defined in a TLocale object and returned by the |
|
775 ThousandsSeparator() member function of that class. |
|
776 |
|
777 TRealFormat::iTriLen - set to 1 |
|
778 |
|
779 Note that if the iType data member is changed after construction, aDecimalPlaces |
|
780 may be interpreted as the number of significant digits. For more information, |
|
781 see KRealFormatFixed and the other format types, and KExtraSpaceForSign and the |
|
782 other format flags. |
|
783 |
|
784 @param aWidth The width of the character representation of the real number. |
|
785 @param aDecimals The number of digits to follow the decimal point. |
|
786 |
|
787 @see TLocale::DecimalSeparator() |
|
788 @see TLocale::ThousandsSeparator() |
|
789 @see KRealFormatFixed |
|
790 @see KExtraSpaceForSign |
|
791 */ |
|
792 { |
|
793 |
|
794 iType=KRealFormatFixed; |
|
795 iWidth=aWidth; |
|
796 iPlaces=aDecimals; |
|
797 TLocale locale; |
|
798 iPoint=locale.DecimalSeparator(); |
|
799 iTriad=locale.ThousandsSeparator(); |
|
800 iTriLen=1; |
|
801 } |
|
802 |
|
803 |
|
804 |
|
805 |
|
806 EXPORT_C TInt Math::Round(TReal &aTrg,const TReal &aSrc,TInt aDecimalPlaces) |
|
807 /** |
|
808 Rounds to a specified number of decimal places. |
|
809 |
|
810 The function rounds a number to a given number, n, of decimal places. |
|
811 Rounding may be thought of as multiplying the number by 10 to the power of n, |
|
812 rounding to the nearest integer, and then dividing the result by 10 to |
|
813 the power of n and returning that as the answer. |
|
814 |
|
815 In the process of rounding, numbers ending with .5 are rounded away from zero, |
|
816 so that 1.5 becomes 2, 2.5 becomes 3, -1.5 becomes -2, etc. |
|
817 |
|
818 @param aTrg A reference containing the result. |
|
819 @param aSrc The number to be rounded. |
|
820 @param aDecimalPlaces The number of decimal places to round to: must be |
|
821 zero or positive. |
|
822 |
|
823 @return KErrNone if successful, otherwise another of the system-wide error codes. |
|
824 */ |
|
825 { |
|
826 |
|
827 if (aSrc==0.0) |
|
828 { |
|
829 aTrg=aSrc; |
|
830 return(KErrNone); |
|
831 } |
|
832 TInt ret,exp; |
|
833 TBuf8<0x20> rbuf; |
|
834 if ((ret=fDigLim(rbuf,aSrc,exp,EFalse))<0) |
|
835 return(ret); |
|
836 if ((exp+aDecimalPlaces)<0) |
|
837 { // Number too small to be rounded |
|
838 aTrg=0; |
|
839 return(KErrNone); |
|
840 } |
|
841 if ((ret-2)<(exp+aDecimalPlaces)) //ret is the string length, including prefixed +/- |
|
842 { // Rounding will have no effect |
|
843 aTrg=aSrc; |
|
844 return(KErrNone); |
|
845 } |
|
846 if ((ret=round(rbuf.Ptr()+1,exp+aDecimalPlaces))!=KErrNone) |
|
847 exp++; |
|
848 rbuf.Insert(1,TPtrC8((TText8*)".",1)); |
|
849 rbuf.SetLength(exp+aDecimalPlaces+2); |
|
850 if (!(exp+aDecimalPlaces)) |
|
851 rbuf.Append('0'); |
|
852 // rbuf.AppendFormat(TPtrC8((TText8*)"%c%d",4),'E',exp); |
|
853 rbuf.Append(TChar('E')); |
|
854 rbuf.AppendNum(exp); |
|
855 return(((TLex8)rbuf).Val(aTrg,(TChar)'.')); |
|
856 } |
|
857 |
|
858 EXPORT_C TInt TDes8::Num(TReal aVal,const TRealFormat &aFormat) __SOFTFP |
|
859 /** |
|
860 Converts the specified floating point number into a character representation |
|
861 and copies the conversion into this descriptor, replacing any existing data. |
|
862 |
|
863 The length of this descriptor is set to reflect the new data. |
|
864 |
|
865 The character representation of the real number is dictated by the specified |
|
866 format. |
|
867 |
|
868 Note that the function leaves if the iType data member of the specified |
|
869 TRealFormat object has both an invalid character representation format |
|
870 (i.e. the format type) and invalid format flags. |
|
871 |
|
872 @param aVal The floating point number to be converted. |
|
873 @param aFormat The format of the conversion. |
|
874 |
|
875 @return If the conversion is successful, the length of this descriptor. If |
|
876 the conversion fails, a negative value indicating the cause of failure. |
|
877 In addition, extra information on the cause of the failure may be |
|
878 appended onto this descriptor. The possible values and their meaning |
|
879 are: |
|
880 |
|
881 1.KErrArgument - the supplied floating point number is not a valid |
|
882 number. The three characters NaN are appended to this descriptor. |
|
883 |
|
884 2.KErrOverflow - the number is too large to represent. |
|
885 2.1 For positive overflow, the three characters Inf are appended |
|
886 to this descriptor. |
|
887 2.2 For negative overflow, the four characters -Inf are appended |
|
888 to this descriptor. |
|
889 |
|
890 3.KErrUnderflow - the number is too small to represent. |
|
891 3.1 For positive underflow, the three characters Inf are appended |
|
892 to this descriptor. |
|
893 3.2 For negative underflow, the four characters -Inf are appended |
|
894 to this descriptor. |
|
895 |
|
896 4.KErrGeneral - the conversion cannot be completed. There are a |
|
897 number of possible reasons for this, but the two most common |
|
898 are: |
|
899 4.1 the maximum number of characters necessary to represent the number, |
|
900 as defined in the TRealFormat object, is greater than the maximum |
|
901 length of this descriptor |
|
902 4.2 the character representation format (i.e. the format type), as |
|
903 defined in the TRealFormat object is not recognised. |
|
904 |
|
905 @see TRealFormat::iType |
|
906 */ |
|
907 { |
|
908 |
|
909 Zero(); |
|
910 return(rtob(this,aVal,aFormat)); |
|
911 } |
|
912 |
|
913 EXPORT_C TInt TDes8::AppendNum(TReal aVal,const TRealFormat &aFormat) __SOFTFP |
|
914 /** |
|
915 Converts the specified floating point number into a character representation |
|
916 and appends the conversion onto the end of this descriptor's data. |
|
917 |
|
918 The length of this descriptor is incremented to reflect the new content. |
|
919 |
|
920 The character representation of the real number is dictated by the specified |
|
921 format. |
|
922 |
|
923 @param aVal The floating point number to be converted. |
|
924 @param aFormat The format of the conversion. |
|
925 |
|
926 @return If the conversion is successful, the length of this descriptor. If |
|
927 the conversion fails, a negative value indicating the cause of failure. |
|
928 In addition, extra information on the cause of the failure may be |
|
929 appended onto this descriptor. The possible values and their meaning |
|
930 are: |
|
931 |
|
932 1.KErrArgument - the supplied floating point number is not a valid |
|
933 number. The three characters NaN are appended to this descriptor. |
|
934 |
|
935 2.KErrOverflow - the number is too large to represent. |
|
936 2.1 For positive overflow, the three characters Inf are appended |
|
937 to this descriptor. |
|
938 2.2 For negative overflow, the four characters -Inf are appended |
|
939 to this descriptor. |
|
940 |
|
941 3.KErrUnderflow - the number is too small to represent. |
|
942 3.1 For positive underflow, the three characters Inf are appended |
|
943 to this descriptor. |
|
944 3.2 For negative underflow, the four characters -Inf are appended |
|
945 to this descriptor. |
|
946 |
|
947 4.KErrGeneral - the conversion cannot be completed. There are a |
|
948 number of possible reasons for this, but the two most common |
|
949 are: |
|
950 4.1 the maximum number of characters necessary to represent the number, |
|
951 as defined in the TRealFormat object, is greater than the maximum |
|
952 length of this descriptor |
|
953 4.2 the character representation format (i.e. the format type), as |
|
954 defined in the TRealFormat object is not recognised |
|
955 */ |
|
956 { |
|
957 |
|
958 return(rtob(this,aVal,aFormat)); |
|
959 } |
|
960 |
|
961 EXPORT_C TInt TDes16::Num(TReal aVal,const TRealFormat &aFormat) __SOFTFP |
|
962 /** |
|
963 Converts the specified floating point number into a character representation |
|
964 and copies the conversion into this descriptor, replacing any existing data. |
|
965 |
|
966 The length of this descriptor is set to reflect the new data. |
|
967 |
|
968 The character representation of the real number is dictated by the specified |
|
969 format. |
|
970 |
|
971 Note that the function leaves if the iType data member of the specified |
|
972 TRealFormat object has both an invalid character representation format |
|
973 (i.e. the format type) and invalid format flags. |
|
974 |
|
975 @param aVal The floating point number to be converted. |
|
976 @param aFormat The format of the conversion. |
|
977 |
|
978 @return If the conversion is successful, the length of this descriptor. If |
|
979 the conversion fails, a negative value indicating the cause of failure. |
|
980 In addition, extra information on the cause of the failure may be |
|
981 appended onto this descriptor. The possible values and their meaning |
|
982 are: |
|
983 |
|
984 1.KErrArgument - the supplied floating point number is not a valid |
|
985 number. The three characters NaN are appended to this descriptor. |
|
986 |
|
987 2.KErrOverflow - the number is too large to represent. |
|
988 2.1 For positive overflow, the three characters Inf are appended |
|
989 to this descriptor. |
|
990 2.2 For negative overflow, the four characters -Inf are appended |
|
991 to this descriptor. |
|
992 |
|
993 3.KErrUnderflow - the number is too small to represent. |
|
994 3.1 For positive underflow, the three characters Inf are appended |
|
995 to this descriptor. |
|
996 3.2 For negative underflow, the four characters -Inf are appended |
|
997 to this descriptor. |
|
998 |
|
999 4.KErrGeneral - the conversion cannot be completed. There are a |
|
1000 number of possible reasons for this, but the two most common |
|
1001 are: |
|
1002 4.1 the maximum number of characters necessary to represent the number, |
|
1003 as defined in the TRealFormat object, is greater than the maximum |
|
1004 length of this descriptor |
|
1005 4.2 the character representation format (i.e. the format type), as |
|
1006 defined in the TRealFormat object is not recognised. |
|
1007 |
|
1008 @see TRealFormat::iType |
|
1009 */ |
|
1010 { |
|
1011 |
|
1012 Zero(); |
|
1013 return (AppendNum(aVal,aFormat)); |
|
1014 } |
|
1015 |
|
1016 EXPORT_C TInt TDes16::AppendNum(TReal aVal,const TRealFormat &aFormat) __SOFTFP |
|
1017 /** |
|
1018 Converts the specified floating point number into a character representation |
|
1019 and appends the conversion onto the end of this descriptor's data. |
|
1020 |
|
1021 The length of this descriptor is incremented to reflect the new content. |
|
1022 |
|
1023 The character representation of the real number is dictated by the specified |
|
1024 format. |
|
1025 |
|
1026 @param aVal The floating point number to be converted. |
|
1027 @param aFormat The format of the conversion. |
|
1028 |
|
1029 @return If the conversion is successful, the length of this descriptor. If |
|
1030 the conversion fails, a negative value indicating the cause of failure. |
|
1031 In addition, extra information on the cause of the failure may be |
|
1032 appended onto this descriptor. The possible values and their meaning |
|
1033 are: |
|
1034 |
|
1035 1.KErrArgument - the supplied floating point number is not a valid |
|
1036 number. The three characters NaN are appended to this descriptor. |
|
1037 |
|
1038 2.KErrOverflow - the number is too large to represent. |
|
1039 2.1 For positive overflow, the three characters Inf are appended |
|
1040 to this descriptor. |
|
1041 2.2 For negative overflow, the four characters -Inf are appended |
|
1042 to this descriptor. |
|
1043 |
|
1044 3.KErrUnderflow - the number is too small to represent. |
|
1045 3.1 For positive underflow, the three characters Inf are appended |
|
1046 to this descriptor. |
|
1047 3.2 For negative underflow, the four characters -Inf are appended |
|
1048 to this descriptor. |
|
1049 |
|
1050 4.KErrGeneral - the conversion cannot be completed. There are a |
|
1051 number of possible reasons for this, but the two most common |
|
1052 are: |
|
1053 4.1 the maximum number of characters necessary to represent the number, |
|
1054 as defined in the TRealFormat object, is greater than the maximum |
|
1055 length of this descriptor |
|
1056 4.2 the character representation format (i.e. the format type), as |
|
1057 defined in the TRealFormat object is not recognised |
|
1058 */ |
|
1059 { |
|
1060 |
|
1061 HBufC8 *temp=HBufC8::New(MaxLength()); |
|
1062 if (temp==NULL) |
|
1063 return(KErrNoMemory); |
|
1064 TPtr8 p(temp->Des()); |
|
1065 TInt ret=rtob(&p,aVal,aFormat); |
|
1066 const TText8 *pTemp=temp->Ptr(); |
|
1067 for (TInt ii=temp->Length();ii>0;ii--) |
|
1068 Append(*pTemp++); |
|
1069 if (ret>0) |
|
1070 ret=Length(); |
|
1071 User::Free(temp); |
|
1072 return (ret); |
|
1073 } |