xref: /trunk/main/scaddins/source/analysis/analysishelper.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 #include <com/sun/star/util/XNumberFormatTypes.hpp>
29 
30 #include <string.h>
31 #include <stdio.h>
32 #include <tools/resary.hxx>
33 #include <rtl/math.hxx>
34 #include "analysishelper.hxx"
35 #include "analysis.hrc"
36 
37 using namespace                 ::rtl;
38 using namespace                 ::com::sun::star;
39 
40 
41 
42 #define UNIQUE              sal_False   // function name does not exist in Calc
43 #define DOUBLE              sal_True    // function name exists in Calc
44 
45 #define STDPAR              sal_False   // all parameters are described
46 #define INTPAR              sal_True    // first parameter is internal
47 
48 #define FUNCDATA( FUNCNAME, DBL, OPT, NUMOFPAR, CAT ) \
49     { "get" #FUNCNAME, ANALYSIS_FUNCNAME_##FUNCNAME, ANALYSIS_##FUNCNAME, DBL, OPT, ANALYSIS_DEFFUNCNAME_##FUNCNAME, NUMOFPAR, CAT }
50 
51 const FuncDataBase pFuncDatas[] =
52 {
53     //                          UNIQUE or   INTPAR or
54     //         function name     DOUBLE      STDPAR     # of param  category
55     FUNCDATA( Workday,          UNIQUE,     INTPAR,     3,          FDCat_DateTime ),
56     FUNCDATA( Yearfrac,         UNIQUE,     INTPAR,     3,          FDCat_DateTime ),
57     FUNCDATA( Edate,            UNIQUE,     INTPAR,     2,          FDCat_DateTime ),
58     FUNCDATA( Weeknum,          DOUBLE,     INTPAR,     2,          FDCat_DateTime ),
59     FUNCDATA( Eomonth,          UNIQUE,     INTPAR,     2,          FDCat_DateTime ),
60     FUNCDATA( Networkdays,      UNIQUE,     INTPAR,     3,          FDCat_DateTime ),
61     FUNCDATA( Iseven,           DOUBLE,     STDPAR,     1,          FDCat_Inf ),
62     FUNCDATA( Isodd,            DOUBLE,     STDPAR,     1,          FDCat_Inf ),
63     FUNCDATA( Multinomial,      UNIQUE,     STDPAR,     1,          FDCat_Math ),
64     FUNCDATA( Seriessum,        UNIQUE,     STDPAR,     4,          FDCat_Math ),
65     FUNCDATA( Quotient,         UNIQUE,     STDPAR,     2,          FDCat_Math ),
66     FUNCDATA( Mround,           UNIQUE,     STDPAR,     2,          FDCat_Math ),
67     FUNCDATA( Sqrtpi,           UNIQUE,     STDPAR,     1,          FDCat_Math ),
68     FUNCDATA( Randbetween,      UNIQUE,     STDPAR,     2,          FDCat_Math ),
69     FUNCDATA( Gcd,              DOUBLE,     INTPAR,     1,          FDCat_Math ),
70     FUNCDATA( Lcm,              DOUBLE,     INTPAR,     1,          FDCat_Math ),
71     FUNCDATA( Besseli,          UNIQUE,     STDPAR,     2,          FDCat_Tech ),
72     FUNCDATA( Besselj,          UNIQUE,     STDPAR,     2,          FDCat_Tech ),
73     FUNCDATA( Besselk,          UNIQUE,     STDPAR,     2,          FDCat_Tech ),
74     FUNCDATA( Bessely,          UNIQUE,     STDPAR,     2,          FDCat_Tech ),
75     FUNCDATA( Bin2Oct,          UNIQUE,     INTPAR,     2,          FDCat_Tech ),
76     FUNCDATA( Bin2Dec,          UNIQUE,     STDPAR,     1,          FDCat_Tech ),
77     FUNCDATA( Bin2Hex,          UNIQUE,     INTPAR,     2,          FDCat_Tech ),
78     FUNCDATA( Oct2Bin,          UNIQUE,     INTPAR,     2,          FDCat_Tech ),
79     FUNCDATA( Oct2Dec,          UNIQUE,     STDPAR,     1,          FDCat_Tech ),
80     FUNCDATA( Oct2Hex,          UNIQUE,     INTPAR,     2,          FDCat_Tech ),
81     FUNCDATA( Dec2Bin,          UNIQUE,     INTPAR,     2,          FDCat_Tech ),
82     FUNCDATA( Dec2Hex,          UNIQUE,     INTPAR,     2,          FDCat_Tech ),
83     FUNCDATA( Dec2Oct,          UNIQUE,     INTPAR,     2,          FDCat_Tech ),
84     FUNCDATA( Hex2Bin,          UNIQUE,     INTPAR,     2,          FDCat_Tech ),
85     FUNCDATA( Hex2Dec,          UNIQUE,     STDPAR,     1,          FDCat_Tech ),
86     FUNCDATA( Hex2Oct,          UNIQUE,     INTPAR,     2,          FDCat_Tech ),
87     FUNCDATA( Delta,            UNIQUE,     INTPAR,     2,          FDCat_Tech ),
88     FUNCDATA( Erf,              UNIQUE,     INTPAR,     2,          FDCat_Tech ),
89     FUNCDATA( Erfc,             UNIQUE,     STDPAR,     1,          FDCat_Tech ),
90     FUNCDATA( Gestep,           UNIQUE,     INTPAR,     2,          FDCat_Tech ),
91     FUNCDATA( Factdouble,       UNIQUE,     STDPAR,     1,          FDCat_Tech ),
92     FUNCDATA( Imabs,            UNIQUE,     STDPAR,     1,          FDCat_Tech ),
93     FUNCDATA( Imaginary,        UNIQUE,     STDPAR,     1,          FDCat_Tech ),
94     FUNCDATA( Impower,          UNIQUE,     STDPAR,     2,          FDCat_Tech ),
95     FUNCDATA( Imargument,       UNIQUE,     STDPAR,     1,          FDCat_Tech ),
96     FUNCDATA( Imcos,            UNIQUE,     STDPAR,     1,          FDCat_Tech ),
97     FUNCDATA( Imdiv,            UNIQUE,     STDPAR,     2,          FDCat_Tech ),
98     FUNCDATA( Imexp,            UNIQUE,     STDPAR,     1,          FDCat_Tech ),
99     FUNCDATA( Imconjugate,      UNIQUE,     STDPAR,     1,          FDCat_Tech ),
100     FUNCDATA( Imln,             UNIQUE,     STDPAR,     1,          FDCat_Tech ),
101     FUNCDATA( Imlog10,          UNIQUE,     STDPAR,     1,          FDCat_Tech ),
102     FUNCDATA( Imlog2,           UNIQUE,     STDPAR,     1,          FDCat_Tech ),
103     FUNCDATA( Improduct,        UNIQUE,     INTPAR,     2,          FDCat_Tech ),
104     FUNCDATA( Imreal,           UNIQUE,     STDPAR,     1,          FDCat_Tech ),
105     FUNCDATA( Imsin,            UNIQUE,     STDPAR,     1,          FDCat_Tech ),
106     FUNCDATA( Imsub,            UNIQUE,     STDPAR,     2,          FDCat_Tech ),
107     FUNCDATA( Imsqrt,           UNIQUE,     STDPAR,     1,          FDCat_Tech ),
108     FUNCDATA( Imsum,            UNIQUE,     INTPAR,     1,          FDCat_Tech ),
109     FUNCDATA( Complex,          UNIQUE,     STDPAR,     3,          FDCat_Tech ),
110     FUNCDATA( Convert,          DOUBLE,     STDPAR,     3,          FDCat_Tech ),
111     FUNCDATA( Amordegrc,        UNIQUE,     INTPAR,     7,          FDCat_Finance ),
112     FUNCDATA( Amorlinc,         UNIQUE,     INTPAR,     7,          FDCat_Finance ),
113     FUNCDATA( Accrint,          UNIQUE,     INTPAR,     7,          FDCat_Finance ),
114     FUNCDATA( Accrintm,         UNIQUE,     INTPAR,     5,          FDCat_Finance ),
115     FUNCDATA( Received,         UNIQUE,     INTPAR,     5,          FDCat_Finance ),
116     FUNCDATA( Disc,             UNIQUE,     INTPAR,     5,          FDCat_Finance ),
117     FUNCDATA( Duration,         DOUBLE,     INTPAR,     6,          FDCat_Finance ),
118     FUNCDATA( Effect,           DOUBLE,     STDPAR,     2,          FDCat_Finance ),
119     FUNCDATA( Cumprinc,         DOUBLE,     STDPAR,     6,          FDCat_Finance ),
120     FUNCDATA( Cumipmt,          DOUBLE,     STDPAR,     6,          FDCat_Finance ),
121     FUNCDATA( Price,            UNIQUE,     INTPAR,     7,          FDCat_Finance ),
122     FUNCDATA( Pricedisc,        UNIQUE,     INTPAR,     5,          FDCat_Finance ),
123     FUNCDATA( Pricemat,         UNIQUE,     INTPAR,     6,          FDCat_Finance ),
124     FUNCDATA( Mduration,        UNIQUE,     INTPAR,     6,          FDCat_Finance ),
125     FUNCDATA( Nominal,          DOUBLE,     STDPAR,     2,          FDCat_Finance ),
126     FUNCDATA( Dollarfr,         UNIQUE,     STDPAR,     2,          FDCat_Finance ),
127     FUNCDATA( Dollarde,         UNIQUE,     STDPAR,     2,          FDCat_Finance ),
128     FUNCDATA( Yield,            UNIQUE,     INTPAR,     7,          FDCat_Finance ),
129     FUNCDATA( Yielddisc,        UNIQUE,     INTPAR,     5,          FDCat_Finance ),
130     FUNCDATA( Yieldmat,         UNIQUE,     INTPAR,     6,          FDCat_Finance ),
131     FUNCDATA( Tbilleq,          UNIQUE,     INTPAR,     3,          FDCat_Finance ),
132     FUNCDATA( Tbillprice,       UNIQUE,     INTPAR,     3,          FDCat_Finance ),
133     FUNCDATA( Tbillyield,       UNIQUE,     INTPAR,     3,          FDCat_Finance ),
134     FUNCDATA( Oddfprice,        UNIQUE,     INTPAR,     9,          FDCat_Finance ),
135     FUNCDATA( Oddfyield,        UNIQUE,     INTPAR,     9,          FDCat_Finance ),
136     FUNCDATA( Oddlprice,        UNIQUE,     INTPAR,     8,          FDCat_Finance ),
137     FUNCDATA( Oddlyield,        UNIQUE,     INTPAR,     8,          FDCat_Finance ),
138     FUNCDATA( Xirr,             UNIQUE,     INTPAR,     3,          FDCat_Finance ),
139     FUNCDATA( Xnpv,             UNIQUE,     STDPAR,     3,          FDCat_Finance ),
140     FUNCDATA( Intrate,          UNIQUE,     INTPAR,     5,          FDCat_Finance ),
141     FUNCDATA( Coupncd,          UNIQUE,     INTPAR,     4,          FDCat_Finance ),
142     FUNCDATA( Coupdays,         UNIQUE,     INTPAR,     4,          FDCat_Finance ),
143     FUNCDATA( Coupdaysnc,       UNIQUE,     INTPAR,     4,          FDCat_Finance ),
144     FUNCDATA( Coupdaybs,        UNIQUE,     INTPAR,     4,          FDCat_Finance ),
145     FUNCDATA( Couppcd,          UNIQUE,     INTPAR,     4,          FDCat_Finance ),
146     FUNCDATA( Coupnum,          UNIQUE,     INTPAR,     4,          FDCat_Finance ),
147     FUNCDATA( Fvschedule,       UNIQUE,     STDPAR,     2,          FDCat_Finance )
148 };
149 #undef FUNCDATA
150 
151 
152 sal_uInt16 DaysInMonth( sal_uInt16 nMonth, sal_uInt16 nYear )
153 {
154     if( (nMonth == 2) && IsLeapYear( nYear ) )
155         return 29;
156     static const sal_uInt16 aDaysInMonth[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
157     return aDaysInMonth[ nMonth ];
158 }
159 
160 
161 /**
162  * Convert a date to a count of days starting from 01/01/0001
163  *
164  * The internal representation of a Date used in this Addin
165  * is the number of days between 01/01/0001 and the date
166  * this function converts a Day , Month, Year representation
167  * to this internal Date value.
168  *
169  */
170 
171 sal_Int32 DateToDays( sal_uInt16 nDay, sal_uInt16 nMonth, sal_uInt16 nYear )
172 {
173     sal_Int32 nDays = ((sal_Int32)nYear-1) * 365;
174     nDays += ((nYear-1) / 4) - ((nYear-1) / 100) + ((nYear-1) / 400);
175 
176     for( sal_uInt16 i = 1; i < nMonth; i++ )
177         nDays += DaysInMonth(i,nYear);
178     nDays += nDay;
179 
180     return nDays;
181 }
182 
183 
184 /**
185  * Convert a count of days starting from 01/01/0001 to a date
186  *
187  * The internal representation of a Date used in this Addin
188  * is the number of days between 01/01/0001 and the date
189  * this function converts this internal Date value
190  * to a Day , Month, Year representation of a Date.
191  *
192  */
193 
194 void DaysToDate( sal_Int32 nDays, sal_uInt16& rDay, sal_uInt16& rMonth, sal_uInt16& rYear )
195     throw( lang::IllegalArgumentException )
196 {
197     if( nDays < 0 )
198         throw lang::IllegalArgumentException();
199 
200     sal_Int32   nTempDays;
201     sal_Int32   i = 0;
202     sal_Bool    bCalc;
203 
204     do
205     {
206         nTempDays = nDays;
207         rYear = (sal_uInt16)((nTempDays / 365) - i);
208         nTempDays -= ((sal_Int32) rYear -1) * 365;
209         nTempDays -= (( rYear -1) / 4) - (( rYear -1) / 100) + ((rYear -1) / 400);
210         bCalc = sal_False;
211         if ( nTempDays < 1 )
212         {
213             i++;
214             bCalc = sal_True;
215         }
216         else
217         {
218             if ( nTempDays > 365 )
219             {
220                 if ( (nTempDays != 366) || !IsLeapYear( rYear ) )
221                 {
222                     i--;
223                     bCalc = sal_True;
224                 }
225             }
226         }
227     }
228     while ( bCalc );
229 
230     rMonth = 1;
231     while ( (sal_Int32)nTempDays > DaysInMonth( rMonth, rYear ) )
232     {
233         nTempDays -= DaysInMonth( rMonth, rYear );
234         rMonth++;
235     }
236     rDay = (sal_uInt16)nTempDays;
237 }
238 
239 
240 /**
241  * Get the null date used by the spreadsheet document
242  *
243  * The internal representation of a Date used in this Addin
244  * is the number of days between 01/01/0001 and the date
245  * this function returns this internal Date value for the document null date
246  *
247  */
248 
249 sal_Int32 GetNullDate( constREFXPS& xOpt ) THROWDEF_RTE
250 {
251     if( xOpt.is() )
252     {
253         try
254         {
255             ANY aAny = xOpt->getPropertyValue( STRFROMASCII( "NullDate" ) );
256             util::Date  aDate;
257             if( aAny >>= aDate )
258                 return DateToDays( aDate.Day, aDate.Month, aDate.Year );
259         }
260         catch( uno::Exception& )
261         {
262         }
263     }
264 
265     // no null date available -> no calculations possible
266     throw uno::RuntimeException();
267 }
268 
269 
270 sal_Int32 GetDiffDate360(
271                 sal_uInt16 nDay1, sal_uInt16 nMonth1, sal_uInt16 nYear1, sal_Bool bLeapYear1,
272                 sal_uInt16 nDay2, sal_uInt16 nMonth2, sal_uInt16 nYear2,
273                 sal_Bool bUSAMethod )
274 {
275     if( nDay1 == 31 )
276         nDay1--;
277     else if( bUSAMethod && ( nMonth1 == 2 && ( nDay1 == 29 || ( nDay1 == 28 && !bLeapYear1 ) ) ) )
278             nDay1 = 30;
279 
280     if( nDay2 == 31 )
281     {
282         if( bUSAMethod && nDay1 != 30 )
283         {
284             //aDate2 += 1;      -> 1.xx.yyyy
285             nDay2 = 1;
286             if( nMonth2 == 12 )
287             {
288                 nYear2++;
289                 nMonth2 = 1;
290             }
291             else
292                 nMonth2++;
293         }
294         else
295             nDay2 = 30;
296     }
297 
298     return nDay2 + nMonth2 * 30 + nYear2 * 360 - nDay1 - nMonth1 * 30 - nYear1 * 360;
299 }
300 
301 
302 sal_Int32 GetDiffDate360( sal_Int32 nNullDate, sal_Int32 nDate1, sal_Int32 nDate2, sal_Bool bUSAMethod )
303 {
304     nDate1 += nNullDate;
305     nDate2 += nNullDate;
306 
307     sal_uInt16 nDay1, nMonth1, nYear1, nDay2, nMonth2, nYear2;
308 
309     DaysToDate( nDate1, nDay1, nMonth1, nYear1 );
310     DaysToDate( nDate2, nDay2, nMonth2, nYear2 );
311 
312     return GetDiffDate360( nDay1, nMonth1, nYear1, IsLeapYear( nYear1 ), nDay2, nMonth2, nYear2, bUSAMethod );
313 }
314 
315 
316 sal_Int32 GetDaysInYears( sal_uInt16 nYear1, sal_uInt16 nYear2 )
317 {
318     sal_uInt16  nLeaps = 0;
319     for( sal_uInt16 n = nYear1 ; n <= nYear2 ; n++ )
320     {
321         if( IsLeapYear( n ) )
322             nLeaps++;
323     }
324 
325     sal_uInt32  nSum = 1;
326     nSum += nYear2;
327     nSum -= nYear1;
328     nSum *= 365;
329     nSum += nLeaps;
330 
331     return nSum;
332 }
333 
334 
335 void GetDiffParam( sal_Int32 nNullDate, sal_Int32 nStartDate, sal_Int32 nEndDate, sal_Int32 nMode,
336     sal_uInt16& rYears, sal_Int32& rDayDiffPart, sal_Int32& rDaysInYear ) THROWDEF_RTE_IAE
337 {
338     if( nStartDate > nEndDate )
339     {
340         sal_Int32   n = nEndDate;
341         nEndDate = nStartDate;
342         nStartDate = n;
343     }
344 
345     sal_Int32   nDate1 = nStartDate + nNullDate;
346     sal_Int32   nDate2 = nEndDate + nNullDate;
347 
348     sal_uInt16  nDay1, nDay2;
349     sal_uInt16  nMonth1, nMonth2;
350     sal_uInt16  nYear1, nYear2;
351 
352     DaysToDate( nDate1, nDay1, nMonth1, nYear1 );
353     DaysToDate( nDate2, nDay2, nMonth2, nYear2 );
354 
355     sal_uInt16  nYears;
356 
357     sal_Int32   nDayDiff, nDaysInYear;
358 
359     switch( nMode )
360     {
361         case 0:         // 0=USA (NASD) 30/360
362         case 4:         // 4=Europe 30/360
363             nDaysInYear = 360;
364             nYears = nYear2 - nYear1;
365             nDayDiff = GetDiffDate360( nDay1, nMonth1, nYear1, IsLeapYear( nYear1 ),
366                                         nDay2, nMonth2, nYear2, nMode == 0 ) - nYears * nDaysInYear;
367             break;
368         case 1:         // 1=exact/exact
369             nYears = nYear2 - nYear1;
370 
371             nDaysInYear = IsLeapYear( nYear1 )? 366 : 365;
372 
373             if( nYears && ( nMonth1 > nMonth2 || ( nMonth1 == nMonth2 && nDay1 > nDay2 ) ) )
374                 nYears--;
375 
376             if( nYears )
377                 nDayDiff = nDate2 - DateToDays( nDay1, nMonth1, nYear2 );
378             else
379                 nDayDiff = nDate2 - nDate1;
380 
381             if( nDayDiff < 0 )
382                 nDayDiff += nDaysInYear;
383 
384             break;
385         case 2:         // 2=exact/360
386             nDaysInYear = 360;
387             nYears = sal_uInt16( ( nDate2 - nDate1 ) / nDaysInYear );
388             nDayDiff = nDate2 - nDate1;
389             nDayDiff %= nDaysInYear;
390             break;
391         case 3:         //3=exact/365
392             nDaysInYear = 365;
393             nYears = sal_uInt16( ( nDate2 - nDate1 ) / nDaysInYear );
394             nDayDiff = nDate2 - nDate1;
395             nDayDiff %= nDaysInYear;
396             break;
397         default:
398             THROW_IAE;
399     }
400 
401     rYears = nYears;
402     rDayDiffPart = nDayDiff;
403     rDaysInYear = nDaysInYear;
404 }
405 
406 
407 sal_Int32 GetDiffDate( sal_Int32 nNullDate, sal_Int32 nStartDate, sal_Int32 nEndDate, sal_Int32 nMode,
408     sal_Int32* pOptDaysIn1stYear ) THROWDEF_RTE_IAE
409 {
410     sal_Bool    bNeg = nStartDate > nEndDate;
411 
412     if( bNeg )
413     {
414         sal_Int32   n = nEndDate;
415         nEndDate = nStartDate;
416         nStartDate = n;
417     }
418 
419     sal_Int32       nRet;
420 
421     switch( nMode )
422     {
423         case 0:         // 0=USA (NASD) 30/360
424         case 4:         // 4=Europe 30/360
425             {
426             sal_uInt16      nD1, nM1, nY1, nD2, nM2, nY2;
427 
428             nStartDate += nNullDate;
429             nEndDate += nNullDate;
430 
431             DaysToDate( nStartDate, nD1, nM1, nY1 );
432             DaysToDate( nEndDate, nD2, nM2, nY2 );
433 
434             sal_Bool        bLeap = IsLeapYear( nY1 );
435             sal_Int32       nDays, nMonths/*, nYears*/;
436 
437             nMonths = nM2 - nM1;
438             nDays = nD2 - nD1;
439 
440             nMonths += ( nY2 - nY1 ) * 12;
441 
442             nRet = nMonths * 30 + nDays;
443             if( nMode == 0 && nM1 == 2 && nM2 != 2 && nY1 == nY2 )
444                 nRet -= bLeap? 1 : 2;
445 
446             if( pOptDaysIn1stYear )
447                 *pOptDaysIn1stYear = 360;
448             }
449             break;
450         case 1:         // 1=exact/exact
451             if( pOptDaysIn1stYear )
452             {
453                 sal_uInt16      nD, nM, nY;
454 
455                 DaysToDate( nStartDate + nNullDate, nD, nM, nY );
456 
457                 *pOptDaysIn1stYear = IsLeapYear( nY )? 366 : 365;
458             }
459             nRet = nEndDate - nStartDate;
460             break;
461         case 2:         // 2=exact/360
462             nRet = nEndDate - nStartDate;
463             if( pOptDaysIn1stYear )
464                 *pOptDaysIn1stYear = 360;
465             break;
466         case 3:         //3=exact/365
467             nRet = nEndDate - nStartDate;
468             if( pOptDaysIn1stYear )
469                 *pOptDaysIn1stYear = 365;
470             break;
471         default:
472             THROW_IAE;
473     }
474 
475     return bNeg? -nRet : nRet;
476 }
477 
478 
479 double GetYearDiff( sal_Int32 nNullDate, sal_Int32 nStartDate, sal_Int32 nEndDate, sal_Int32 nMode ) THROWDEF_RTE_IAE
480 {
481     sal_Int32   nDays1stYear;
482     sal_Int32   nTotalDays = GetDiffDate( nNullDate, nStartDate, nEndDate, nMode, &nDays1stYear );
483 
484     return double( nTotalDays ) / double( nDays1stYear );
485 }
486 
487 
488 sal_Int32 GetDaysInYear( sal_Int32 nNullDate, sal_Int32 nDate, sal_Int32 nMode ) THROWDEF_RTE_IAE
489 {
490     switch( nMode )
491     {
492         case 0:         // 0=USA (NASD) 30/360
493         case 2:         // 2=exact/360
494         case 4:         // 4=Europe 30/360
495             return 360;
496         case 1:         // 1=exact/exact
497             {
498             sal_uInt16  nD, nM, nY;
499             nDate += nNullDate;
500             DaysToDate( nDate, nD, nM, nY );
501             return IsLeapYear( nY )? 366 : 365;
502             }
503         case 3:         //3=exact/365
504             return 365;
505         default:
506             THROW_IAE;
507     }
508 }
509 
510 
511 double GetYearFrac( sal_Int32 nNullDate, sal_Int32 nStartDate, sal_Int32 nEndDate, sal_Int32 nMode ) THROWDEF_RTE_IAE
512 {
513     if( nStartDate == nEndDate )
514         return 0.0;     // nothing to do...
515 
516     sal_uInt16  nYears;
517     sal_Int32   nDayDiff, nDaysInYear;
518 
519     GetDiffParam( nNullDate, nStartDate, nEndDate, nMode, nYears, nDayDiff, nDaysInYear );
520 
521     return double( nYears ) + double( nDayDiff ) / double( nDaysInYear );
522 }
523 
524 
525 double Fak( sal_Int32 n )
526 {
527     if( n > 0 )
528     {
529         double  fRet = n;
530         double  f = n - 1;
531 
532         while( f >= 2.0 )
533         {
534             fRet *= f;
535             f--;
536         }
537 
538         return fRet;
539     }
540     else if( !n )
541         return 1.0;
542     else
543         return 0.0;
544 }
545 
546 
547 double GetGcd( double f1, double f2 )
548 {
549     double  f = fmod( f1, f2 );
550     while( f > 0.0 )
551     {
552         f1 = f2;
553         f2 = f;
554         f = fmod( f1, f2 );
555     }
556 
557     return f2;
558 }
559 
560 
561 double ConvertToDec( const STRING& aStr, sal_uInt16 nBase, sal_uInt16 nCharLim ) THROWDEF_RTE_IAE
562 {
563     if ( nBase < 2 || nBase > 36 )
564         THROW_IAE;
565 
566     sal_uInt32      nStrLen = aStr.getLength();
567     if( nStrLen > nCharLim )
568         THROW_IAE;
569     else if( !nStrLen )
570         return 0.0;
571 
572     double          fVal = 0.0;
573 
574     register const sal_Unicode* p = aStr.getStr();
575 
576     sal_uInt16          nFirstDig = 0;
577     sal_Bool            bFirstDig = sal_True;
578     double              fBase = nBase;
579 
580     while ( *p )
581     {
582         sal_uInt16      n;
583 
584         if( '0' <= *p && *p <= '9' )
585             n = *p - '0';
586         else if( 'A' <= *p && *p <= 'Z' )
587             n = 10 + ( *p - 'A' );
588         else if ( 'a' <= *p && *p <= 'z' )
589             n = 10 + ( *p - 'a' );
590         else
591             n = nBase;
592 
593         if( n < nBase )
594         {
595             if( bFirstDig )
596             {
597                 bFirstDig = sal_False;
598                 nFirstDig = n;
599             }
600             fVal = fVal * fBase + double( n );
601         }
602         else
603             // illegal char!
604             THROW_IAE;
605 
606         p++;
607 
608     }
609 
610     if( nStrLen == nCharLim && !bFirstDig && (nFirstDig >= nBase / 2) )
611     {   // handling negativ values
612         fVal = ( pow( double( nBase ), double( nCharLim ) ) - fVal );   // complement
613         fVal *= -1.0;
614     }
615 
616     return fVal;
617 }
618 
619 
620 static inline sal_Char GetMaxChar( sal_uInt16 nBase )
621 {
622     const sal_Char* c = "--123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
623     return c[ nBase ];
624 }
625 
626 
627 STRING ConvertFromDec( double fNum, double fMin, double fMax, sal_uInt16 nBase,
628     sal_Int32 nPlaces, sal_Int32 nMaxPlaces, sal_Bool bUsePlaces ) THROWDEF_RTE_IAE
629 {
630     fNum = ::rtl::math::approxFloor( fNum );
631     fMin = ::rtl::math::approxFloor( fMin );
632     fMax = ::rtl::math::approxFloor( fMax );
633 
634     if( fNum < fMin || fNum > fMax || ( bUsePlaces && ( nPlaces <= 0 || nPlaces > nMaxPlaces ) ) )
635         THROW_IAE;
636 
637     sal_Int64 nNum = static_cast< sal_Int64 >( fNum );
638     sal_Bool        bNeg = nNum < 0;
639     if( bNeg )
640         nNum = sal_Int64( pow( double( nBase ), double( nMaxPlaces ) ) ) + nNum;
641 
642     STRING          aRet( STRING::valueOf( nNum, nBase ).toAsciiUpperCase() );
643 
644 
645     if( bUsePlaces )
646     {
647         sal_Int32 nLen = aRet.getLength();
648         if( !bNeg && nLen > nPlaces )
649         {
650             THROW_IAE;
651         }
652         else if( ( bNeg && nLen < nMaxPlaces ) || ( !bNeg && nLen < nPlaces ) )
653         {
654             sal_Int32   nLeft = nPlaces - nLen;
655             sal_Char*   p = new sal_Char[ nLeft + 1 ];
656             memset( p, bNeg? GetMaxChar( nBase ) : '0', nLeft );
657             p[ nLeft ] = 0x00;
658             STRING  aTmp( p, nLeft, RTL_TEXTENCODING_MS_1252 );
659             aTmp += aRet;
660             aRet = aTmp;
661 
662             delete[] p;
663         }
664     }
665 
666     return aRet;
667 }
668 
669 // implementation moved to module sal, see #i97091#
670 double Erf( double x )
671 {
672     return ::rtl::math::erf(x);
673 }
674 
675 // implementation moved to module sal, see #i97091#
676 double Erfc( double x )
677 {
678     return ::rtl::math::erfc(x);
679 }
680 
681 inline sal_Bool IsNum( sal_Unicode c )
682 {
683     return c >= '0' && c <= '9';
684 }
685 
686 
687 inline sal_Bool IsComma( sal_Unicode c )
688 {
689     return c == '.' || c == ',';
690 }
691 
692 
693 inline sal_Bool IsExpStart( sal_Unicode c )
694 {
695     return c == 'e' || c == 'E';
696 }
697 
698 
699 inline sal_Bool IsImagUnit( sal_Unicode c )
700 {
701     return c == 'i' || c == 'j';
702 }
703 
704 
705 inline sal_uInt16 GetVal( sal_Unicode c )
706 {
707     return sal_uInt16( c - '0' );
708 }
709 
710 
711 sal_Bool ParseDouble( const sal_Unicode*& rp, double& rRet )
712 {
713     double              fInt = 0.0;
714     double              fFrac = 0.0;
715     double              fMult = 0.1;    // multiplier to multiply digits with, when adding fractional ones
716     sal_Int32           nExp = 0;
717     sal_Int32           nMaxExp = 307;
718     sal_uInt16          nDigCnt = 18;   // max. number of digits to read in, rest doesn't matter
719 
720     enum State  { S_End = 0, S_Sign, S_IntStart, S_Int, S_IgnoreIntDigs, S_Frac, S_IgnoreFracDigs, S_ExpSign, S_Exp };
721 
722     State           eS = S_Sign;
723 
724     sal_Bool            bNegNum = sal_False;
725     sal_Bool            bNegExp = sal_False;
726 
727     const sal_Unicode*  p = rp;
728     sal_Unicode         c;
729 
730     while( eS )
731     {
732         c = *p;
733         switch( eS )
734         {
735             case S_Sign:
736                 if( IsNum( c ) )
737                 {
738                     fInt = GetVal( c );
739                     nDigCnt--;
740                     eS = S_Int;
741                 }
742                 else if( c == '-' )
743                 {
744                     bNegNum = sal_True;
745                     eS = S_IntStart;
746                 }
747                 else if( c == '+' )
748                     eS = S_IntStart;
749                 else if( IsComma( c ) )
750                     eS = S_Frac;
751                 else
752                     return sal_False;
753                 break;
754             case S_IntStart:
755                 if( IsNum( c ) )
756                 {
757                     fInt = GetVal( c );
758                     nDigCnt--;
759                     eS = S_Int;
760                 }
761                 else if( IsComma( c ) )
762                     eS = S_Frac;
763                 else if( IsImagUnit( c ) )
764                 {
765                     rRet = 0.0;
766                     return sal_True;
767                 }
768                 else
769                     return sal_False;
770                 break;
771             case S_Int:
772                 if( IsNum( c ) )
773                 {
774                     fInt *= 10.0;
775                     fInt += double( GetVal( c ) );
776                     nDigCnt--;
777                     if( !nDigCnt )
778                         eS = S_IgnoreIntDigs;
779                 }
780                 else if( IsComma( c ) )
781                     eS = S_Frac;
782                 else if( IsExpStart( c ) )
783                     eS = S_ExpSign;
784                 else
785                     eS = S_End;
786                 break;
787             case S_IgnoreIntDigs:
788                 if( IsNum( c ) )
789                     nExp++;         // just multiply num with 10... ;-)
790                 else if( IsComma( c ) )
791                     eS = S_Frac;
792                 else if( IsExpStart( c ) )
793                     eS = S_ExpSign;
794                 else
795                     eS = S_End;
796                 break;
797             case S_Frac:
798                 if( IsNum( c ) )
799                 {
800                     fFrac += double( GetVal( c ) ) * fMult;
801                     nDigCnt--;
802                     if( nDigCnt )
803                         fMult *= 0.1;
804                     else
805                         eS = S_IgnoreFracDigs;
806                 }
807                 else if( IsExpStart( c ) )
808                     eS = S_ExpSign;
809                 else
810                     eS = S_End;
811                 break;
812             case S_IgnoreFracDigs:
813                 if( IsExpStart( c ) )
814                     eS = S_ExpSign;
815                 else if( !IsNum( c ) )
816                     eS = S_End;
817                 break;
818             case S_ExpSign:
819                 if( IsNum( c ) )
820                 {
821                     nExp = GetVal( c );
822                     eS = S_Exp;
823                 }
824                 else if( c == '-' )
825                 {
826                     bNegExp = sal_True;
827                     eS = S_Exp;
828                 }
829                 else if( c != '+' )
830                     eS = S_End;
831                 break;
832             case S_Exp:
833                 if( IsNum( c ) )
834                 {
835                     nExp *= 10;
836                     nExp += GetVal( c );
837                     if( nExp > nMaxExp )
838                         return sal_False;
839                 }
840                 else
841                     eS = S_End;
842                 break;
843             case S_End:     // to avoid compiler warning
844                 break;      // loop exits anyway
845         }
846 
847         p++;
848     }
849 
850     p--;        // set pointer back to last
851     rp = p;
852 
853     fInt += fFrac;
854     sal_Int32   nLog10 = sal_Int32( log10( fInt ) );
855 
856     if( bNegExp )
857         nExp = -nExp;
858 
859     if( nLog10 + nExp > nMaxExp )
860         return sal_False;
861 
862     fInt = ::rtl::math::pow10Exp( fInt, nExp );
863 
864     if( bNegNum )
865         fInt = -fInt;
866 
867     rRet = fInt;
868 
869     return sal_True;
870 }
871 
872 
873 STRING GetString( double f, sal_Bool bLeadingSign, sal_uInt16 nMaxDig )
874 {
875     const int       nBuff = 256;
876     sal_Char        aBuff[ nBuff + 1 ];
877     const char*     pFormStr = bLeadingSign? "%+.*g" : "%.*g";
878     int             nLen = snprintf( aBuff, nBuff, pFormStr, int( nMaxDig ), f );
879                     // you never know which underlying implementation you get ...
880                     aBuff[nBuff] = 0;
881                     if ( nLen < 0 || nLen > nBuff )
882                         nLen = strlen( aBuff );
883 
884     STRING          aRet( aBuff, nLen, RTL_TEXTENCODING_MS_1252 );
885 
886     return aRet;
887 }
888 
889 
890 double GetAmordegrc( sal_Int32 nNullDate, double fCost, sal_Int32 nDate, sal_Int32 nFirstPer,
891     double fRestVal, double fPer, double fRate, sal_Int32 nBase ) THROWDEF_RTE_IAE
892 {
893     if( nBase == 2 )
894         THROW_IAE;
895 
896     sal_uInt32  nPer = sal_uInt32( fPer );
897     double      fUsePer = 1.0 / fRate;
898     double      fAmorCoeff;
899 
900     if( fUsePer < 3.0 )
901         fAmorCoeff = 1.0;
902     else if( fUsePer < 5.0 )
903         fAmorCoeff = 1.5;
904     else if( fUsePer <= 6.0 )
905         fAmorCoeff = 2.0;
906     else
907         fAmorCoeff = 2.5;
908 
909     fRate *= fAmorCoeff;
910     double      fNRate = ::rtl::math::round( GetYearFrac( nNullDate, nDate, nFirstPer, nBase ) * fRate * fCost, 0 );
911     fCost -= fNRate;
912     double      fRest = fCost - fRestVal;   // Anschaffungskosten - Restwert - Summe aller Abschreibungen
913 
914     for( sal_uInt32 n = 0 ; n < nPer ; n++ )
915     {
916         fNRate = ::rtl::math::round( fRate * fCost, 0 );
917         fRest -= fNRate;
918 
919         if( fRest < 0.0 )
920         {
921             switch( nPer - n )
922             {
923                 case 0:
924                 case 1:
925                     return ::rtl::math::round( fCost * 0.5, 0 );
926                 default:
927                     return 0.0;
928             }
929         }
930 
931         fCost -= fNRate;
932     }
933 
934     return fNRate;
935 }
936 
937 
938 double GetAmorlinc( sal_Int32 nNullDate, double fCost, sal_Int32 nDate, sal_Int32 nFirstPer,
939     double fRestVal, double fPer, double fRate, sal_Int32 nBase ) THROWDEF_RTE_IAE
940 {
941     if( nBase == 2 )
942         THROW_IAE;
943 
944     sal_uInt32  nPer = sal_uInt32( fPer );
945     double      fOneRate = fCost * fRate;
946     double      fCostDelta = fCost - fRestVal;
947     double      f0Rate = GetYearFrac( nNullDate, nDate, nFirstPer, nBase ) * fRate * fCost;
948     sal_uInt32  nNumOfFullPeriods = sal_uInt32( ( fCost - fRestVal - f0Rate) / fOneRate );
949 
950     if( nPer == 0 )
951         return f0Rate;
952     else if( nPer <= nNumOfFullPeriods )
953         return fOneRate;
954     else if( nPer == nNumOfFullPeriods + 1 )
955         return fCostDelta - fOneRate * nNumOfFullPeriods - f0Rate;
956     else
957         return 0.0;
958 }
959 
960 
961 double GetDuration( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, double fCoup,
962     double fYield, sal_Int32 nFreq, sal_Int32 nBase ) THROWDEF_RTE_IAE
963 {
964     double          fYearfrac = GetYearFrac( nNullDate, nSettle, nMat, nBase );
965     double          fNumOfCoups = GetCoupnum( nNullDate, nSettle, nMat, nFreq, nBase );
966     double          fDur = 0.0;
967     const double    f100 = 100.0;
968     fCoup *= f100 / double( nFreq );    // fCoup is used as cash flow
969     fYield /= nFreq;
970     fYield += 1.0;
971 
972     double nDiff = fYearfrac * nFreq - fNumOfCoups;
973 
974     double          t;
975 
976     for( t = 1.0 ; t < fNumOfCoups ; t++ )
977         fDur += ( t + nDiff ) * ( fCoup ) / pow( fYield, t + nDiff );
978 
979     fDur += ( fNumOfCoups + nDiff ) * ( fCoup + f100 ) / pow( fYield, fNumOfCoups + nDiff );
980 
981     double          p = 0.0;
982     for( t = 1.0 ; t < fNumOfCoups ; t++ )
983         p += fCoup / pow( fYield, t + nDiff );
984 
985     p += ( fCoup + f100 ) / pow( fYield, fNumOfCoups + nDiff );
986 
987     fDur /= p;
988     fDur /= double( nFreq );
989 
990     return fDur;
991 }
992 
993 
994 double GetYieldmat( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nIssue,
995     double fRate, double fPrice, sal_Int32 nBase ) THROWDEF_RTE_IAE
996 {
997     double      fIssMat = GetYearFrac( nNullDate, nIssue, nMat, nBase );
998     double      fIssSet = GetYearFrac( nNullDate, nIssue, nSettle, nBase );
999     double      fSetMat = GetYearFrac( nNullDate, nSettle, nMat, nBase );
1000 
1001     double      y = 1.0 + fIssMat * fRate;
1002     y /= fPrice / 100.0 + fIssSet * fRate;
1003     y--;
1004     y /= fSetMat;
1005 
1006     return y;
1007 }
1008 
1009 
1010 double GetOddfprice( sal_Int32 /*nNullDate*/, sal_Int32 /*nSettle*/, sal_Int32 /*nMat*/, sal_Int32 /*nIssue*/,
1011     sal_Int32 /*nFirstCoup*/, double /*fRate*/, double /*fYield*/, double /*fRedemp*/, sal_Int32 /*nFreq*/,
1012     sal_Int32 /*nBase*/ ) THROWDEF_RTE_IAE
1013 {
1014     THROW_RTE;  // #87380#
1015 /*
1016     double      fN = GetCoupnum( nNullDate, nSettle, nMat, nFreq, nBase ) - 1.0;
1017     double      fNq = GetCoupnum( nNullDate, nSettle, nFirstCoup, nFreq, nBase ) - 1.0;
1018     double      fDSC = GetCoupdaysnc( nNullDate, nSettle, nFirstCoup, nFreq, nBase );
1019     double      fDSC_E = fDSC / GetCoupdays( nNullDate, nSettle, nMat, nFreq, nBase );
1020     double      fNC = GetCoupnum( nNullDate, nIssue, nFirstCoup, nFreq, nBase );
1021     sal_uInt32  nNC = sal_uInt32( fNC );
1022     sal_uInt16  nMonthDelta = 12 / sal_uInt16( nFreq );
1023 
1024     sal_uInt32  i;
1025     double      f1YieldFreq = 1.0 + fYield / double( nFreq );
1026     double      f100RateFreq = 100.0 * fRate / double( nFreq );
1027 
1028     double*     pDC = new double[ nNC + 1 ];
1029     double*     pNL = new double[ nNC + 1 ];
1030     double*     pA = new double[ nNC + 1 ];
1031 
1032     pDC[ 0 ] = pNL[ 0 ] = pA[ 0 ] = 1.0;
1033 
1034     ScaDate aStartDate( nNullDate, nSettle, nBase );
1035     ScaDate aNextCoup( nNullDate, nFirstCoup, nBase );
1036     if( nNC )
1037     {
1038         pDC[ 1 ] = ScaDate::GetDiff( aStartDate, aNextCoup );
1039         pNL[ 1 ] = GetCoupdays( nNullDate, nSettle, nFirstCoup, nFreq, nBase );
1040         pA[ 1 ] = pDC[ 1 ];
1041         ScaDate aPre;
1042         for( i = 1 ; i <= nNC ; i++ )
1043         {
1044             aPre = aStartDate;
1045             aStartDate.addMonths( nMonthDelta );
1046             aNextCoup.addMonths( nMonthDelta );
1047             pDC[ i ] = ScaDate::GetDiff( aPre, aStartDate );
1048             pNL[ i ] = GetCoupdays( nNullDate, aStartDate.GetDate( nNullDate ), aNextCoup.GetDate( nNullDate ),
1049                                         nFreq, nBase );
1050             pA[ i ] = ScaDate::GetDiff( aStartDate, aNextCoup );
1051         }
1052     }
1053 
1054     double      fT1 = fRedemp / pow( f1YieldFreq, fN + fNq + fDSC_E );
1055 
1056     double      fT2 = 0.0;
1057     for( i = 1 ; i <= nNC ; i++ )
1058         fT2 += pDC[ i ] / pNL[ i ];
1059     fT2 *= f100RateFreq / pow( f1YieldFreq, fNq + fDSC_E );
1060 
1061     double      fT3 = 0.0;
1062     for( double k = 2.0 ; k <= fN ; k++ )
1063         fT3 += 1.0 / pow( f1YieldFreq, k - fNq + fDSC_E );
1064     fT3 *= f100RateFreq;
1065 
1066     double      fT4 = 0.0;
1067     for( i = 1 ; i <= nNC ; i++ )
1068         fT4 += pA[ i ] / pNL[ i ];
1069     fT4 *= f100RateFreq;
1070 
1071     if( nNC )
1072     {
1073         delete pDC;
1074         delete pNL;
1075         delete pA;
1076     }
1077 
1078     return fT1 + fT2 + fT3 - fT4;
1079 */
1080 }
1081 
1082 
1083 double getYield_( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, double fCoup, double fPrice,
1084                     double fRedemp, sal_Int32 nFreq, sal_Int32 nBase ) THROWDEF_RTE_IAE
1085 {
1086     double      fRate = fCoup;
1087     double      fPriceN = 0.0;
1088     double      fYield1 = 0.0;
1089     double      fYield2 = 1.0;
1090     double      fPrice1 = getPrice_( nNullDate, nSettle, nMat, fRate, fYield1, fRedemp, nFreq, nBase );
1091     double      fPrice2 = getPrice_( nNullDate, nSettle, nMat, fRate, fYield2, fRedemp, nFreq, nBase );
1092     double      fYieldN = ( fYield2 - fYield1 ) * 0.5;
1093 
1094     for( sal_uInt32 nIter = 0 ; nIter < 100 && fPriceN != fPrice ; nIter++ )
1095     {
1096         fPriceN = getPrice_( nNullDate, nSettle, nMat, fRate, fYieldN, fRedemp, nFreq, nBase );
1097 
1098         if( fPrice == fPrice1 )
1099             return fYield1;
1100         else if( fPrice == fPrice2 )
1101             return fYield2;
1102         else if( fPrice == fPriceN )
1103             return fYieldN;
1104         else if( fPrice < fPrice2 )
1105         {
1106             fYield2 *= 2.0;
1107             fPrice2 = getPrice_( nNullDate, nSettle, nMat, fRate, fYield2, fRedemp, nFreq, nBase );
1108 
1109             fYieldN = ( fYield2 - fYield1 ) * 0.5;
1110         }
1111         else
1112         {
1113             if( fPrice < fPriceN )
1114             {
1115                 fYield1 = fYieldN;
1116                 fPrice1 = fPriceN;
1117             }
1118             else
1119             {
1120                 fYield2 = fYieldN;
1121                 fPrice2 = fPriceN;
1122             }
1123 
1124             fYieldN = fYield2 - ( fYield2 - fYield1 ) * ( ( fPrice - fPrice2 ) / ( fPrice1 - fPrice2 ) );
1125         }
1126     }
1127 
1128     if( fabs( fPrice - fPriceN ) > fPrice / 100.0 )
1129         THROW_IAE;      // result not precise enough
1130 
1131     return fYieldN;
1132 }
1133 
1134 
1135 double getPrice_( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, double fRate, double fYield,
1136                     double fRedemp, sal_Int32 nFreq, sal_Int32 nBase ) THROWDEF_RTE_IAE
1137 {
1138     double      fFreq = nFreq;
1139 
1140     double      fE = GetCoupdays( nNullDate, nSettle, nMat, nFreq, nBase );
1141     double      fDSC_E = GetCoupdaysnc( nNullDate, nSettle, nMat, nFreq, nBase ) / fE;
1142     double      fN = GetCoupnum( nNullDate, nSettle, nMat, nFreq, nBase );
1143     double      fA = GetCoupdaybs( nNullDate, nSettle, nMat, nFreq, nBase );
1144 
1145     double      fRet = fRedemp / ( pow( 1.0 + fYield / fFreq, fN - 1.0 + fDSC_E ) );
1146     fRet -= 100.0 * fRate / fFreq * fA / fE;
1147 
1148     double      fT1 = 100.0 * fRate / fFreq;
1149     double      fT2 = 1.0 + fYield / fFreq;
1150 
1151     for( double fK = 0.0 ; fK < fN ; fK++ )
1152         fRet += fT1 / pow( fT2, fK + fDSC_E );
1153 
1154     return fRet;
1155 }
1156 
1157 
1158 double GetOddfyield( sal_Int32 /*nNullDate*/, sal_Int32 /*nSettle*/, sal_Int32 /*nMat*/, sal_Int32 /*nIssue*/,
1159     sal_Int32 /*nFirstCoup*/, double /*fRate*/, double /*fPrice*/, double /*fRedemp*/, sal_Int32 /*nFreq*/,
1160     sal_Int32 /*nBase*/ ) THROWDEF_RTE_IAE
1161 {
1162     THROW_RTE;  // #87380#
1163 /*
1164     //GetOddfprice( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nIssue,
1165     //sal_Int32 nFirstCoup, double fRate, double fYield, double fRedemp, sal_Int32 nFreq,
1166     //sal_Int32 nBase )
1167     double      fPriceN = 0.0;
1168     double      fYield1 = 0.0;
1169     double      fYield2 = 1.0;
1170     double      fPrice1 = GetOddfprice( nNullDate, nSettle, nMat, nIssue, nFirstCoup, fRate, fYield1, fRedemp, nFreq, nBase );
1171     double      fPrice2 = GetOddfprice( nNullDate, nSettle, nMat, nIssue, nFirstCoup, fRate, fYield2, fRedemp, nFreq, nBase );
1172     double      fYieldN = ( fYield2 - fYield1 ) * 0.5;
1173 
1174     for( sal_uInt32 nIter = 0 ; nIter < 100 && fPriceN != fPrice ; nIter++ )
1175     {
1176         fPriceN = GetOddfprice( nNullDate, nSettle, nMat, nIssue, nFirstCoup, fRate, fYieldN, fRedemp, nFreq, nBase );
1177 
1178         if( fPrice == fPrice1 )
1179             return fYield1;
1180         else if( fPrice == fPrice2 )
1181             return fYield2;
1182         else if( fPrice == fPriceN )
1183             return fYieldN;
1184         else if( fPrice < fPrice2 )
1185         {
1186             fYield2 *= 2.0;
1187             fPrice2 = GetOddfprice( nNullDate, nSettle, nMat, nIssue, nFirstCoup, fRate, fYield2, fRedemp, nFreq, nBase );
1188 
1189             fYieldN = ( fYield2 - fYield1 ) * 0.5;
1190         }
1191         else
1192         {
1193             if( fPrice < fPriceN )
1194             {
1195                 fYield1 = fYieldN;
1196                 fPrice1 = fPriceN;
1197             }
1198             else
1199             {
1200                 fYield2 = fYieldN;
1201                 fPrice2 = fPriceN;
1202             }
1203 
1204             fYieldN = fYield2 - ( fYield2 - fYield1 ) * ( ( fPrice - fPrice2 ) / ( fPrice1 - fPrice2 ) );
1205         }
1206     }
1207 
1208     if( fabs( fPrice - fPriceN ) > fPrice / 100.0 )
1209         THROW_IAE;      // result not precise enough
1210 
1211     return fYieldN;
1212 */
1213 }
1214 
1215 
1216 double GetOddlprice( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nLastCoup,
1217     double fRate, double fYield, double fRedemp, sal_Int32 nFreq, sal_Int32 nBase ) THROWDEF_RTE_IAE
1218 {
1219     double      fFreq = double( nFreq );
1220     double      fDCi = GetYearFrac( nNullDate, nLastCoup, nMat, nBase ) * fFreq;
1221     double      fDSCi = GetYearFrac( nNullDate, nSettle, nMat, nBase ) * fFreq;
1222     double      fAi = GetYearFrac( nNullDate, nLastCoup, nSettle, nBase ) * fFreq;
1223 
1224     double      p = fRedemp + fDCi * 100.0 * fRate / fFreq;
1225     p /= fDSCi * fYield / fFreq + 1.0;
1226     p -= fAi * 100.0 * fRate / fFreq;
1227 
1228     return p;
1229 }
1230 
1231 
1232 double GetOddlyield( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nLastCoup,
1233     double fRate, double fPrice, double fRedemp, sal_Int32 nFreq, sal_Int32 nBase ) THROWDEF_RTE_IAE
1234 {
1235     double      fFreq = double( nFreq );
1236     double      fDCi = GetYearFrac( nNullDate, nLastCoup, nMat, nBase ) * fFreq;
1237     double      fDSCi = GetYearFrac( nNullDate, nSettle, nMat, nBase ) * fFreq;
1238     double      fAi = GetYearFrac( nNullDate, nLastCoup, nSettle, nBase ) * fFreq;
1239 
1240     double      y = fRedemp + fDCi * 100.0 * fRate / fFreq;
1241     y /= fPrice + fAi * 100.0 * fRate / fFreq;
1242     y--;
1243     y *= fFreq / fDSCi;
1244 
1245     return y;
1246 }
1247 
1248 
1249 double GetRmz( double fZins, double fZzr, double fBw, double fZw, sal_Int32 nF )
1250 {
1251     double      fRmz;
1252     if( fZins == 0.0 )
1253         fRmz = ( fBw + fZw ) / fZzr;
1254     else
1255     {
1256         double  fTerm = pow( 1.0 + fZins, fZzr );
1257         if( nF > 0 )
1258             fRmz = ( fZw * fZins / ( fTerm - 1.0 ) + fBw * fZins / ( 1.0 - 1.0 / fTerm ) ) / ( 1.0 + fZins );
1259         else
1260             fRmz = fZw * fZins / ( fTerm - 1.0 ) + fBw * fZins / ( 1.0 - 1.0 / fTerm );
1261     }
1262 
1263     return -fRmz;
1264 }
1265 
1266 
1267 double GetZw( double fZins, double fZzr, double fRmz, double fBw, sal_Int32 nF )
1268 {
1269     double      fZw;
1270     if( fZins == 0.0 )
1271         fZw = fBw + fRmz * fZzr;
1272     else
1273     {
1274         double  fTerm = pow( 1.0 + fZins, fZzr );
1275         if( nF > 0 )
1276             fZw = fBw * fTerm + fRmz * ( 1.0 + fZins ) * ( fTerm - 1.0 ) / fZins;
1277         else
1278             fZw = fBw * fTerm + fRmz * ( fTerm - 1.0 ) / fZins;
1279     }
1280 
1281     return -fZw;
1282 }
1283 
1284 
1285 /*double TBillYield( constREFXPS& xOpt, sal_Int32 nSettle, sal_Int32 nMat, double fPrice ) THROWDEF_RTE_IAE
1286 {
1287     sal_Int32   nDiff = GetDiffDate360( xOpt, nSettle, nMat, sal_True );
1288 
1289     if( fPrice <= 0.0 || nSettle >= nMat || nDiff > 360 )
1290         THROW_IAE;
1291 
1292     double      fRet = 100.0;
1293     fRet /= fPrice;
1294     fRet--;
1295     fRet *= double( nDiff );
1296     fRet /= 360.0;
1297 
1298     return fRet;
1299 }*/
1300 
1301 
1302 //-----------------------------------------------------------------------------
1303 // financial functions COUP***
1304 
1305 
1306 //-------
1307 // COUPPCD: find last coupon date before settlement (can be equal to settlement)
1308 void lcl_GetCouppcd( ScaDate& rDate, const ScaDate& rSettle, const ScaDate& rMat, sal_Int32 nFreq )
1309     throw( lang::IllegalArgumentException )
1310 {
1311     rDate = rMat;
1312     rDate.setYear( rSettle.getYear() );
1313     if( rDate < rSettle )
1314         rDate.addYears( 1 );
1315     while( rDate > rSettle )
1316         rDate.addMonths( -12 / nFreq );
1317 }
1318 
1319 double GetCouppcd( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nFreq, sal_Int32 nBase )
1320     THROWDEF_RTE_IAE
1321 {
1322     if( nSettle >= nMat || CHK_Freq )
1323         THROW_IAE;
1324 
1325     ScaDate aDate;
1326     lcl_GetCouppcd( aDate, ScaDate( nNullDate, nSettle, nBase ), ScaDate( nNullDate, nMat, nBase ), nFreq );
1327     return aDate.getDate( nNullDate );
1328 }
1329 
1330 
1331 //-------
1332 // COUPNCD: find first coupon date after settlement (is never equal to settlement)
1333 void lcl_GetCoupncd( ScaDate& rDate, const ScaDate& rSettle, const ScaDate& rMat, sal_Int32 nFreq )
1334     throw( lang::IllegalArgumentException )
1335 {
1336     rDate = rMat;
1337     rDate.setYear( rSettle.getYear() );
1338     if( rDate > rSettle )
1339         rDate.addYears( -1 );
1340     while( rDate <= rSettle )
1341         rDate.addMonths( 12 / nFreq );
1342 }
1343 
1344 double GetCoupncd( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nFreq, sal_Int32 nBase )
1345     THROWDEF_RTE_IAE
1346 {
1347     if( nSettle >= nMat || CHK_Freq )
1348         THROW_IAE;
1349 
1350     ScaDate aDate;
1351     lcl_GetCoupncd( aDate, ScaDate( nNullDate, nSettle, nBase ), ScaDate( nNullDate, nMat, nBase ), nFreq );
1352     return aDate.getDate( nNullDate );
1353 }
1354 
1355 
1356 //-------
1357 // COUPDAYBS: get day count: coupon date before settlement <-> settlement
1358 double GetCoupdaybs( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nFreq, sal_Int32 nBase )
1359     THROWDEF_RTE_IAE
1360 {
1361     if( nSettle >= nMat || CHK_Freq )
1362         THROW_IAE;
1363 
1364     ScaDate aSettle( nNullDate, nSettle, nBase );
1365     ScaDate aDate;
1366     lcl_GetCouppcd( aDate, aSettle, ScaDate( nNullDate, nMat, nBase ), nFreq );
1367     return ScaDate::getDiff( aDate, aSettle );
1368 }
1369 
1370 
1371 //-------
1372 // COUPDAYSNC: get day count: settlement <-> coupon date after settlement
1373 double GetCoupdaysnc( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nFreq, sal_Int32 nBase )
1374     THROWDEF_RTE_IAE
1375 {
1376     if( nSettle >= nMat || CHK_Freq )
1377         THROW_IAE;
1378 
1379     if( (nBase != 0) && (nBase != 4) )
1380     {
1381         ScaDate aSettle( nNullDate, nSettle, nBase );
1382         ScaDate aDate;
1383         lcl_GetCoupncd( aDate, aSettle, ScaDate( nNullDate, nMat, nBase ), nFreq );
1384         return ScaDate::getDiff( aSettle, aDate );
1385     }
1386     return GetCoupdays( nNullDate, nSettle, nMat, nFreq, nBase ) - GetCoupdaybs( nNullDate, nSettle, nMat, nFreq, nBase );
1387 }
1388 
1389 
1390 //-------
1391 // COUPDAYS: get day count: coupon date before settlement <-> coupon date after settlement
1392 double GetCoupdays( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nFreq, sal_Int32 nBase )
1393     THROWDEF_RTE_IAE
1394 {
1395     if( nSettle >= nMat || CHK_Freq )
1396         THROW_IAE;
1397 
1398     if( nBase == 1 )
1399     {
1400         ScaDate aDate;
1401         lcl_GetCouppcd( aDate, ScaDate( nNullDate, nSettle, nBase ), ScaDate( nNullDate, nMat, nBase ), nFreq );
1402         ScaDate aNextDate( aDate );
1403         aNextDate.addMonths( 12 / nFreq );
1404         return ScaDate::getDiff( aDate, aNextDate );
1405     }
1406     return static_cast< double >( GetDaysInYear( 0, 0, nBase ) ) / nFreq;
1407 }
1408 
1409 
1410 //-------
1411 // COUPNUM: get count of coupon dates
1412 double GetCoupnum( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nFreq, sal_Int32 nBase )
1413     THROWDEF_RTE_IAE
1414 {
1415     if( nSettle >= nMat || CHK_Freq )
1416         THROW_IAE;
1417 
1418     ScaDate aMat( nNullDate, nMat, nBase );
1419     ScaDate aDate;
1420     lcl_GetCouppcd( aDate, ScaDate( nNullDate, nSettle, nBase ), aMat, nFreq );
1421     sal_uInt16 nMonths = (aMat.getYear() - aDate.getYear()) * 12 + aMat.getMonth() - aDate.getMonth();
1422     return static_cast< double >( nMonths * nFreq / 12 );
1423 }
1424 
1425 
1426 
1427 
1428 
1429 
1430 
1431 const sal_uInt32 MyList::nStartSize = 16;
1432 const sal_uInt32 MyList::nIncrSize = 16;
1433 
1434 
1435 void MyList::_Grow( void )
1436 {
1437     nSize += nIncrSize;
1438 
1439     void**          pNewData = new void*[ nSize ];
1440     memcpy( pNewData, pData, nNew * sizeof( void* ) );
1441 
1442     delete[] pData;
1443     pData = pNewData;
1444 }
1445 
1446 
1447 MyList::MyList( void )
1448 {
1449     nSize = nStartSize;
1450     pData = new void*[ nSize ];
1451     nNew = nAct = 0;
1452 }
1453 
1454 
1455 MyList::~MyList()
1456 {
1457     delete[] pData;
1458 }
1459 
1460 
1461 void MyList::Insert( void* p, sal_uInt32 n )
1462 {
1463     if( n >= nNew )
1464         Append( p );
1465     else
1466     {
1467         Grow();
1468 
1469         void**      pIns = pData + n;
1470         memmove( pIns + 1, pIns, ( nNew - n ) * sizeof( void* ) );
1471 
1472         *pIns = p;
1473 
1474         nNew++;
1475     }
1476 }
1477 
1478 
1479 
1480 
1481 StringList::~StringList()
1482 {
1483     for( STRING* p = ( STRING* ) First() ; p ; p = ( STRING* ) Next() )
1484         delete p;
1485 }
1486 
1487 
1488 class AnalysisRscStrArrLoader : public Resource
1489 {
1490 private:
1491     ResStringArray          aStrArray;
1492 public:
1493                             AnalysisRscStrArrLoader( sal_uInt16 nRsc, sal_uInt16 nArrayId, ResMgr& rResMgr ) :
1494                                 Resource( AnalysisResId( nRsc, rResMgr ) ),
1495                                 aStrArray( AnalysisResId( nArrayId, rResMgr ) )
1496                             {
1497                                 FreeResource();
1498                             }
1499 
1500     const ResStringArray&   GetStringArray() const { return aStrArray; }
1501 };
1502 
1503 
1504 
1505 
1506 FuncData::FuncData( const FuncDataBase& r, ResMgr& rResMgr ) :
1507     aIntName( OUString::createFromAscii( r.pIntName ) ),
1508     nUINameID( r.nUINameID ),
1509     nDescrID( r.nDescrID ),
1510     bDouble( r.bDouble ),
1511     bWithOpt( r.bWithOpt ),
1512     nParam( r.nNumOfParams ),
1513     nCompID( r.nCompListID ),
1514     eCat( r.eCat )
1515 {
1516     AnalysisRscStrArrLoader aArrLoader( RID_ANALYSIS_DEFFUNCTION_NAMES, nCompID, rResMgr );
1517 //  ResStringArray      aDefFuncNameArray( AnalysisResId( nCompID, rResMgr ) );
1518     const ResStringArray&   rArr = aArrLoader.GetStringArray();
1519 
1520     sal_uInt16              nCount = sal::static_int_cast<sal_uInt16>( rArr.Count() );
1521     sal_uInt16              n;
1522 
1523     for( n = 0 ; n < nCount ; n++ )
1524         aCompList.Append( rArr.GetString( n ) );
1525 }
1526 
1527 
1528 FuncData::~FuncData()
1529 {
1530 }
1531 
1532 
1533 sal_uInt16 FuncData::GetStrIndex( sal_uInt16 nParamNum ) const
1534 {
1535     if( !bWithOpt )
1536         nParamNum++;
1537 
1538     if( nParamNum > nParam )
1539         return nParam * 2;
1540     else
1541         return nParamNum * 2;
1542 }
1543 
1544 
1545 
1546 
1547 FuncDataList::FuncDataList( ResMgr& rResMgr )
1548 {
1549     const sal_uInt32    nNum = sizeof( pFuncDatas ) / sizeof( FuncDataBase );
1550 
1551     for( sal_uInt16 n = 0 ; n < nNum ; n++ )
1552         Append( new FuncData( pFuncDatas[ n ], rResMgr ) );
1553 }
1554 
1555 
1556 FuncDataList::~FuncDataList()
1557 {
1558     for( FuncData* p = ( FuncData* ) First() ; p ; p = ( FuncData* ) Next() )
1559         delete p;
1560 }
1561 
1562 
1563 const FuncData* FuncDataList::Get(  const OUString& aProgrammaticName ) const
1564 {
1565     if( aLastName == aProgrammaticName )
1566         return Get( nLast );
1567 
1568     ( ( FuncDataList* ) this )->aLastName = aProgrammaticName;
1569 
1570     sal_uInt32  nE = Count();
1571     for( sal_uInt32 n = 0 ; n < nE ; n++ )
1572     {
1573         const FuncData* p = Get( n );
1574         if( p->Is( aProgrammaticName ) )
1575         {
1576             ( ( FuncDataList* ) this )->nLast = n;
1577             return p;
1578         }
1579     }
1580 
1581     ( ( FuncDataList* ) this )->nLast = 0xFFFFFFFF;
1582     return NULL;
1583 }
1584 
1585 
1586 AnalysisResId::AnalysisResId( sal_uInt16 nId, ResMgr& rResMgr ) : ResId( nId, rResMgr )
1587 {
1588 }
1589 
1590 
1591 
1592 
1593 SortedIndividualInt32List::SortedIndividualInt32List()
1594 {
1595 }
1596 
1597 
1598 SortedIndividualInt32List::~SortedIndividualInt32List()
1599 {
1600 }
1601 
1602 
1603 void SortedIndividualInt32List::Insert( sal_Int32 nDay )
1604 {
1605     sal_uInt32 nIndex = Count();
1606     while( nIndex )
1607     {
1608         nIndex--;
1609         sal_Int32 nRef = Get( nIndex );
1610         if( nDay == nRef )
1611             return;
1612         else if( nDay > nRef )
1613         {
1614             MyList::Insert( (void*) nDay, nIndex + 1 );
1615             return;
1616         }
1617     }
1618     MyList::Insert( (void*) nDay, 0UL );
1619 }
1620 
1621 
1622 void SortedIndividualInt32List::Insert( sal_Int32 nDay, sal_Int32 nNullDate, sal_Bool bInsertOnWeekend )
1623 {
1624     if( !nDay )
1625         return;
1626 
1627     nDay += nNullDate;
1628     if( bInsertOnWeekend || (GetDayOfWeek( nDay ) < 5) )
1629         Insert( nDay );
1630 }
1631 
1632 
1633 void SortedIndividualInt32List::Insert(
1634         double fDay, sal_Int32 nNullDate, sal_Bool bInsertOnWeekend ) throw( uno::RuntimeException, lang::IllegalArgumentException )
1635 {
1636     if( (fDay < -2147483648.0) || (fDay > 2147483649.0) )
1637         throw lang::IllegalArgumentException();
1638     Insert( static_cast< sal_Int32 >( fDay ), nNullDate, bInsertOnWeekend );
1639 }
1640 
1641 
1642 sal_Bool SortedIndividualInt32List::Find( sal_Int32 nVal ) const
1643 {
1644     sal_uInt32  nE = Count();
1645 
1646     if( !nE || nVal < Get( 0 ) || nVal > Get( nE - 1 ) )
1647         return sal_False;
1648 
1649     // linear search
1650 
1651     for( sal_uInt32 n = 0 ; n < nE ; n++ )
1652     {
1653         sal_Int32   nRef = Get( n );
1654 
1655         if( nRef == nVal )
1656             return sal_True;
1657         else if( nRef > nVal )
1658             return sal_False;
1659     }
1660     return sal_False;
1661 }
1662 
1663 
1664 void SortedIndividualInt32List::InsertHolidayList(
1665         const ScaAnyConverter& rAnyConv,
1666         const uno::Any& rHolAny,
1667         sal_Int32 nNullDate,
1668         sal_Bool bInsertOnWeekend ) throw( uno::RuntimeException, lang::IllegalArgumentException )
1669 {
1670     double fDay;
1671     if( rAnyConv.getDouble( fDay, rHolAny ) )
1672         Insert( fDay, nNullDate, bInsertOnWeekend );
1673 }
1674 
1675 
1676 void SortedIndividualInt32List::InsertHolidayList(
1677         ScaAnyConverter& rAnyConv,
1678         const uno::Reference< beans::XPropertySet >& xOptions,
1679         const uno::Any& rHolAny,
1680         sal_Int32 nNullDate,
1681         sal_Bool bInsertOnWeekend ) throw( uno::RuntimeException, lang::IllegalArgumentException )
1682 {
1683     rAnyConv.init( xOptions );
1684     if( rHolAny.getValueTypeClass() == uno::TypeClass_SEQUENCE )
1685     {
1686         uno::Sequence< uno::Sequence< uno::Any > > aAnySeq;
1687         if( rHolAny >>= aAnySeq )
1688         {
1689             const uno::Sequence< uno::Any >* pSeqArray = aAnySeq.getConstArray();
1690             for( sal_Int32 nIndex1 = 0; nIndex1 < aAnySeq.getLength(); nIndex1++ )
1691             {
1692                 const uno::Sequence< uno::Any >& rSubSeq = pSeqArray[ nIndex1 ];
1693                 const uno::Any* pAnyArray = rSubSeq.getConstArray();
1694 
1695                 for( sal_Int32 nIndex2 = 0; nIndex2 < rSubSeq.getLength(); nIndex2++ )
1696                     InsertHolidayList( rAnyConv, pAnyArray[ nIndex2 ], nNullDate, bInsertOnWeekend );
1697             }
1698         }
1699         else
1700             throw lang::IllegalArgumentException();
1701     }
1702     else
1703         InsertHolidayList( rAnyConv, rHolAny, nNullDate, bInsertOnWeekend );
1704 }
1705 
1706 
1707 
1708 //-----------------------------------------------------------------------------
1709 
1710 ScaDoubleList::~ScaDoubleList()
1711 {
1712     for( double* pDbl = const_cast< double* >( First() ); pDbl; pDbl = const_cast< double* >( Next() ) )
1713         delete pDbl;
1714 }
1715 
1716 
1717 void ScaDoubleList::Append(
1718         const uno::Sequence< uno::Sequence< double > >& rValueSeq ) throw( uno::RuntimeException, lang::IllegalArgumentException )
1719 {
1720     const uno::Sequence< double >* pSeqArray = rValueSeq.getConstArray();
1721     for( sal_Int32 nIndex1 = 0; nIndex1 < rValueSeq.getLength(); nIndex1++ )
1722     {
1723         const uno::Sequence< double >& rSubSeq = pSeqArray[ nIndex1 ];
1724         const double* pArray = rSubSeq.getConstArray();
1725         for( sal_Int32 nIndex2 = 0; nIndex2 < rSubSeq.getLength(); nIndex2++ )
1726             Append( pArray[ nIndex2 ] );
1727     }
1728 }
1729 
1730 
1731 void ScaDoubleList::Append(
1732         const uno::Sequence< uno::Sequence< sal_Int32 > >& rValueSeq ) throw( uno::RuntimeException, lang::IllegalArgumentException )
1733 {
1734     const uno::Sequence< sal_Int32 >* pSeqArray = rValueSeq.getConstArray();
1735     for( sal_Int32 nIndex1 = 0; nIndex1 < rValueSeq.getLength(); nIndex1++ )
1736     {
1737         const uno::Sequence< sal_Int32 >& rSubSeq = pSeqArray[ nIndex1 ];
1738         const sal_Int32* pArray = rSubSeq.getConstArray();
1739         for( sal_Int32 nIndex2 = 0; nIndex2 < rSubSeq.getLength(); nIndex2++ )
1740             Append( pArray[ nIndex2 ] );
1741     }
1742 }
1743 
1744 
1745 
1746 void ScaDoubleList::Append(
1747         const ScaAnyConverter& rAnyConv,
1748         const uno::Any& rAny,
1749         sal_Bool bIgnoreEmpty ) throw( uno::RuntimeException, lang::IllegalArgumentException )
1750 {
1751     if( rAny.getValueTypeClass() == uno::TypeClass_SEQUENCE )
1752         Append( rAnyConv, *static_cast< const uno::Sequence< uno::Sequence< uno::Any > >* >( rAny.getValue() ), bIgnoreEmpty );
1753     else
1754     {
1755         double fValue;
1756         if( rAnyConv.getDouble( fValue, rAny ) )
1757             Append( fValue );
1758         else if( !bIgnoreEmpty )
1759             Append( 0.0 );
1760     }
1761 }
1762 
1763 
1764 void ScaDoubleList::Append(
1765         const ScaAnyConverter& rAnyConv,
1766         const uno::Sequence< uno::Any >& rAnySeq,
1767         sal_Bool bIgnoreEmpty ) throw( uno::RuntimeException, lang::IllegalArgumentException )
1768 {
1769     const uno::Any* pArray = rAnySeq.getConstArray();
1770     for( sal_Int32 nIndex = 0; nIndex < rAnySeq.getLength(); nIndex++ )
1771         Append( rAnyConv, pArray[ nIndex ], bIgnoreEmpty );
1772 }
1773 
1774 
1775 void ScaDoubleList::Append(
1776         const ScaAnyConverter& rAnyConv,
1777         const uno::Sequence< uno::Sequence< uno::Any > >& rAnySeq,
1778         sal_Bool bIgnoreEmpty ) throw( uno::RuntimeException, lang::IllegalArgumentException )
1779 {
1780     const uno::Sequence< uno::Any >* pArray = rAnySeq.getConstArray();
1781     for( sal_Int32 nIndex = 0; nIndex < rAnySeq.getLength(); nIndex++ )
1782         Append( rAnyConv, pArray[ nIndex ], bIgnoreEmpty );
1783 }
1784 
1785 
1786 
1787 void ScaDoubleList::Append(
1788         ScaAnyConverter& rAnyConv,
1789         const uno::Reference< beans::XPropertySet >& xOpt,
1790         const uno::Sequence< uno::Any >& rAnySeq,
1791         sal_Bool bIgnoreEmpty ) throw( uno::RuntimeException, lang::IllegalArgumentException )
1792 {
1793     rAnyConv.init( xOpt );
1794     Append( rAnyConv, rAnySeq, bIgnoreEmpty );
1795 }
1796 
1797 
1798 sal_Bool ScaDoubleList::CheckInsert( double ) const throw( uno::RuntimeException, lang::IllegalArgumentException )
1799 {
1800     return sal_True;
1801 }
1802 
1803 
1804 
1805 //-----------------------------------------------------------------------------
1806 
1807 sal_Bool ScaDoubleListGT0::CheckInsert( double fValue ) const throw( uno::RuntimeException, lang::IllegalArgumentException )
1808 {
1809     if( fValue < 0.0 )
1810         throw lang::IllegalArgumentException();
1811     return fValue > 0.0;
1812 }
1813 
1814 
1815 
1816 //-----------------------------------------------------------------------------
1817 
1818 sal_Bool ScaDoubleListGE0::CheckInsert( double fValue ) const throw( uno::RuntimeException, lang::IllegalArgumentException )
1819 {
1820     if( fValue < 0.0 )
1821         throw lang::IllegalArgumentException();
1822     return sal_True;
1823 }
1824 
1825 
1826 
1827 //-----------------------------------------------------------------------------
1828 
1829 Complex::Complex( const STRING& rStr ) THROWDEF_RTE_IAE
1830 {
1831     if( !ParseString( rStr, *this ) )
1832         THROW_IAE;
1833 }
1834 
1835 
1836 inline sal_Bool Complex::IsImagUnit( sal_Unicode c )
1837 {
1838     return c == 'i' || c == 'j';
1839 }
1840 
1841 sal_Bool Complex::ParseString( const STRING& rStr, Complex& rCompl )
1842 {
1843     rCompl.c = '\0';    // do not force a symbol, if only real part present
1844 
1845     const sal_Unicode*      pStr = ( const sal_Unicode * ) rStr;
1846 
1847     if( IsImagUnit( *pStr ) && rStr.getLength() == 1)
1848     {
1849         rCompl.r = 0.0;
1850         rCompl.i = 1.0;
1851         rCompl.c = *pStr;
1852         return sal_True;
1853     }
1854 
1855     double                  f;
1856 
1857     if( !ParseDouble( pStr, f ) )
1858         return sal_False;
1859 
1860     switch( *pStr )
1861     {
1862         case '-':   // imag part follows
1863         case '+':
1864             {
1865             double      r = f;
1866             if( IsImagUnit( pStr[ 1 ] ) )
1867             {
1868                 rCompl.c = pStr[ 1 ];
1869                 if( pStr[ 2 ] == 0 )
1870                 {
1871                     rCompl.r = f;
1872                     rCompl.i = ( *pStr == '+' )? 1.0 : -1.0;
1873                     return sal_True;
1874                 }
1875             }
1876             else if( ParseDouble( pStr, f ) && IsImagUnit( *pStr ) )
1877             {
1878                 rCompl.c = *pStr;
1879                 pStr++;
1880                 if( *pStr == 0 )
1881                 {
1882                     rCompl.r = r;
1883                     rCompl.i = f;
1884                     return sal_True;
1885                 }
1886             }
1887             }
1888             break;
1889         case 'j':
1890         case 'i':
1891             rCompl.c = *pStr;
1892             pStr++;
1893             if( *pStr == 0 )
1894             {
1895                 rCompl.i = f;
1896                 rCompl.r = 0.0;
1897                 return sal_True;
1898             }
1899             break;
1900         case 0:     // only real-part
1901             rCompl.r = f;
1902             rCompl.i = 0.0;
1903             return sal_True;
1904     }
1905 
1906     return sal_False;
1907 }
1908 
1909 
1910 STRING Complex::GetString() const THROWDEF_RTE_IAE
1911 {
1912     static const String aI( 'i' );
1913     static const String aJ( 'j' );
1914     static const String aPlus( '+' );
1915     static const String aMinus( '-' );
1916 
1917     CHK_FINITE(r);
1918     CHK_FINITE(i);
1919     STRING aRet;
1920 
1921     bool bHasImag = i != 0.0;
1922     bool bHasReal = !bHasImag || (r != 0.0);
1923 
1924     if( bHasReal )
1925         aRet = ::GetString( r );
1926     if( bHasImag )
1927     {
1928         if( i == 1.0 )
1929         {
1930             if( bHasReal )
1931                 aRet += aPlus;
1932         }
1933         else if( i == -1.0 )
1934             aRet += aMinus;
1935         else
1936             aRet += ::GetString( i, bHasReal );
1937         aRet += (c != 'j') ? aI : aJ;
1938     }
1939 
1940     return aRet;
1941 }
1942 
1943 
1944 double Complex::Arg( void ) const THROWDEF_RTE_IAE
1945 {
1946     if( r == 0.0 && i == 0.0 )
1947         THROW_IAE;
1948 
1949     double  phi = acos( r / Abs() );
1950 
1951     if( i < 0.0 )
1952         phi = -phi;
1953 
1954     return phi;
1955 }
1956 
1957 
1958 void Complex::Power( double fPower ) THROWDEF_RTE_IAE
1959 {
1960     if( r == 0.0 && i == 0.0 )
1961     {
1962         if( fPower > 0 )
1963         {
1964             r = i = 0.0;
1965             return;
1966         }
1967         else
1968             THROW_IAE;
1969     }
1970 
1971     double      p, phi;
1972 
1973     p = Abs();
1974 
1975     phi = acos( r / p );
1976     if( i < 0.0 )
1977         phi = -phi;
1978 
1979     p = pow( p, fPower );
1980     phi *= fPower;
1981 
1982     r = cos( phi ) * p;
1983     i = sin( phi ) * p;
1984 }
1985 
1986 
1987 void Complex::Sqrt( void )
1988 {
1989     static const double fMultConst = 0.7071067811865475;    // ...2440084436210485 = 1/sqrt(2)
1990     double  p = Abs();
1991     double  i_ = sqrt( p - r ) * fMultConst;
1992 
1993     r = sqrt( p + r ) * fMultConst;
1994     i = ( i < 0.0 )? -i_ : i_;
1995 }
1996 
1997 
1998 inline sal_Bool SinOverflow( double f )
1999 {
2000     return fabs( f ) >= 134217728;
2001 }
2002 
2003 
2004 void Complex::Sin( void ) THROWDEF_RTE_IAE
2005 {
2006     if( SinOverflow( r ) )
2007         THROW_IAE;
2008 
2009     if( i )
2010     {
2011         double  r_;
2012 
2013         r_ = sin( r ) * cosh( i );
2014         i = cos( r ) * sinh( i );
2015         r = r_;
2016     }
2017     else
2018         r = sin( r );
2019 }
2020 
2021 
2022 void Complex::Cos( void ) THROWDEF_RTE_IAE
2023 {
2024     if( SinOverflow( r ) )
2025         THROW_IAE;
2026 
2027     if( i )
2028     {
2029         double      r_;
2030 
2031         r_ = cos( r ) * cosh( i );
2032         i = -( sin( r ) * sinh( i ) );
2033         r = r_;
2034     }
2035     else
2036         r = cos( r );
2037 }
2038 
2039 
2040 void Complex::Div( const Complex& z ) THROWDEF_RTE_IAE
2041 {
2042     if( z.r == 0 && z.i == 0 )
2043         THROW_IAE;
2044 
2045     double  a1 = r;
2046     double  a2 = z.r;
2047     double  b1 = i;
2048     double  b2 = z.i;
2049 
2050     double  f = 1.0 / ( a2 * a2 + b2 * b2 );
2051 
2052     r = ( a1 * a2 + b1 * b2 ) * f;
2053     i = ( a2 * b1 - a1 * b2 ) * f;
2054 
2055     if( !c ) c = z.c;
2056 }
2057 
2058 
2059 void Complex::Exp( void )
2060 {
2061     double  fE = exp( r );
2062     r = fE * cos( i );
2063     i = fE * sin( i );
2064 }
2065 
2066 
2067 void Complex::Ln( void ) THROWDEF_RTE_IAE
2068 {
2069     if( r == 0.0 && i == 0.0 )
2070         THROW_IAE;
2071 
2072     double      fAbs = Abs();
2073     sal_Bool    bNegi = i < 0.0;
2074 
2075     i = acos( r / fAbs );
2076 
2077     if( bNegi )
2078         i = -i;
2079 
2080     r = log( fAbs );
2081 }
2082 
2083 
2084 void Complex::Log10( void ) THROWDEF_RTE_IAE
2085 {
2086     Ln();
2087     Mult( 0.434294481903251828 );   // * log10( e )
2088 }
2089 
2090 
2091 void Complex::Log2( void ) THROWDEF_RTE_IAE
2092 {
2093     Ln();
2094     Mult( 1.442695040888963407 );   // * log2( e )
2095 }
2096 
2097 
2098 
2099 
2100 ComplexList::~ComplexList()
2101 {
2102     for( Complex* p = ( Complex* ) First() ; p ; p = ( Complex* ) Next() )
2103         delete p;
2104 }
2105 
2106 
2107 void ComplexList::Append( const SEQSEQ( STRING )& r, ComplListAppendHandl eAH ) THROWDEF_RTE_IAE
2108 {
2109     sal_Int32   n1, n2;
2110     sal_Int32   nE1 = r.getLength();
2111     sal_Int32   nE2;
2112     sal_Bool    bEmpty0 = eAH == AH_EmpyAs0;
2113     sal_Bool    bErrOnEmpty = eAH == AH_EmptyAsErr;
2114 
2115     for( n1 = 0 ; n1 < nE1 ; n1++ )
2116     {
2117         const SEQ( STRING )&    rList = r[ n1 ];
2118         nE2 = rList.getLength();
2119 
2120         for( n2 = 0 ; n2 < nE2 ; n2++ )
2121         {
2122             const STRING&   rStr = rList[ n2 ];
2123 
2124             if( rStr.getLength() )
2125                 Append( new Complex( rStr ) );
2126             else if( bEmpty0 )
2127                 Append( new Complex( 0.0 ) );
2128             else if( bErrOnEmpty )
2129                 THROW_IAE;
2130         }
2131     }
2132 }
2133 
2134 
2135 void ComplexList::Append( const SEQ( ANY )& aMultPars, ComplListAppendHandl eAH ) THROWDEF_RTE_IAE
2136 {
2137     sal_Int32       nEle = aMultPars.getLength();
2138     sal_Bool        bEmpty0 = eAH == AH_EmpyAs0;
2139     sal_Bool        bErrOnEmpty = eAH == AH_EmptyAsErr;
2140 
2141     for( sal_Int32 i = 0 ; i < nEle ; i++ )
2142     {
2143         const ANY&  r = aMultPars[ i ];
2144         switch( r.getValueTypeClass() )
2145         {
2146             case uno::TypeClass_VOID:       break;
2147             case uno::TypeClass_STRING:
2148                 {
2149                 const STRING*       pStr = ( const STRING* ) r.getValue();
2150 
2151                 if( pStr->getLength() )
2152                     Append( new Complex( *( STRING* ) r.getValue() ) );
2153                 else if( bEmpty0 )
2154                     Append( new Complex( 0.0 ) );
2155                 else if( bErrOnEmpty )
2156                     THROW_IAE;
2157                 }
2158                 break;
2159             case uno::TypeClass_DOUBLE:
2160                 Append( new Complex( *( double* ) r.getValue(), 0.0 ) );
2161                 break;
2162             case uno::TypeClass_SEQUENCE:
2163                 {
2164                 SEQSEQ( ANY )           aValArr;
2165                 if( r >>= aValArr )
2166                 {
2167                     sal_Int32           nE = aValArr.getLength();
2168                     const SEQ( ANY )*   pArr = aValArr.getConstArray();
2169                     for( sal_Int32 n = 0 ; n < nE ; n++ )
2170                         Append( pArr[ n ], eAH );
2171                 }
2172                 else
2173                     THROW_IAE;
2174                 }
2175                 break;
2176             default:
2177                 THROW_IAE;
2178         }
2179     }
2180 }
2181 
2182 
2183 
2184 
2185 ConvertData::ConvertData( const sal_Char p[], double fC, ConvertDataClass e, sal_Bool bPrefSupport ) : aName( p, strlen( p ), RTL_TEXTENCODING_MS_1252 )
2186 {
2187     fConst = fC;
2188     eClass = e;
2189     bPrefixSupport = bPrefSupport;
2190 }
2191 
2192 ConvertData::~ConvertData()
2193 {
2194 }
2195 
2196 
2197 sal_Int16 ConvertData::GetMatchingLevel( const STRING& rRef ) const
2198 {
2199     STRING aStr = rRef;
2200     sal_Int32 nLen = rRef.getLength();
2201     sal_Int32 nIndex = rRef.lastIndexOf( '^' );
2202     if( nIndex > 0 && nIndex  == ( nLen - 2 ) )
2203     {
2204         const sal_Unicode*  p = aStr.getStr();
2205         aStr = STRING( p, nLen - 2 );
2206         aStr += STRING( p[ nLen - 1 ] );
2207     }
2208     if( aName.equals( aStr ) )
2209         return 0;
2210     else
2211     {
2212         const sal_Unicode*  p = aStr.getStr();
2213 
2214         nLen = aStr.getLength();
2215         bool bPref = IsPrefixSupport();
2216         bool bOneChar = (bPref && nLen > 1 && (aName == p + 1));
2217         if (bOneChar || (bPref && nLen > 2 && (aName == p + 2) &&
2218                     *p == 'd' && *(p+1) == 'a'))
2219         {
2220             sal_Int16       n;
2221             switch( *p )
2222             {
2223                 case 'y':   n = -24;    break;      // yocto
2224                 case 'z':   n = -21;    break;      // zepto
2225                 case 'a':   n = -18;    break;
2226                 case 'f':   n = -15;    break;
2227                 case 'p':   n = -12;    break;
2228                 case 'n':   n = -9;     break;
2229                 case 'u':   n = -6;     break;
2230                 case 'm':   n = -3;     break;
2231                 case 'c':   n = -2;     break;
2232                 case 'd':
2233                     {
2234                         if ( bOneChar )
2235                             n = -1;                 // deci
2236                         else
2237                             n = 1;                  // deca
2238                     }
2239                     break;
2240                 case 'e':   n = 1;      break;
2241                 case 'h':   n = 2;      break;
2242                 case 'k':   n = 3;      break;
2243                 case 'M':   n = 6;      break;
2244                 case 'G':   n = 9;      break;
2245                 case 'T':   n = 12;     break;
2246                 case 'P':   n = 15;     break;
2247                 case 'E':   n = 18;     break;
2248                 case 'Z':   n = 21;     break;      // zetta
2249                 case 'Y':   n = 24;     break;      // yotta
2250                 default:
2251                             n = INV_MATCHLEV;
2252             }
2253 
2254 // We could weed some nonsense out, ODFF doesn't say so though.
2255 #if 0
2256             if (n < 0 && Class() == CDC_Information)
2257                 n = INV_MATCHLEV;   // milli-bits doesn't make sense
2258 #endif
2259 
2260 //! <HACK> #100616# "cm3" is not 10^-2 m^3 but 10^-6 m^3 !!! ------------------
2261             if( n != INV_MATCHLEV )
2262             {
2263                 sal_Unicode cLast = p[ aStr.getLength() - 1 ];
2264                 if( cLast == '2' )
2265                     n *= 2;
2266                 else if( cLast == '3' )
2267                     n *= 3;
2268             }
2269 //! </HACK> -------------------------------------------------------------------
2270 
2271             return n;
2272         }
2273         else if ( nLen > 2 && ( aName == p + 2 ) && ( Class() == CDC_Information ) )
2274         {
2275             const sal_Unicode*  pStr = aStr.getStr();
2276             if ( *(pStr + 1) != 'i')
2277                 return INV_MATCHLEV;
2278             sal_Int16 n;
2279             switch( *pStr )
2280             {
2281                 case 'k':   n = 10;      break;
2282                 case 'M':   n = 20;      break;
2283                 case 'G':   n = 30;      break;
2284                 case 'T':   n = 40;      break;
2285                 case 'P':   n = 50;      break;
2286                 case 'E':   n = 60;      break;
2287                 case 'Z':   n = 70;      break;
2288                 case 'Y':   n = 80;      break;
2289                 default:
2290                             n = INV_MATCHLEV;
2291             }
2292             return n;
2293         }
2294         else
2295             return INV_MATCHLEV;
2296     }
2297 }
2298 
2299 
2300 double ConvertData::Convert(
2301     double f, const ConvertData& r, sal_Int16 nLevFrom, sal_Int16 nLevTo ) const THROWDEF_RTE_IAE
2302 {
2303     if( Class() != r.Class() )
2304         THROW_IAE;
2305 
2306     sal_Bool bBinFromLev = ( nLevFrom > 0 && ( nLevFrom % 10 ) == 0 );
2307     sal_Bool bBinToLev   = ( nLevTo > 0 && ( nLevTo % 10 ) == 0 );
2308 
2309     if ( Class() == CDC_Information && ( bBinFromLev || bBinToLev ) )
2310     {
2311         if ( bBinFromLev && bBinToLev )
2312         {
2313             nLevFrom = sal::static_int_cast<sal_Int16>( nLevFrom - nLevTo );
2314             f *= r.fConst / fConst;
2315             if( nLevFrom )
2316                 f *= pow( 2.0, nLevFrom );
2317         }
2318         else if ( bBinFromLev )
2319             f *= ( r.fConst / fConst ) * ( pow( 2.0, nLevFrom ) / pow( 10.0, nLevTo ) );
2320         else
2321             f *= ( r.fConst / fConst ) * ( pow( 10.0, nLevFrom ) / pow( 2.0, nLevTo ) );
2322         return f;
2323     }
2324 
2325     nLevFrom = sal::static_int_cast<sal_Int16>( nLevFrom - nLevTo );    // effective level
2326 
2327     f *= r.fConst / fConst;
2328 
2329     if( nLevFrom )
2330         f = ::rtl::math::pow10Exp( f, nLevFrom );
2331 
2332     return f;
2333 }
2334 
2335 
2336 double ConvertData::ConvertToBase( double f, sal_Int16 n ) const
2337 {
2338     return ::rtl::math::pow10Exp( f / fConst, n );
2339 }
2340 
2341 
2342 double ConvertData::ConvertFromBase( double f, sal_Int16 n ) const
2343 {
2344     return ::rtl::math::pow10Exp( f * fConst, -n );
2345 }
2346 
2347 
2348 
2349 ConvertDataLinear::~ConvertDataLinear()
2350 {
2351 }
2352 
2353 double ConvertDataLinear::Convert(
2354     double f, const ConvertData& r, sal_Int16 nLevFrom, sal_Int16 nLevTo ) const THROWDEF_RTE_IAE
2355 {
2356     if( Class() != r.Class() )
2357         THROW_IAE;
2358 
2359 //  return ::rtl::math::round( r.ConvertFromBase( ConvertToBase( f, nLevFrom ), nLevTo ), 13 );
2360     return r.ConvertFromBase( ConvertToBase( f, nLevFrom ), nLevTo );
2361 }
2362 
2363 
2364 double ConvertDataLinear::ConvertToBase( double f, sal_Int16 n ) const
2365 {
2366     if( n )
2367         f = ::rtl::math::pow10Exp( f, n );
2368 
2369     f /= fConst;
2370     f -= fOffs;
2371 
2372     return f;
2373 }
2374 
2375 
2376 double ConvertDataLinear::ConvertFromBase( double f, sal_Int16 n ) const
2377 {
2378     f += fOffs;
2379     f *= fConst;
2380 
2381     if( n )
2382         f = ::rtl::math::pow10Exp( f, -n );
2383 
2384     return f;
2385 }
2386 
2387 
2388 
2389 
2390 ConvertDataList::ConvertDataList( void )
2391 {
2392 #define NEWD(str,unit,cl)   Append(new ConvertData(str,unit,cl))
2393 #define NEWDP(str,unit,cl)  Append(new ConvertData(str,unit,cl,sal_True))
2394 #define NEWL(str,unit,offs,cl)  Append(new ConvertDataLinear(str,unit,offs,cl))
2395 #define NEWLP(str,unit,offs,cl) Append(new ConvertDataLinear(str,unit,offs,cl,sal_True))
2396 
2397     // *** are extra and not standard Excel Analysis Addin!
2398 
2399     // MASS: 1 Gram is...
2400     NEWDP( "g",         1.0000000000000000E00,  CDC_Mass ); // Gram
2401     NEWD( "sg",         6.8522050005347800E-05, CDC_Mass ); // Pieces
2402     NEWD( "lbm",        2.2046229146913400E-03, CDC_Mass ); // Pound (commercial weight)
2403     NEWDP( "u",         6.0221370000000000E23,  CDC_Mass ); // U (atomic mass)
2404     NEWD( "ozm",        3.5273971800362700E-02, CDC_Mass ); // Ounce (commercial weight)
2405     NEWD( "stone",      1.574730e-04,           CDC_Mass ); // *** Stone
2406     NEWD( "ton",        1.102311e-06,           CDC_Mass ); // *** Ton
2407     NEWD( "grain",      1.543236E01,            CDC_Mass ); // *** Grain
2408     NEWD( "pweight",    7.054792E-01,           CDC_Mass ); // *** Pennyweight
2409     NEWD( "hweight",    1.968413E-05,           CDC_Mass ); // *** Hundredweight
2410     NEWD( "shweight",   2.204623E-05,           CDC_Mass ); // *** Shorthundredweight
2411     NEWD( "brton",      9.842065E-07,           CDC_Mass ); // *** Gross Registered Ton
2412     NEWD( "cwt",        2.2046226218487758E-05, CDC_Mass ); // U.S. (short) hundredweight
2413     NEWD( "shweight",   2.2046226218487758E-05, CDC_Mass ); // U.S. (short) hundredweight also
2414     NEWD( "uk_cwt",     1.9684130552221213E-05, CDC_Mass ); // Imperial hundredweight
2415     NEWD( "lcwt",       1.9684130552221213E-05, CDC_Mass ); // Imperial hundredweight also
2416     NEWD( "hweight",    1.9684130552221213E-05, CDC_Mass ); // Imperial hundredweight also
2417     NEWD( "uk_ton",     9.8420652761106063E-07, CDC_Mass ); // Imperial ton
2418     NEWD( "LTON",       9.8420652761106063E-07, CDC_Mass ); // Imperial ton also
2419 
2420     // LENGTH: 1 Meter is...
2421     NEWDP( "m",         1.0000000000000000E00,  CDC_Length ); // Meter
2422     NEWD( "mi",         6.2137119223733397E-04, CDC_Length ); // Britsh Mile        6,21371192237333969617434184363e-4
2423     NEWD( "Nmi",        5.3995680345572354E-04, CDC_Length ); // Nautical Mile      5,39956803455723542116630669546e-4
2424     NEWD( "in",         3.9370078740157480E01,  CDC_Length ); // Inch               39,37007874015748031496062992126
2425     NEWD( "ft",         3.2808398950131234E00,  CDC_Length ); // Foot               3,2808398950131233595800524934383
2426     NEWD( "yd",         1.0936132983377078E00,  CDC_Length ); // Yard               1,0936132983377077865266841644794
2427     NEWDP( "ang",       1.0000000000000000E10,  CDC_Length ); // Angstroem
2428     NEWD( "Pica",       2.8346456692913386E03,  CDC_Length ); // Pica (1/72 Inch)   2834,6456692913385826771653543307
2429     NEWD( "ell",        8.748906E-01,           CDC_Length ); // *** Ell
2430     NEWDP( "parsec",    3.240779E-17,           CDC_Length ); // *** Parsec
2431     NEWDP( "pc",        3.240779E-17,           CDC_Length ); // *** Parsec also
2432     NEWDP( "lightyear", 1.0570234557732930E-16, CDC_Length ); // *** Light Year
2433     NEWDP( "ly",        1.0570234557732930E-16, CDC_Length ); // *** Light Year also
2434     NEWD( "survey_mi",  6.2136994949494949E-04, CDC_Length ); // U.S. survey mile
2435 
2436     // TIME: 1 Second is...
2437     NEWD( "yr",     3.1688087814028950E-08, CDC_Time ); // Year
2438     NEWD( "day",    1.1574074074074074E-05, CDC_Time ); // Day
2439     NEWD( "d",      1.1574074074074074E-05, CDC_Time ); // Day also
2440     NEWD( "hr",     2.7777777777777778E-04, CDC_Time ); // Hour
2441     NEWD( "mn",     1.6666666666666667E-02, CDC_Time ); // Minute
2442     NEWD( "min",    1.6666666666666667E-02, CDC_Time ); // Minute also
2443     NEWDP( "sec",   1.0000000000000000E00,  CDC_Time ); // Second
2444     NEWDP( "s",     1.0000000000000000E00,  CDC_Time ); // Second also
2445 
2446     // PRESSURE: 1 Pascal is...
2447     NEWDP( "Pa",    1.0000000000000000E00,  CDC_Pressure ); // Pascal
2448     NEWDP( "atm",   9.8692329999819300E-06, CDC_Pressure ); // Atmosphere
2449     NEWDP( "at",    9.8692329999819300E-06, CDC_Pressure ); // Atmosphere also
2450     NEWDP( "mmHg",  7.5006170799862700E-03, CDC_Pressure ); // mm Hg (Mercury)
2451     NEWD( "Torr",   7.5006380000000000E-03, CDC_Pressure ); // *** Torr
2452     NEWD( "psi",    1.4503770000000000E-04, CDC_Pressure ); // *** Psi
2453 
2454     // FORCE: 1 Newton is...
2455     NEWDP( "N",     1.0000000000000000E00,  CDC_Force ); // Newton
2456     NEWDP( "dyn",   1.0000000000000000E05,  CDC_Force ); // Dyn
2457     NEWDP( "dy",    1.0000000000000000E05,  CDC_Force ); // Dyn also
2458     NEWD( "lbf",    2.24808923655339E-01,   CDC_Force ); // Pound-Force
2459     NEWDP( "pond",  1.019716E02,            CDC_Force ); // *** Pond
2460 
2461     // ENERGY: 1 Joule is...
2462     NEWDP( "J",     1.0000000000000000E00,  CDC_Energy ); // Joule
2463     NEWDP( "e",     1.0000000000000000E07,  CDC_Energy ); // Erg  -> http://www.chemie.fu-berlin.de/chemistry/general/si.html
2464 //  NEWD( "e",      9.99999519343231E06,    CDC_Energy ); // Erg
2465     NEWDP( "c",     2.3900624947346700E-01, CDC_Energy ); // Thermodynamical Calorie
2466     NEWDP( "cal",   2.3884619064201700E-01, CDC_Energy ); // Calorie
2467     NEWDP( "eV",    6.2414570000000000E18,  CDC_Energy ); // Electronvolt
2468     NEWDP( "ev",    6.2414570000000000E18,  CDC_Energy ); // Electronvolt also
2469     NEWD( "HPh",    3.7250611111111111E-07, CDC_Energy ); // Horsepower Hours
2470     NEWD( "hh",     3.7250611111111111E-07, CDC_Energy ); // Horsepower Hours also
2471 //  NEWD( "HPh",    3.72506430801000E-07,   CDC_Energy ); // Horsepower Hours
2472     NEWDP( "Wh",    2.7777777777777778E-04, CDC_Energy ); // Watt Hours
2473     NEWDP( "wh",    2.7777777777777778E-04, CDC_Energy ); // Watt Hours also
2474     NEWD( "flb",    2.37304222192651E01,    CDC_Energy ); // Foot Pound
2475     NEWD( "BTU",    9.4781506734901500E-04, CDC_Energy ); // British Thermal Unit
2476     NEWD( "btu",    9.4781506734901500E-04, CDC_Energy ); // British Thermal Unit also
2477 
2478     // POWER: 1 Watt is...
2479     NEWDP( "W",     1.0000000000000000E00,  CDC_Power ); // Watt
2480     NEWDP( "w",     1.0000000000000000E00,  CDC_Power ); // Watt also
2481     NEWD( "HP",     1.341022E-03,           CDC_Power ); // Horsepower
2482     NEWD( "h",      1.341022E-03,           CDC_Power ); // Horsepower also
2483     NEWD( "PS",     1.359622E-03,           CDC_Power ); // *** German Pferdestaerke
2484 //  NEWD( "HP",     1.4102006031908E-03,    CDC_Power ); // Excel seams to be a little bit wrong... either this doesn't fit to J -> HPh
2485 
2486     // MAGNETISM: 1 Tesla is...
2487     NEWDP( "T",     1.0000000000000000E00,  CDC_Magnetism ); // Tesla
2488     NEWDP( "ga",    1.0000000000000000E04,  CDC_Magnetism ); // Gauss
2489 
2490     // TEMERATURE: 1 Kelvin is...
2491     NEWL( "C",      1.0000000000000000E00,  -2.7315000000000000E02, CDC_Temperature ); // Celsius
2492     NEWL( "cel",    1.0000000000000000E00,  -2.7315000000000000E02, CDC_Temperature ); // Celsius also
2493     NEWL( "F",      1.8000000000000000E00,  -2.5537222222222222E02, CDC_Temperature ); // Fahrenheit
2494     NEWL( "fah",    1.8000000000000000E00,  -2.5537222222222222E02, CDC_Temperature ); // Fahrenheit also
2495     NEWLP( "K",     1.0000000000000000E00,  +0.0000000000000000E00, CDC_Temperature ); // Kelvin
2496     NEWLP( "kel",   1.0000000000000000E00,  +0.0000000000000000E00, CDC_Temperature ); // Kelvin also
2497     NEWL( "Reau",   8.0000000000000000E-01, -2.7315000000000000E02, CDC_Temperature ); // *** Reaumur
2498     NEWL( "Rank",   1.8000000000000000E00,  +0.0000000000000000E00, CDC_Temperature ); // *** Rankine
2499 
2500     // VOLUMNE: 1 Liter is...
2501     NEWD( "tsp",        2.0284000000000000E02,  CDC_Volume ); // Teaspoon
2502     NEWD( "tbs",        6.7613333333333333E01,  CDC_Volume ); // Tablespoon
2503     NEWD( "oz",         3.3806666666666667E01,  CDC_Volume ); // Ounce Liquid
2504     NEWD( "cup",        4.2258333333333333E00,  CDC_Volume ); // Cup
2505     NEWD( "pt",         2.1129166666666667E00,  CDC_Volume ); // US Pint
2506     NEWD( "us_pt",      2.1129166666666667E00,  CDC_Volume ); // US Pint also
2507     NEWD( "uk_pt",      1.75975569552166E00,    CDC_Volume ); // UK Pint
2508     NEWD( "qt",         1.0564583333333333E00,  CDC_Volume ); // Quart
2509     NEWD( "gal",        2.6411458333333333E-01, CDC_Volume ); // Gallone
2510     NEWDP( "l",         1.0000000000000000E00,  CDC_Volume ); // Liter
2511     NEWDP( "L",         1.0000000000000000E00,  CDC_Volume ); // Liter also
2512     NEWDP( "lt",        1.0000000000000000E00,  CDC_Volume ); // Liter also
2513     NEWDP( "m3",        1.0000000000000000E-03, CDC_Volume ); // *** Cubic Meter
2514     NEWD( "mi3",        2.3991275857892772E-13, CDC_Volume ); // *** Cubic Britsh Mile
2515     NEWD( "Nmi3",       1.5742621468581148E-13, CDC_Volume ); // *** Cubic Nautical Mile
2516     NEWD( "in3",        6.1023744094732284E01,  CDC_Volume ); // *** Cubic Inch
2517     NEWD( "ft3",        3.5314666721488590E-02, CDC_Volume ); // *** Cubic Foot
2518     NEWD( "yd3",        1.3079506193143922E-03, CDC_Volume ); // *** Cubic Yard
2519     NEWDP( "ang3",      1.0000000000000000E27,  CDC_Volume ); // *** Cubic Angstroem
2520     NEWD( "Pica3",      2.2776990435870636E07,  CDC_Volume ); // *** Cubic Pica
2521     NEWD( "barrel",     6.289811E-03,           CDC_Volume ); // *** Barrel (=42gal?)
2522     NEWD( "bushel",     2.837759E-02,           CDC_Volume ); // *** Bushel
2523     NEWD( "regton",     3.531467E-04,           CDC_Volume ); // *** Register ton
2524     NEWD( "GRT",        3.531467E-04,           CDC_Volume ); // *** Register ton also
2525     NEWD( "Schooner",   2.3529411764705882E00,  CDC_Volume ); // *** austr. Schooner
2526     NEWD( "Middy",      3.5087719298245614E00,  CDC_Volume ); // *** austr. Middy
2527     NEWD( "Glass",      5.0000000000000000E00,  CDC_Volume ); // *** austr. Glass
2528     NEWD( "Sixpack",    0.5,                    CDC_Volume ); // ***
2529     NEWD( "Humpen",     2.0,                    CDC_Volume ); // ***
2530     NEWD( "ly3",        1.1810108125623799E-51, CDC_Volume ); // *** Cubic light-year
2531     NEWD( "MTON",       1.4125866688595436E00,  CDC_Volume ); // *** Measurement ton
2532     NEWD( "tspm",       5.0000000000000000E02,  CDC_Volume ); // *** Modern teaspoon
2533     NEWD( "uk_gal",     2.199694619402070E-01,  CDC_Volume ); // U.K. / Imperial gallon
2534     NEWD( "uk_qt",      8.798778477608300E-01,  CDC_Volume ); // U.K. / Imperial quart
2535 
2536     // 1 Square Meter is...
2537     NEWDP( "m2",        1.0000000000000000E00,  CDC_Area ); // *** Square Meter
2538     NEWD( "mi2",        3.8610215854244585E-07, CDC_Area ); // *** Square Britsh Mile
2539     NEWD( "Nmi2",       2.9155334959812286E-07, CDC_Area ); // *** Square Nautical Mile
2540     NEWD( "in2",        1.5500031000062000E03,  CDC_Area ); // *** Square Inch
2541     NEWD( "ft2",        1.0763910416709722E01,  CDC_Area ); // *** Square Foot
2542     NEWD( "yd2",        1.1959900463010803E00,  CDC_Area ); // *** Square Yard
2543     NEWDP( "ang2",      1.0000000000000000E20,  CDC_Area ); // *** Square Angstroem
2544     NEWD( "Pica2",      8.0352160704321409E06,  CDC_Area ); // *** Square Pica
2545     NEWD( "Morgen",     4.0000000000000000E-04, CDC_Area ); // *** Morgen
2546     NEWDP( "ar",        1.000000E-02,           CDC_Area ); // *** Ar
2547     NEWD( "acre",       2.471053815E-04,        CDC_Area ); // *** Acre
2548     NEWD( "uk_acre",    2.4710538146716534E-04, CDC_Area ); // *** International acre
2549     NEWD( "us_acre",    2.4710439304662790E-04, CDC_Area ); // *** U.S. survey/statute acre
2550     NEWD( "ly2",        1.1172985860549147E-32, CDC_Area ); // *** Square Light-year
2551     NEWD( "ha",         1.000000E-04,           CDC_Area ); // *** Hectare
2552     NEWD( "Quadratlatschen",5.6689342403628117914,CDC_Area ); // ***
2553 
2554     // SPEED: 1 Meter per Second is...
2555     NEWDP( "m/s",   1.0000000000000000E00,  CDC_Speed ); // *** Meters per Second
2556     NEWDP( "m/sec", 1.0000000000000000E00,  CDC_Speed ); // *** Meters per Second also
2557     NEWDP( "m/h",   3.6000000000000000E03,  CDC_Speed ); // *** Meters per Hour
2558     NEWDP( "m/hr",  3.6000000000000000E03,  CDC_Speed ); // *** Meters per Hour also
2559     NEWD( "mph",    2.2369362920544023E00,  CDC_Speed ); // *** Britsh Miles per Hour
2560     NEWD( "kn",     1.9438444924406048E00,  CDC_Speed ); // *** Knot = Nautical Miles per Hour
2561     NEWD( "admkn",  1.9438446603753486E00,  CDC_Speed ); // *** Admiralty Knot
2562     NEWD( "wahnsinnige Geschwindigkeit", 2.0494886343432328E-14, CDC_Speed ); // ***
2563     NEWD( "ludicrous speed", 2.0494886343432328E-14, CDC_Speed ); // ***
2564     NEWD( "laecherliche Geschwindigkeit", 4.0156958471424288E-06, CDC_Speed); // ***
2565     NEWD( "ridiculous speed", 4.0156958471424288E-06, CDC_Speed); // ***
2566 
2567     // INFORMATION: 1 Bit is...
2568     NEWDP( "bit",   1.00E00,  CDC_Information); // *** Bit
2569     NEWDP( "byte",  1.25E-01, CDC_Information); // *** Byte
2570 }
2571 
2572 
2573 ConvertDataList::~ConvertDataList()
2574 {
2575     for( ConvertData* p = First() ; p ; p = Next() )
2576         delete p;
2577 }
2578 
2579 
2580 double ConvertDataList::Convert( double fVal, const STRING& rFrom, const STRING& rTo ) THROWDEF_RTE_IAE
2581 {
2582 // This will not catch illegal units
2583 //   if( rFrom == rTo )
2584 //       return fVal;
2585 
2586     ConvertData*    pFrom = NULL;
2587     ConvertData*    pTo = NULL;
2588     sal_Bool        bSearchFrom = sal_True;
2589     sal_Bool        bSearchTo = sal_True;
2590     sal_Int16       nLevelFrom = 0;
2591     sal_Int16       nLevelTo = 0;
2592 
2593     ConvertData*    p = First();
2594     while( p && ( bSearchFrom || bSearchTo ) )
2595     {
2596         if( bSearchFrom )
2597         {
2598             sal_Int16   n = p->GetMatchingLevel( rFrom );
2599             if( n != INV_MATCHLEV )
2600             {
2601                 if( n )
2602                 {   // only first match for partial equality rulz a little bit more
2603                     pFrom = p;
2604                     nLevelFrom = n;
2605                 }
2606                 else
2607                 {   // ... but exact match rulz most
2608                     pFrom = p;
2609                     bSearchFrom = sal_False;
2610                     nLevelFrom = n;
2611                 }
2612             }
2613         }
2614 
2615         if( bSearchTo )
2616         {
2617             sal_Int16   n = p->GetMatchingLevel( rTo );
2618             if( n != INV_MATCHLEV )
2619             {
2620                 if( n )
2621                 {   // only first match for partial equality rulz a little bit more
2622                     pTo = p;
2623                     nLevelTo = n;
2624                 }
2625                 else
2626                 {   // ... but exact match rulz most
2627                     pTo = p;
2628                     bSearchTo = sal_False;
2629                     nLevelTo = n;
2630                 }
2631             }
2632         }
2633 
2634         p = Next();
2635     }
2636 
2637     if( pFrom && pTo )
2638         return pFrom->Convert( fVal, *pTo, nLevelFrom, nLevelTo );
2639     else
2640         THROW_IAE;
2641 }
2642 
2643 
2644 
2645 //-----------------------------------------------------------------------------
2646 
2647 ScaDate::ScaDate() :
2648     nOrigDay( 1 ),
2649     nDay( 1 ),
2650     nMonth( 1 ),
2651     nYear( 1900 ),
2652     bLastDayMode( sal_True ),
2653     bLastDay( sal_False ),
2654     b30Days( sal_False ),
2655     bUSMode( sal_False )
2656 {
2657 }
2658 
2659 ScaDate::ScaDate( sal_Int32 nNullDate, sal_Int32 nDate, sal_Int32 nBase )
2660 {
2661     DaysToDate( nNullDate + nDate, nOrigDay, nMonth, nYear );
2662     bLastDayMode = (nBase != 5);
2663     bLastDay = (nOrigDay >= ::DaysInMonth( nMonth, nYear ));
2664     b30Days = (nBase == 0) || (nBase == 4);
2665     bUSMode = (nBase == 0);
2666     setDay();
2667 }
2668 
2669 ScaDate::ScaDate( const ScaDate& rCopy ) :
2670     nOrigDay( rCopy.nOrigDay ),
2671     nDay( rCopy.nDay ),
2672     nMonth( rCopy.nMonth ),
2673     nYear( rCopy.nYear ),
2674     bLastDayMode( rCopy.bLastDayMode ),
2675     bLastDay( rCopy.bLastDay ),
2676     b30Days( rCopy.b30Days ),
2677     bUSMode( rCopy.bUSMode )
2678 {
2679 }
2680 
2681 ScaDate& ScaDate::operator=( const ScaDate& rCopy )
2682 {
2683     if( this != &rCopy )
2684     {
2685         nOrigDay = rCopy.nOrigDay;
2686         nDay = rCopy.nDay;
2687         nMonth = rCopy.nMonth;
2688         nYear = rCopy.nYear;
2689         bLastDayMode = rCopy.bLastDayMode;
2690         bLastDay = rCopy.bLastDay;
2691         b30Days = rCopy.b30Days;
2692         bUSMode = rCopy.bUSMode;
2693     }
2694     return *this;
2695 }
2696 
2697 void ScaDate::setDay()
2698 {
2699     if( b30Days )
2700     {
2701         // 30-days-mode: set nDay to 30 if original was last day in month
2702         nDay = Min( nOrigDay, static_cast< sal_uInt16 >( 30 ) );
2703         if( bLastDay || (nDay >= ::DaysInMonth( nMonth, nYear )) )
2704             nDay = 30;
2705     }
2706     else
2707     {
2708         // set nDay to last day in this month if original was last day
2709         sal_uInt16 nLastDay = ::DaysInMonth( nMonth, nYear );
2710         nDay = bLastDay ? nLastDay : Min( nOrigDay, nLastDay );
2711     }
2712 }
2713 
2714 sal_Int32 ScaDate::getDaysInMonthRange( sal_uInt16 nFrom, sal_uInt16 nTo ) const
2715 {
2716     if( nFrom > nTo )
2717         return 0;
2718 
2719     sal_Int32 nRet = 0;
2720     if( b30Days )
2721         nRet = (nTo - nFrom + 1) * 30;
2722     else
2723     {
2724         for( sal_uInt16 nMonthIx = nFrom; nMonthIx <= nTo; ++nMonthIx )
2725             nRet += getDaysInMonth( nMonthIx );
2726     }
2727     return nRet;
2728 }
2729 
2730 sal_Int32 ScaDate::getDaysInYearRange( sal_uInt16 nFrom, sal_uInt16 nTo ) const
2731 {
2732     if( nFrom > nTo )
2733         return 0;
2734 
2735     return b30Days ? ((nTo - nFrom + 1) * 360) : ::GetDaysInYears( nFrom, nTo );
2736 }
2737 
2738 void ScaDate::doAddYears( sal_Int32 nYearCount ) throw( lang::IllegalArgumentException )
2739 {
2740     sal_Int32 nNewYear = nYearCount + nYear;
2741     if( (nNewYear < 0) || (nNewYear > 0x7FFF) )
2742         throw lang::IllegalArgumentException();
2743     nYear = static_cast< sal_uInt16 >( nNewYear );
2744 }
2745 
2746 void ScaDate::addMonths( sal_Int32 nMonthCount ) throw( lang::IllegalArgumentException )
2747 {
2748     sal_Int32 nNewMonth = nMonthCount + nMonth;
2749     if( nNewMonth > 12 )
2750     {
2751         --nNewMonth;
2752         doAddYears( nNewMonth / 12 );
2753         nMonth = static_cast< sal_uInt16 >( nNewMonth % 12 ) + 1;
2754     }
2755     else if( nNewMonth < 1 )
2756     {
2757         doAddYears( nNewMonth / 12 - 1 );
2758         nMonth = static_cast< sal_uInt16 >( nNewMonth % 12 + 12 );
2759     }
2760     else
2761         nMonth = static_cast< sal_uInt16 >( nNewMonth );
2762     setDay();
2763 }
2764 
2765 sal_Int32 ScaDate::getDate( sal_Int32 nNullDate ) const
2766 {
2767     sal_uInt16 nLastDay = ::DaysInMonth( nMonth, nYear );
2768     sal_uInt16 nRealDay = (bLastDayMode && bLastDay) ? nLastDay : Min( nLastDay, nOrigDay );
2769     return ::DateToDays( nRealDay, nMonth, nYear ) - nNullDate;
2770 }
2771 
2772 sal_Int32 ScaDate::getDiff( const ScaDate& rFrom, const ScaDate& rTo ) throw( lang::IllegalArgumentException )
2773 {
2774     if( rFrom > rTo )
2775         return getDiff( rTo, rFrom );
2776 
2777     sal_Int32 nDiff = 0;
2778     ScaDate aFrom( rFrom );
2779     ScaDate aTo( rTo );
2780 
2781     if( rTo.b30Days )
2782     {
2783         // corrections for base 0 (US NASD)
2784         if( rTo.bUSMode )
2785         {
2786             if( ((rFrom.nMonth == 2) || (rFrom.nDay < 30)) && (aTo.nOrigDay == 31) )
2787                 aTo.nDay = 31;
2788             else if( (aTo.nMonth == 2) && aTo.bLastDay )
2789                 aTo.nDay = ::DaysInMonth( 2, aTo.nYear );
2790         }
2791         // corrections for base 4 (Europe)
2792         else
2793         {
2794             if( (aFrom.nMonth == 2) && (aFrom.nDay == 30) )
2795                 aFrom.nDay = ::DaysInMonth( 2, aFrom.nYear );
2796             if( (aTo.nMonth == 2) && (aTo.nDay == 30) )
2797                 aTo.nDay = ::DaysInMonth( 2, aTo.nYear );
2798         }
2799     }
2800 
2801     if( (aFrom.nYear < aTo.nYear) || ((aFrom.nYear == aTo.nYear) && (aFrom.nMonth < aTo.nMonth)) )
2802     {
2803         // move aFrom to 1st day of next month
2804         nDiff = aFrom.getDaysInMonth() - aFrom.nDay + 1;
2805         aFrom.nOrigDay = aFrom.nDay = 1;
2806         aFrom.bLastDay = sal_False;
2807         aFrom.addMonths( 1 );
2808 
2809         if( aFrom.nYear < aTo.nYear )
2810         {
2811             // move aFrom to 1st day of next year
2812             nDiff += aFrom.getDaysInMonthRange( aFrom.nMonth, 12 );
2813             aFrom.addMonths( 13 - aFrom.nMonth );
2814 
2815             // move aFrom to 1st day of this year
2816             nDiff += aFrom.getDaysInYearRange( aFrom.nYear, aTo.nYear - 1 );
2817             aFrom.addYears( aTo.nYear - aFrom.nYear );
2818         }
2819 
2820         // move aFrom to 1st day of this month
2821         nDiff += aFrom.getDaysInMonthRange( aFrom.nMonth, aTo.nMonth - 1 );
2822         aFrom.addMonths( aTo.nMonth - aFrom.nMonth );
2823     }
2824     // finally add remaining days in this month
2825     nDiff += aTo.nDay - aFrom.nDay;
2826     return nDiff > 0 ? nDiff : 0;
2827 }
2828 
2829 sal_Bool ScaDate::operator<( const ScaDate& rCmp ) const
2830 {
2831     if( nYear != rCmp.nYear )
2832         return nYear < rCmp.nYear;
2833     if( nMonth != rCmp.nMonth )
2834         return nMonth < rCmp.nMonth;
2835     if( nDay != rCmp.nDay )
2836         return nDay < rCmp.nDay;
2837     if( bLastDay || rCmp.bLastDay )
2838         return !bLastDay && rCmp.bLastDay;
2839     return nOrigDay < rCmp.nOrigDay;
2840 }
2841 
2842 
2843 
2844 //-----------------------------------------------------------------------------
2845 
2846 ScaAnyConverter::ScaAnyConverter( const uno::Reference< lang::XMultiServiceFactory >& xServiceFact ) :
2847     bHasValidFormat( sal_False )
2848 {
2849     if( xServiceFact.is() )
2850     {
2851         uno::Reference< uno::XInterface > xInstance = xServiceFact->createInstance(
2852             OUString::createFromAscii( "com.sun.star.util.NumberFormatter" ) );
2853         xFormatter = uno::Reference< util::XNumberFormatter >( xInstance, uno::UNO_QUERY );
2854     }
2855 }
2856 
2857 ScaAnyConverter::~ScaAnyConverter()
2858 {
2859 }
2860 
2861 void ScaAnyConverter::init( const uno::Reference< beans::XPropertySet >& xPropSet ) throw( uno::RuntimeException )
2862 {
2863     // try to get default number format
2864     bHasValidFormat = sal_False;
2865     if( xFormatter.is() )
2866     {
2867         // get XFormatsSupplier from outer XPropertySet
2868         uno::Reference< util::XNumberFormatsSupplier > xFormatsSupp( xPropSet, uno::UNO_QUERY );
2869         if( xFormatsSupp.is() )
2870         {
2871             // get XNumberFormatTypes from XNumberFormatsSupplier to get standard index
2872             uno::Reference< util::XNumberFormats > xFormats( xFormatsSupp->getNumberFormats() );
2873             uno::Reference< util::XNumberFormatTypes > xFormatTypes( xFormats, uno::UNO_QUERY );
2874             if( xFormatTypes.is() )
2875             {
2876                 lang::Locale eLocale;
2877                 nDefaultFormat = xFormatTypes->getStandardIndex( eLocale );
2878                 xFormatter->attachNumberFormatsSupplier( xFormatsSupp );
2879                 bHasValidFormat = sal_True;
2880             }
2881         }
2882     }
2883 }
2884 
2885 double ScaAnyConverter::convertToDouble( const OUString& rString ) const throw( lang::IllegalArgumentException )
2886 {
2887     double fValue = 0.0;
2888     if( bHasValidFormat )
2889     {
2890         try
2891         {
2892             fValue = xFormatter->convertStringToNumber( nDefaultFormat, rString );
2893         }
2894         catch( uno::Exception& )
2895         {
2896             throw lang::IllegalArgumentException();
2897         }
2898     }
2899     else
2900     {
2901         rtl_math_ConversionStatus eStatus;
2902         sal_Int32 nEnd;
2903         fValue = ::rtl::math::stringToDouble( rString, '.', ',', &eStatus, &nEnd );
2904         if( (eStatus != rtl_math_ConversionStatus_Ok) || (nEnd < rString.getLength()) )
2905             throw lang::IllegalArgumentException();
2906     }
2907     return fValue;
2908 }
2909 
2910 sal_Bool ScaAnyConverter::getDouble(
2911         double& rfResult,
2912         const uno::Any& rAny ) const throw( lang::IllegalArgumentException )
2913 {
2914     rfResult = 0.0;
2915     sal_Bool bContainsVal = sal_True;
2916     switch( rAny.getValueTypeClass() )
2917     {
2918         case uno::TypeClass_VOID:
2919             bContainsVal = sal_False;
2920         break;
2921         case uno::TypeClass_DOUBLE:
2922             rAny >>= rfResult;
2923         break;
2924         case uno::TypeClass_STRING:
2925         {
2926             const OUString* pString = static_cast< const OUString* >( rAny.getValue() );
2927             if( pString->getLength() )
2928                 rfResult = convertToDouble( *pString );
2929             else
2930                 bContainsVal = sal_False;
2931         }
2932         break;
2933         default:
2934             throw lang::IllegalArgumentException();
2935     }
2936     return bContainsVal;
2937 }
2938 
2939 sal_Bool ScaAnyConverter::getDouble(
2940         double& rfResult,
2941         const uno::Reference< beans::XPropertySet >& xPropSet,
2942         const uno::Any& rAny ) throw( uno::RuntimeException, lang::IllegalArgumentException )
2943 {
2944     init( xPropSet );
2945     return getDouble( rfResult, rAny );
2946 }
2947 
2948 double ScaAnyConverter::getDouble(
2949         const uno::Reference< beans::XPropertySet >& xPropSet,
2950         const uno::Any& rAny,
2951         double fDefault ) throw( uno::RuntimeException, lang::IllegalArgumentException )
2952 {
2953     double fResult;
2954     if( !getDouble( fResult, xPropSet, rAny ) )
2955         fResult = fDefault;
2956     return fResult;
2957 }
2958 
2959 sal_Bool ScaAnyConverter::getInt32(
2960         sal_Int32& rnResult,
2961         const uno::Reference< beans::XPropertySet >& xPropSet,
2962         const uno::Any& rAny ) throw( uno::RuntimeException, lang::IllegalArgumentException )
2963 {
2964     double fResult;
2965     sal_Bool bContainsVal = getDouble( fResult, xPropSet, rAny );
2966     if( (fResult <= -2147483649.0) || (fResult >= 2147483648.0) )
2967         throw lang::IllegalArgumentException();
2968 
2969     rnResult = static_cast< sal_Int32 >( fResult );
2970     return bContainsVal;
2971 }
2972 
2973 sal_Int32 ScaAnyConverter::getInt32(
2974         const uno::Reference< beans::XPropertySet >& xPropSet,
2975         const uno::Any& rAny,
2976         sal_Int32 nDefault ) throw( uno::RuntimeException, lang::IllegalArgumentException )
2977 {
2978     sal_Int32 nResult;
2979     if( !getInt32( nResult, xPropSet, rAny ) )
2980         nResult = nDefault;
2981     return nResult;
2982 }
2983 
2984 
2985 
2986 //-----------------------------------------------------------------------------
2987 
2988 
2989