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