Version 3.6.0.2, tag libreoffice-3.6.0.2
[LibreOffice.git] / scaddins / source / analysis / analysishelper.cxx
bloba37632f2fca9af09455b79c2c89933591b4b8222
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * Copyright 2000, 2010 Oracle and/or its affiliates.
8 * OpenOffice.org - a multi-platform office productivity suite
10 * This file is part of OpenOffice.org.
12 * OpenOffice.org is free software: you can redistribute it and/or modify
13 * it under the terms of the GNU Lesser General Public License version 3
14 * only, as published by the Free Software Foundation.
16 * OpenOffice.org is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License version 3 for more details
20 * (a copy is included in the LICENSE file that accompanied this code).
22 * You should have received a copy of the GNU Lesser General Public License
23 * version 3 along with OpenOffice.org. If not, see
24 * <http://www.openoffice.org/license.html>
25 * for a copy of the LGPLv3 License.
27 ************************************************************************/
29 #include <com/sun/star/util/XNumberFormatTypes.hpp>
31 #include <string.h>
32 #include <stdio.h>
33 #include <tools/resary.hxx>
34 #include <rtl/math.hxx>
35 #include <sal/macros.h>
36 #include "analysishelper.hxx"
37 #include "analysis.hrc"
39 using namespace ::rtl;
40 using namespace ::com::sun::star;
44 #define UNIQUE sal_False // function name does not exist in Calc
45 #define DOUBLE sal_True // function name exists in Calc
47 #define STDPAR sal_False // all parameters are described
48 #define INTPAR sal_True // first parameter is internal
50 #define FUNCDATA( FUNCNAME, DBL, OPT, NUMOFPAR, CAT ) \
51 { "get" #FUNCNAME, ANALYSIS_FUNCNAME_##FUNCNAME, ANALYSIS_##FUNCNAME, DBL, OPT, ANALYSIS_DEFFUNCNAME_##FUNCNAME, NUMOFPAR, CAT }
53 const FuncDataBase pFuncDatas[] =
55 // UNIQUE or INTPAR or
56 // function name DOUBLE STDPAR # of param category
57 FUNCDATA( Workday, UNIQUE, INTPAR, 3, FDCat_DateTime ),
58 FUNCDATA( Yearfrac, UNIQUE, INTPAR, 3, FDCat_DateTime ),
59 FUNCDATA( Edate, UNIQUE, INTPAR, 2, FDCat_DateTime ),
60 FUNCDATA( Weeknum, DOUBLE, INTPAR, 2, FDCat_DateTime ),
61 FUNCDATA( Eomonth, UNIQUE, INTPAR, 2, FDCat_DateTime ),
62 FUNCDATA( Networkdays, UNIQUE, INTPAR, 3, FDCat_DateTime ),
63 FUNCDATA( Iseven, DOUBLE, STDPAR, 1, FDCat_Inf ),
64 FUNCDATA( Isodd, DOUBLE, STDPAR, 1, FDCat_Inf ),
65 FUNCDATA( Multinomial, UNIQUE, STDPAR, 1, FDCat_Math ),
66 FUNCDATA( Seriessum, UNIQUE, STDPAR, 4, FDCat_Math ),
67 FUNCDATA( Quotient, UNIQUE, STDPAR, 2, FDCat_Math ),
68 FUNCDATA( Mround, UNIQUE, STDPAR, 2, FDCat_Math ),
69 FUNCDATA( Sqrtpi, UNIQUE, STDPAR, 1, FDCat_Math ),
70 FUNCDATA( Randbetween, UNIQUE, STDPAR, 2, FDCat_Math ),
71 FUNCDATA( Gcd, DOUBLE, INTPAR, 1, FDCat_Math ),
72 FUNCDATA( Lcm, DOUBLE, INTPAR, 1, FDCat_Math ),
73 FUNCDATA( Besseli, UNIQUE, STDPAR, 2, FDCat_Tech ),
74 FUNCDATA( Besselj, UNIQUE, STDPAR, 2, FDCat_Tech ),
75 FUNCDATA( Besselk, UNIQUE, STDPAR, 2, FDCat_Tech ),
76 FUNCDATA( Bessely, UNIQUE, STDPAR, 2, FDCat_Tech ),
77 FUNCDATA( Bin2Oct, UNIQUE, INTPAR, 2, FDCat_Tech ),
78 FUNCDATA( Bin2Dec, UNIQUE, STDPAR, 1, FDCat_Tech ),
79 FUNCDATA( Bin2Hex, UNIQUE, INTPAR, 2, FDCat_Tech ),
80 FUNCDATA( Oct2Bin, UNIQUE, INTPAR, 2, FDCat_Tech ),
81 FUNCDATA( Oct2Dec, UNIQUE, STDPAR, 1, FDCat_Tech ),
82 FUNCDATA( Oct2Hex, UNIQUE, INTPAR, 2, FDCat_Tech ),
83 FUNCDATA( Dec2Bin, UNIQUE, INTPAR, 2, FDCat_Tech ),
84 FUNCDATA( Dec2Hex, UNIQUE, INTPAR, 2, FDCat_Tech ),
85 FUNCDATA( Dec2Oct, UNIQUE, INTPAR, 2, FDCat_Tech ),
86 FUNCDATA( Hex2Bin, UNIQUE, INTPAR, 2, FDCat_Tech ),
87 FUNCDATA( Hex2Dec, UNIQUE, STDPAR, 1, FDCat_Tech ),
88 FUNCDATA( Hex2Oct, UNIQUE, INTPAR, 2, FDCat_Tech ),
89 FUNCDATA( Delta, UNIQUE, INTPAR, 2, FDCat_Tech ),
90 FUNCDATA( Erf, UNIQUE, INTPAR, 2, FDCat_Tech ),
91 FUNCDATA( Erfc, UNIQUE, STDPAR, 1, FDCat_Tech ),
92 FUNCDATA( Gestep, UNIQUE, INTPAR, 2, FDCat_Tech ),
93 FUNCDATA( Factdouble, UNIQUE, STDPAR, 1, FDCat_Tech ),
94 FUNCDATA( Imabs, UNIQUE, STDPAR, 1, FDCat_Tech ),
95 FUNCDATA( Imaginary, UNIQUE, STDPAR, 1, FDCat_Tech ),
96 FUNCDATA( Impower, UNIQUE, STDPAR, 2, FDCat_Tech ),
97 FUNCDATA( Imargument, UNIQUE, STDPAR, 1, FDCat_Tech ),
98 FUNCDATA( Imcos, UNIQUE, STDPAR, 1, FDCat_Tech ),
99 FUNCDATA( Imdiv, UNIQUE, STDPAR, 2, FDCat_Tech ),
100 FUNCDATA( Imexp, UNIQUE, STDPAR, 1, FDCat_Tech ),
101 FUNCDATA( Imconjugate, UNIQUE, STDPAR, 1, FDCat_Tech ),
102 FUNCDATA( Imln, UNIQUE, STDPAR, 1, FDCat_Tech ),
103 FUNCDATA( Imlog10, UNIQUE, STDPAR, 1, FDCat_Tech ),
104 FUNCDATA( Imlog2, UNIQUE, STDPAR, 1, FDCat_Tech ),
105 FUNCDATA( Improduct, UNIQUE, INTPAR, 2, FDCat_Tech ),
106 FUNCDATA( Imreal, UNIQUE, STDPAR, 1, FDCat_Tech ),
107 FUNCDATA( Imsin, UNIQUE, STDPAR, 1, FDCat_Tech ),
108 FUNCDATA( Imsub, UNIQUE, STDPAR, 2, FDCat_Tech ),
109 FUNCDATA( Imsqrt, UNIQUE, STDPAR, 1, FDCat_Tech ),
110 FUNCDATA( Imsum, UNIQUE, INTPAR, 1, FDCat_Tech ),
111 FUNCDATA( Imtan, UNIQUE, STDPAR, 1, FDCat_Tech ),
112 FUNCDATA( Imsec, UNIQUE, STDPAR, 1, FDCat_Tech ),
113 FUNCDATA( Imcsc, UNIQUE, STDPAR, 1, FDCat_Tech ),
114 FUNCDATA( Imcot, UNIQUE, STDPAR, 1, FDCat_Tech ),
115 FUNCDATA( Imsinh, UNIQUE, STDPAR, 1, FDCat_Tech ),
116 FUNCDATA( Imcosh, UNIQUE, STDPAR, 1, FDCat_Tech ),
117 FUNCDATA( Imsech, UNIQUE, STDPAR, 1, FDCat_Tech ),
118 FUNCDATA( Imcsch, UNIQUE, STDPAR, 1, FDCat_Tech ),
119 FUNCDATA( Complex, UNIQUE, STDPAR, 3, FDCat_Tech ),
120 FUNCDATA( Convert, DOUBLE, STDPAR, 3, FDCat_Tech ),
121 FUNCDATA( Amordegrc, UNIQUE, INTPAR, 7, FDCat_Finance ),
122 FUNCDATA( Amorlinc, UNIQUE, INTPAR, 7, FDCat_Finance ),
123 FUNCDATA( Accrint, UNIQUE, INTPAR, 7, FDCat_Finance ),
124 FUNCDATA( Accrintm, UNIQUE, INTPAR, 5, FDCat_Finance ),
125 FUNCDATA( Received, UNIQUE, INTPAR, 5, FDCat_Finance ),
126 FUNCDATA( Disc, UNIQUE, INTPAR, 5, FDCat_Finance ),
127 FUNCDATA( Duration, DOUBLE, INTPAR, 6, FDCat_Finance ),
128 FUNCDATA( Effect, DOUBLE, STDPAR, 2, FDCat_Finance ),
129 FUNCDATA( Cumprinc, DOUBLE, STDPAR, 6, FDCat_Finance ),
130 FUNCDATA( Cumipmt, DOUBLE, STDPAR, 6, FDCat_Finance ),
131 FUNCDATA( Price, UNIQUE, INTPAR, 7, FDCat_Finance ),
132 FUNCDATA( Pricedisc, UNIQUE, INTPAR, 5, FDCat_Finance ),
133 FUNCDATA( Pricemat, UNIQUE, INTPAR, 6, FDCat_Finance ),
134 FUNCDATA( Mduration, UNIQUE, INTPAR, 6, FDCat_Finance ),
135 FUNCDATA( Nominal, DOUBLE, STDPAR, 2, FDCat_Finance ),
136 FUNCDATA( Dollarfr, UNIQUE, STDPAR, 2, FDCat_Finance ),
137 FUNCDATA( Dollarde, UNIQUE, STDPAR, 2, FDCat_Finance ),
138 FUNCDATA( Yield, UNIQUE, INTPAR, 7, FDCat_Finance ),
139 FUNCDATA( Yielddisc, UNIQUE, INTPAR, 5, FDCat_Finance ),
140 FUNCDATA( Yieldmat, UNIQUE, INTPAR, 6, FDCat_Finance ),
141 FUNCDATA( Tbilleq, UNIQUE, INTPAR, 3, FDCat_Finance ),
142 FUNCDATA( Tbillprice, UNIQUE, INTPAR, 3, FDCat_Finance ),
143 FUNCDATA( Tbillyield, UNIQUE, INTPAR, 3, FDCat_Finance ),
144 FUNCDATA( Oddfprice, UNIQUE, INTPAR, 9, FDCat_Finance ),
145 FUNCDATA( Oddfyield, UNIQUE, INTPAR, 9, FDCat_Finance ),
146 FUNCDATA( Oddlprice, UNIQUE, INTPAR, 8, FDCat_Finance ),
147 FUNCDATA( Oddlyield, UNIQUE, INTPAR, 8, FDCat_Finance ),
148 FUNCDATA( Xirr, UNIQUE, INTPAR, 3, FDCat_Finance ),
149 FUNCDATA( Xnpv, UNIQUE, STDPAR, 3, FDCat_Finance ),
150 FUNCDATA( Intrate, UNIQUE, INTPAR, 5, FDCat_Finance ),
151 FUNCDATA( Coupncd, UNIQUE, INTPAR, 4, FDCat_Finance ),
152 FUNCDATA( Coupdays, UNIQUE, INTPAR, 4, FDCat_Finance ),
153 FUNCDATA( Coupdaysnc, UNIQUE, INTPAR, 4, FDCat_Finance ),
154 FUNCDATA( Coupdaybs, UNIQUE, INTPAR, 4, FDCat_Finance ),
155 FUNCDATA( Couppcd, UNIQUE, INTPAR, 4, FDCat_Finance ),
156 FUNCDATA( Coupnum, UNIQUE, INTPAR, 4, FDCat_Finance ),
157 FUNCDATA( Fvschedule, UNIQUE, STDPAR, 2, FDCat_Finance )
159 #undef FUNCDATA
162 sal_uInt16 DaysInMonth( sal_uInt16 nMonth, sal_uInt16 nYear )
164 if( (nMonth == 2) && IsLeapYear( nYear ) )
165 return 29;
166 static const sal_uInt16 aDaysInMonth[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
167 return aDaysInMonth[ nMonth ];
172 * Convert a date to a count of days starting from 01/01/0001
174 * The internal representation of a Date used in this Addin
175 * is the number of days between 01/01/0001 and the date
176 * this function converts a Day , Month, Year representation
177 * to this internal Date value.
181 sal_Int32 DateToDays( sal_uInt16 nDay, sal_uInt16 nMonth, sal_uInt16 nYear )
183 sal_Int32 nDays = ((sal_Int32)nYear-1) * 365;
184 nDays += ((nYear-1) / 4) - ((nYear-1) / 100) + ((nYear-1) / 400);
186 for( sal_uInt16 i = 1; i < nMonth; i++ )
187 nDays += DaysInMonth(i,nYear);
188 nDays += nDay;
190 return nDays;
195 * Convert a count of days starting from 01/01/0001 to a date
197 * The internal representation of a Date used in this Addin
198 * is the number of days between 01/01/0001 and the date
199 * this function converts this internal Date value
200 * to a Day , Month, Year representation of a Date.
204 void DaysToDate( sal_Int32 nDays, sal_uInt16& rDay, sal_uInt16& rMonth, sal_uInt16& rYear )
205 throw( lang::IllegalArgumentException )
207 if( nDays < 0 )
208 throw lang::IllegalArgumentException();
210 sal_Int32 nTempDays;
211 sal_Int32 i = 0;
212 sal_Bool bCalc;
216 nTempDays = nDays;
217 rYear = (sal_uInt16)((nTempDays / 365) - i);
218 nTempDays -= ((sal_Int32) rYear -1) * 365;
219 nTempDays -= (( rYear -1) / 4) - (( rYear -1) / 100) + ((rYear -1) / 400);
220 bCalc = sal_False;
221 if ( nTempDays < 1 )
223 i++;
224 bCalc = sal_True;
226 else
228 if ( nTempDays > 365 )
230 if ( (nTempDays != 366) || !IsLeapYear( rYear ) )
232 i--;
233 bCalc = sal_True;
238 while ( bCalc );
240 rMonth = 1;
241 while ( (sal_Int32)nTempDays > DaysInMonth( rMonth, rYear ) )
243 nTempDays -= DaysInMonth( rMonth, rYear );
244 rMonth++;
246 rDay = (sal_uInt16)nTempDays;
251 * Get the null date used by the spreadsheet document
253 * The internal representation of a Date used in this Addin
254 * is the number of days between 01/01/0001 and the date
255 * this function returns this internal Date value for the document null date
259 sal_Int32 GetNullDate( constREFXPS& xOpt ) THROWDEF_RTE
261 if( xOpt.is() )
265 ANY aAny = xOpt->getPropertyValue( STRFROMASCII( "NullDate" ) );
266 util::Date aDate;
267 if( aAny >>= aDate )
268 return DateToDays( aDate.Day, aDate.Month, aDate.Year );
270 catch( uno::Exception& )
275 // no null date available -> no calculations possible
276 throw uno::RuntimeException();
280 sal_Int32 GetDiffDate360(
281 sal_uInt16 nDay1, sal_uInt16 nMonth1, sal_uInt16 nYear1, sal_Bool bLeapYear1,
282 sal_uInt16 nDay2, sal_uInt16 nMonth2, sal_uInt16 nYear2,
283 sal_Bool bUSAMethod )
285 if( nDay1 == 31 )
286 nDay1--;
287 else if( bUSAMethod && ( nMonth1 == 2 && ( nDay1 == 29 || ( nDay1 == 28 && !bLeapYear1 ) ) ) )
288 nDay1 = 30;
290 if( nDay2 == 31 )
292 if( bUSAMethod && nDay1 != 30 )
294 nDay2 = 1;
295 if( nMonth2 == 12 )
297 nYear2++;
298 nMonth2 = 1;
300 else
301 nMonth2++;
303 else
304 nDay2 = 30;
307 return nDay2 + nMonth2 * 30 + nYear2 * 360 - nDay1 - nMonth1 * 30 - nYear1 * 360;
311 sal_Int32 GetDiffDate360( sal_Int32 nNullDate, sal_Int32 nDate1, sal_Int32 nDate2, sal_Bool bUSAMethod )
313 nDate1 += nNullDate;
314 nDate2 += nNullDate;
316 sal_uInt16 nDay1, nMonth1, nYear1, nDay2, nMonth2, nYear2;
318 DaysToDate( nDate1, nDay1, nMonth1, nYear1 );
319 DaysToDate( nDate2, nDay2, nMonth2, nYear2 );
321 return GetDiffDate360( nDay1, nMonth1, nYear1, IsLeapYear( nYear1 ), nDay2, nMonth2, nYear2, bUSAMethod );
325 sal_Int32 GetDaysInYears( sal_uInt16 nYear1, sal_uInt16 nYear2 )
327 sal_uInt16 nLeaps = 0;
328 for( sal_uInt16 n = nYear1 ; n <= nYear2 ; n++ )
330 if( IsLeapYear( n ) )
331 nLeaps++;
334 sal_uInt32 nSum = 1;
335 nSum += nYear2;
336 nSum -= nYear1;
337 nSum *= 365;
338 nSum += nLeaps;
340 return nSum;
344 void GetDiffParam( sal_Int32 nNullDate, sal_Int32 nStartDate, sal_Int32 nEndDate, sal_Int32 nMode,
345 sal_uInt16& rYears, sal_Int32& rDayDiffPart, sal_Int32& rDaysInYear ) THROWDEF_RTE_IAE
347 if( nStartDate > nEndDate )
349 sal_Int32 n = nEndDate;
350 nEndDate = nStartDate;
351 nStartDate = n;
354 sal_Int32 nDate1 = nStartDate + nNullDate;
355 sal_Int32 nDate2 = nEndDate + nNullDate;
357 sal_uInt16 nDay1, nDay2;
358 sal_uInt16 nMonth1, nMonth2;
359 sal_uInt16 nYear1, nYear2;
361 DaysToDate( nDate1, nDay1, nMonth1, nYear1 );
362 DaysToDate( nDate2, nDay2, nMonth2, nYear2 );
364 sal_uInt16 nYears;
366 sal_Int32 nDayDiff, nDaysInYear;
368 switch( nMode )
370 case 0: // 0=USA (NASD) 30/360
371 case 4: // 4=Europe 30/360
372 nDaysInYear = 360;
373 nYears = nYear2 - nYear1;
374 nDayDiff = GetDiffDate360( nDay1, nMonth1, nYear1, IsLeapYear( nYear1 ),
375 nDay2, nMonth2, nYear2, nMode == 0 ) - nYears * nDaysInYear;
376 break;
377 case 1: // 1=exact/exact
378 nYears = nYear2 - nYear1;
380 nDaysInYear = IsLeapYear( nYear1 )? 366 : 365;
382 if( nYears && ( nMonth1 > nMonth2 || ( nMonth1 == nMonth2 && nDay1 > nDay2 ) ) )
383 nYears--;
385 if( nYears )
386 nDayDiff = nDate2 - DateToDays( nDay1, nMonth1, nYear2 );
387 else
388 nDayDiff = nDate2 - nDate1;
390 if( nDayDiff < 0 )
391 nDayDiff += nDaysInYear;
393 break;
394 case 2: // 2=exact/360
395 nDaysInYear = 360;
396 nYears = sal_uInt16( ( nDate2 - nDate1 ) / nDaysInYear );
397 nDayDiff = nDate2 - nDate1;
398 nDayDiff %= nDaysInYear;
399 break;
400 case 3: //3=exact/365
401 nDaysInYear = 365;
402 nYears = sal_uInt16( ( nDate2 - nDate1 ) / nDaysInYear );
403 nDayDiff = nDate2 - nDate1;
404 nDayDiff %= nDaysInYear;
405 break;
406 default:
407 THROW_IAE;
410 rYears = nYears;
411 rDayDiffPart = nDayDiff;
412 rDaysInYear = nDaysInYear;
416 sal_Int32 GetDiffDate( sal_Int32 nNullDate, sal_Int32 nStartDate, sal_Int32 nEndDate, sal_Int32 nMode,
417 sal_Int32* pOptDaysIn1stYear ) THROWDEF_RTE_IAE
419 sal_Bool bNeg = nStartDate > nEndDate;
421 if( bNeg )
423 sal_Int32 n = nEndDate;
424 nEndDate = nStartDate;
425 nStartDate = n;
428 sal_Int32 nRet;
430 switch( nMode )
432 case 0: // 0=USA (NASD) 30/360
433 case 4: // 4=Europe 30/360
435 sal_uInt16 nD1, nM1, nY1, nD2, nM2, nY2;
437 nStartDate += nNullDate;
438 nEndDate += nNullDate;
440 DaysToDate( nStartDate, nD1, nM1, nY1 );
441 DaysToDate( nEndDate, nD2, nM2, nY2 );
443 sal_Bool bLeap = IsLeapYear( nY1 );
444 sal_Int32 nDays, nMonths;
446 nMonths = nM2 - nM1;
447 nDays = nD2 - nD1;
449 nMonths += ( nY2 - nY1 ) * 12;
451 nRet = nMonths * 30 + nDays;
452 if( nMode == 0 && nM1 == 2 && nM2 != 2 && nY1 == nY2 )
453 nRet -= bLeap? 1 : 2;
455 if( pOptDaysIn1stYear )
456 *pOptDaysIn1stYear = 360;
458 break;
459 case 1: // 1=exact/exact
460 if( pOptDaysIn1stYear )
462 sal_uInt16 nD, nM, nY;
464 DaysToDate( nStartDate + nNullDate, nD, nM, nY );
466 *pOptDaysIn1stYear = IsLeapYear( nY )? 366 : 365;
468 nRet = nEndDate - nStartDate;
469 break;
470 case 2: // 2=exact/360
471 nRet = nEndDate - nStartDate;
472 if( pOptDaysIn1stYear )
473 *pOptDaysIn1stYear = 360;
474 break;
475 case 3: //3=exact/365
476 nRet = nEndDate - nStartDate;
477 if( pOptDaysIn1stYear )
478 *pOptDaysIn1stYear = 365;
479 break;
480 default:
481 THROW_IAE;
484 return bNeg? -nRet : nRet;
488 double GetYearDiff( sal_Int32 nNullDate, sal_Int32 nStartDate, sal_Int32 nEndDate, sal_Int32 nMode ) THROWDEF_RTE_IAE
490 sal_Int32 nDays1stYear;
491 sal_Int32 nTotalDays = GetDiffDate( nNullDate, nStartDate, nEndDate, nMode, &nDays1stYear );
493 return double( nTotalDays ) / double( nDays1stYear );
497 sal_Int32 GetDaysInYear( sal_Int32 nNullDate, sal_Int32 nDate, sal_Int32 nMode ) THROWDEF_RTE_IAE
499 switch( nMode )
501 case 0: // 0=USA (NASD) 30/360
502 case 2: // 2=exact/360
503 case 4: // 4=Europe 30/360
504 return 360;
505 case 1: // 1=exact/exact
507 sal_uInt16 nD, nM, nY;
508 nDate += nNullDate;
509 DaysToDate( nDate, nD, nM, nY );
510 return IsLeapYear( nY )? 366 : 365;
512 case 3: //3=exact/365
513 return 365;
514 default:
515 THROW_IAE;
520 double GetYearFrac( sal_Int32 nNullDate, sal_Int32 nStartDate, sal_Int32 nEndDate, sal_Int32 nMode ) THROWDEF_RTE_IAE
522 if( nStartDate == nEndDate )
523 return 0.0; // nothing to do...
525 sal_uInt16 nYears;
526 sal_Int32 nDayDiff, nDaysInYear;
528 GetDiffParam( nNullDate, nStartDate, nEndDate, nMode, nYears, nDayDiff, nDaysInYear );
530 return double( nYears ) + double( nDayDiff ) / double( nDaysInYear );
534 double Fak( sal_Int32 n )
536 if( n > 0 )
538 double fRet = n;
539 double f = n - 1;
541 while( f >= 2.0 )
543 fRet *= f;
544 f--;
547 return fRet;
549 else if( !n )
550 return 1.0;
551 else
552 return 0.0;
556 double GetGcd( double f1, double f2 )
558 double f = fmod( f1, f2 );
559 while( f > 0.0 )
561 f1 = f2;
562 f2 = f;
563 f = fmod( f1, f2 );
566 return f2;
570 double ConvertToDec( const STRING& aStr, sal_uInt16 nBase, sal_uInt16 nCharLim ) THROWDEF_RTE_IAE
572 if ( nBase < 2 || nBase > 36 )
573 THROW_IAE;
575 sal_uInt32 nStrLen = aStr.getLength();
576 if( nStrLen > nCharLim )
577 THROW_IAE;
578 else if( !nStrLen )
579 return 0.0;
581 double fVal = 0.0;
583 register const sal_Unicode* p = aStr.getStr();
585 sal_uInt16 nFirstDig = 0;
586 sal_Bool bFirstDig = sal_True;
587 double fBase = nBase;
589 while ( *p )
591 sal_uInt16 n;
593 if( '0' <= *p && *p <= '9' )
594 n = *p - '0';
595 else if( 'A' <= *p && *p <= 'Z' )
596 n = 10 + ( *p - 'A' );
597 else if ( 'a' <= *p && *p <= 'z' )
598 n = 10 + ( *p - 'a' );
599 else
600 n = nBase;
602 if( n < nBase )
604 if( bFirstDig )
606 bFirstDig = sal_False;
607 nFirstDig = n;
609 fVal = fVal * fBase + double( n );
611 else
612 // illegal char!
613 THROW_IAE;
615 p++;
619 if( nStrLen == nCharLim && !bFirstDig && (nFirstDig >= nBase / 2) )
620 { // handling negativ values
621 fVal = ( pow( double( nBase ), double( nCharLim ) ) - fVal ); // complement
622 fVal *= -1.0;
625 return fVal;
629 static inline sal_Char GetMaxChar( sal_uInt16 nBase )
631 const sal_Char* c = "--123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
632 return c[ nBase ];
636 STRING ConvertFromDec( double fNum, double fMin, double fMax, sal_uInt16 nBase,
637 sal_Int32 nPlaces, sal_Int32 nMaxPlaces, sal_Bool bUsePlaces ) THROWDEF_RTE_IAE
639 fNum = ::rtl::math::approxFloor( fNum );
640 fMin = ::rtl::math::approxFloor( fMin );
641 fMax = ::rtl::math::approxFloor( fMax );
643 if( fNum < fMin || fNum > fMax || ( bUsePlaces && ( nPlaces <= 0 || nPlaces > nMaxPlaces ) ) )
644 THROW_IAE;
646 sal_Int64 nNum = static_cast< sal_Int64 >( fNum );
647 sal_Bool bNeg = nNum < 0;
648 if( bNeg )
649 nNum = sal_Int64( pow( double( nBase ), double( nMaxPlaces ) ) ) + nNum;
651 STRING aRet( STRING::valueOf( nNum, nBase ).toAsciiUpperCase() );
654 if( bUsePlaces )
656 sal_Int32 nLen = aRet.getLength();
657 if( !bNeg && nLen > nPlaces )
659 THROW_IAE;
661 else if( ( bNeg && nLen < nMaxPlaces ) || ( !bNeg && nLen < nPlaces ) )
663 sal_Int32 nLeft = nPlaces - nLen;
664 sal_Char* p = new sal_Char[ nLeft + 1 ];
665 memset( p, bNeg? GetMaxChar( nBase ) : '0', nLeft );
666 p[ nLeft ] = 0x00;
667 STRING aTmp( p, nLeft, RTL_TEXTENCODING_MS_1252 );
668 aTmp += aRet;
669 aRet = aTmp;
671 delete[] p;
675 return aRet;
678 // implementation moved to module sal, see #i97091#
679 double Erf( double x )
681 return ::rtl::math::erf(x);
684 // implementation moved to module sal, see #i97091#
685 double Erfc( double x )
687 return ::rtl::math::erfc(x);
690 inline sal_Bool IsNum( sal_Unicode c )
692 return c >= '0' && c <= '9';
696 inline sal_Bool IsComma( sal_Unicode c )
698 return c == '.' || c == ',';
702 inline sal_Bool IsExpStart( sal_Unicode c )
704 return c == 'e' || c == 'E';
708 inline sal_Bool IsImagUnit( sal_Unicode c )
710 return c == 'i' || c == 'j';
714 inline sal_uInt16 GetVal( sal_Unicode c )
716 return sal_uInt16( c - '0' );
720 sal_Bool ParseDouble( const sal_Unicode*& rp, double& rRet )
722 double fInt = 0.0;
723 double fFrac = 0.0;
724 double fMult = 0.1; // multiplier to multiply digits with, when adding fractional ones
725 sal_Int32 nExp = 0;
726 sal_Int32 nMaxExp = 307;
727 sal_uInt16 nDigCnt = 18; // max. number of digits to read in, rest doesn't matter
729 enum State { S_End = 0, S_Sign, S_IntStart, S_Int, S_IgnoreIntDigs, S_Frac, S_IgnoreFracDigs, S_ExpSign, S_Exp };
731 State eS = S_Sign;
733 sal_Bool bNegNum = sal_False;
734 sal_Bool bNegExp = sal_False;
736 const sal_Unicode* p = rp;
737 sal_Unicode c;
739 while( eS )
741 c = *p;
742 switch( eS )
744 case S_Sign:
745 if( IsNum( c ) )
747 fInt = GetVal( c );
748 nDigCnt--;
749 eS = S_Int;
751 else if( c == '-' )
753 bNegNum = sal_True;
754 eS = S_IntStart;
756 else if( c == '+' )
757 eS = S_IntStart;
758 else if( IsComma( c ) )
759 eS = S_Frac;
760 else
761 return sal_False;
762 break;
763 case S_IntStart:
764 if( IsNum( c ) )
766 fInt = GetVal( c );
767 nDigCnt--;
768 eS = S_Int;
770 else if( IsComma( c ) )
771 eS = S_Frac;
772 else if( IsImagUnit( c ) )
774 rRet = 0.0;
775 return sal_True;
777 else
778 return sal_False;
779 break;
780 case S_Int:
781 if( IsNum( c ) )
783 fInt *= 10.0;
784 fInt += double( GetVal( c ) );
785 nDigCnt--;
786 if( !nDigCnt )
787 eS = S_IgnoreIntDigs;
789 else if( IsComma( c ) )
790 eS = S_Frac;
791 else if( IsExpStart( c ) )
792 eS = S_ExpSign;
793 else
794 eS = S_End;
795 break;
796 case S_IgnoreIntDigs:
797 if( IsNum( c ) )
798 nExp++; // just multiply num with 10... ;-)
799 else if( IsComma( c ) )
800 eS = S_Frac;
801 else if( IsExpStart( c ) )
802 eS = S_ExpSign;
803 else
804 eS = S_End;
805 break;
806 case S_Frac:
807 if( IsNum( c ) )
809 fFrac += double( GetVal( c ) ) * fMult;
810 nDigCnt--;
811 if( nDigCnt )
812 fMult *= 0.1;
813 else
814 eS = S_IgnoreFracDigs;
816 else if( IsExpStart( c ) )
817 eS = S_ExpSign;
818 else
819 eS = S_End;
820 break;
821 case S_IgnoreFracDigs:
822 if( IsExpStart( c ) )
823 eS = S_ExpSign;
824 else if( !IsNum( c ) )
825 eS = S_End;
826 break;
827 case S_ExpSign:
828 if( IsNum( c ) )
830 nExp = GetVal( c );
831 eS = S_Exp;
833 else if( c == '-' )
835 bNegExp = sal_True;
836 eS = S_Exp;
838 else if( c != '+' )
839 eS = S_End;
840 break;
841 case S_Exp:
842 if( IsNum( c ) )
844 nExp *= 10;
845 nExp += GetVal( c );
846 if( nExp > nMaxExp )
847 return sal_False;
849 else
850 eS = S_End;
851 break;
852 case S_End: // to avoid compiler warning
853 break; // loop exits anyway
856 p++;
859 p--; // set pointer back to last
860 rp = p;
862 fInt += fFrac;
863 sal_Int32 nLog10 = sal_Int32( log10( fInt ) );
865 if( bNegExp )
866 nExp = -nExp;
868 if( nLog10 + nExp > nMaxExp )
869 return sal_False;
871 fInt = ::rtl::math::pow10Exp( fInt, nExp );
873 if( bNegNum )
874 fInt = -fInt;
876 rRet = fInt;
878 return sal_True;
882 STRING GetString( double f, sal_Bool bLeadingSign, sal_uInt16 nMaxDig )
884 const int nBuff = 256;
885 sal_Char aBuff[ nBuff + 1 ];
886 const char* pFormStr = bLeadingSign? "%+.*g" : "%.*g";
887 int nLen = snprintf( aBuff, nBuff, pFormStr, int( nMaxDig ), f );
888 // you never know which underlying implementation you get ...
889 aBuff[nBuff] = 0;
890 if ( nLen < 0 || nLen > nBuff )
891 nLen = strlen( aBuff );
893 STRING aRet( aBuff, nLen, RTL_TEXTENCODING_MS_1252 );
895 return aRet;
899 double GetAmordegrc( sal_Int32 nNullDate, double fCost, sal_Int32 nDate, sal_Int32 nFirstPer,
900 double fRestVal, double fPer, double fRate, sal_Int32 nBase ) THROWDEF_RTE_IAE
902 if( nBase == 2 )
903 THROW_IAE;
905 sal_uInt32 nPer = sal_uInt32( fPer );
906 double fUsePer = 1.0 / fRate;
907 double fAmorCoeff;
909 if( fUsePer < 3.0 )
910 fAmorCoeff = 1.0;
911 else if( fUsePer < 5.0 )
912 fAmorCoeff = 1.5;
913 else if( fUsePer <= 6.0 )
914 fAmorCoeff = 2.0;
915 else
916 fAmorCoeff = 2.5;
918 fRate *= fAmorCoeff;
919 double fNRate = ::rtl::math::round( GetYearFrac( nNullDate, nDate, nFirstPer, nBase ) * fRate * fCost, 0 );
920 fCost -= fNRate;
921 double fRest = fCost - fRestVal; // Anschaffungskosten - Restwert - Summe aller Abschreibungen
923 for( sal_uInt32 n = 0 ; n < nPer ; n++ )
925 fNRate = ::rtl::math::round( fRate * fCost, 0 );
926 fRest -= fNRate;
928 if( fRest < 0.0 )
930 switch( nPer - n )
932 case 0:
933 case 1:
934 return ::rtl::math::round( fCost * 0.5, 0 );
935 default:
936 return 0.0;
940 fCost -= fNRate;
943 return fNRate;
947 double GetAmorlinc( sal_Int32 nNullDate, double fCost, sal_Int32 nDate, sal_Int32 nFirstPer,
948 double fRestVal, double fPer, double fRate, sal_Int32 nBase ) THROWDEF_RTE_IAE
950 if( nBase == 2 )
951 THROW_IAE;
953 sal_uInt32 nPer = sal_uInt32( fPer );
954 double fOneRate = fCost * fRate;
955 double fCostDelta = fCost - fRestVal;
956 double f0Rate = GetYearFrac( nNullDate, nDate, nFirstPer, nBase ) * fRate * fCost;
957 sal_uInt32 nNumOfFullPeriods = sal_uInt32( ( fCost - fRestVal - f0Rate) / fOneRate );
959 if( nPer == 0 )
960 return f0Rate;
961 else if( nPer <= nNumOfFullPeriods )
962 return fOneRate;
963 else if( nPer == nNumOfFullPeriods + 1 )
964 return fCostDelta - fOneRate * nNumOfFullPeriods - f0Rate;
965 else
966 return 0.0;
970 double GetDuration( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, double fCoup,
971 double fYield, sal_Int32 nFreq, sal_Int32 nBase ) THROWDEF_RTE_IAE
973 double fYearfrac = GetYearFrac( nNullDate, nSettle, nMat, nBase );
974 double fNumOfCoups = GetCoupnum( nNullDate, nSettle, nMat, nFreq, nBase );
975 double fDur = 0.0;
976 const double f100 = 100.0;
977 fCoup *= f100 / double( nFreq ); // fCoup is used as cash flow
978 fYield /= nFreq;
979 fYield += 1.0;
981 double nDiff = fYearfrac * nFreq - fNumOfCoups;
983 double t;
985 for( t = 1.0 ; t < fNumOfCoups ; t++ )
986 fDur += ( t + nDiff ) * ( fCoup ) / pow( fYield, t + nDiff );
988 fDur += ( fNumOfCoups + nDiff ) * ( fCoup + f100 ) / pow( fYield, fNumOfCoups + nDiff );
990 double p = 0.0;
991 for( t = 1.0 ; t < fNumOfCoups ; t++ )
992 p += fCoup / pow( fYield, t + nDiff );
994 p += ( fCoup + f100 ) / pow( fYield, fNumOfCoups + nDiff );
996 fDur /= p;
997 fDur /= double( nFreq );
999 return fDur;
1003 double GetYieldmat( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nIssue,
1004 double fRate, double fPrice, sal_Int32 nBase ) THROWDEF_RTE_IAE
1006 double fIssMat = GetYearFrac( nNullDate, nIssue, nMat, nBase );
1007 double fIssSet = GetYearFrac( nNullDate, nIssue, nSettle, nBase );
1008 double fSetMat = GetYearFrac( nNullDate, nSettle, nMat, nBase );
1010 double y = 1.0 + fIssMat * fRate;
1011 y /= fPrice / 100.0 + fIssSet * fRate;
1012 y--;
1013 y /= fSetMat;
1015 return y;
1019 double GetOddfprice( sal_Int32 /*nNullDate*/, sal_Int32 /*nSettle*/, sal_Int32 /*nMat*/, sal_Int32 /*nIssue*/,
1020 sal_Int32 /*nFirstCoup*/, double /*fRate*/, double /*fYield*/, double /*fRedemp*/, sal_Int32 /*nFreq*/,
1021 sal_Int32 /*nBase*/ ) THROWDEF_RTE_IAE
1023 THROW_RTE; // #87380#
1027 double getYield_( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, double fCoup, double fPrice,
1028 double fRedemp, sal_Int32 nFreq, sal_Int32 nBase ) THROWDEF_RTE_IAE
1030 double fRate = fCoup;
1031 double fPriceN = 0.0;
1032 double fYield1 = 0.0;
1033 double fYield2 = 1.0;
1034 double fPrice1 = getPrice_( nNullDate, nSettle, nMat, fRate, fYield1, fRedemp, nFreq, nBase );
1035 double fPrice2 = getPrice_( nNullDate, nSettle, nMat, fRate, fYield2, fRedemp, nFreq, nBase );
1036 double fYieldN = ( fYield2 - fYield1 ) * 0.5;
1038 for( sal_uInt32 nIter = 0 ; nIter < 100 && fPriceN != fPrice ; nIter++ )
1040 fPriceN = getPrice_( nNullDate, nSettle, nMat, fRate, fYieldN, fRedemp, nFreq, nBase );
1042 if( fPrice == fPrice1 )
1043 return fYield1;
1044 else if( fPrice == fPrice2 )
1045 return fYield2;
1046 else if( fPrice == fPriceN )
1047 return fYieldN;
1048 else if( fPrice < fPrice2 )
1050 fYield2 *= 2.0;
1051 fPrice2 = getPrice_( nNullDate, nSettle, nMat, fRate, fYield2, fRedemp, nFreq, nBase );
1053 fYieldN = ( fYield2 - fYield1 ) * 0.5;
1055 else
1057 if( fPrice < fPriceN )
1059 fYield1 = fYieldN;
1060 fPrice1 = fPriceN;
1062 else
1064 fYield2 = fYieldN;
1065 fPrice2 = fPriceN;
1068 fYieldN = fYield2 - ( fYield2 - fYield1 ) * ( ( fPrice - fPrice2 ) / ( fPrice1 - fPrice2 ) );
1072 if( fabs( fPrice - fPriceN ) > fPrice / 100.0 )
1073 THROW_IAE; // result not precise enough
1075 return fYieldN;
1079 double getPrice_( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, double fRate, double fYield,
1080 double fRedemp, sal_Int32 nFreq, sal_Int32 nBase ) THROWDEF_RTE_IAE
1082 double fFreq = nFreq;
1084 double fE = GetCoupdays( nNullDate, nSettle, nMat, nFreq, nBase );
1085 double fDSC_E = GetCoupdaysnc( nNullDate, nSettle, nMat, nFreq, nBase ) / fE;
1086 double fN = GetCoupnum( nNullDate, nSettle, nMat, nFreq, nBase );
1087 double fA = GetCoupdaybs( nNullDate, nSettle, nMat, nFreq, nBase );
1089 double fRet = fRedemp / ( pow( 1.0 + fYield / fFreq, fN - 1.0 + fDSC_E ) );
1090 fRet -= 100.0 * fRate / fFreq * fA / fE;
1092 double fT1 = 100.0 * fRate / fFreq;
1093 double fT2 = 1.0 + fYield / fFreq;
1095 for( double fK = 0.0 ; fK < fN ; fK++ )
1096 fRet += fT1 / pow( fT2, fK + fDSC_E );
1098 return fRet;
1102 double GetOddfyield( sal_Int32 /*nNullDate*/, sal_Int32 /*nSettle*/, sal_Int32 /*nMat*/, sal_Int32 /*nIssue*/,
1103 sal_Int32 /*nFirstCoup*/, double /*fRate*/, double /*fPrice*/, double /*fRedemp*/, sal_Int32 /*nFreq*/,
1104 sal_Int32 /*nBase*/ ) THROWDEF_RTE_IAE
1106 THROW_RTE; // #87380#
1110 double GetOddlprice( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nLastCoup,
1111 double fRate, double fYield, double fRedemp, sal_Int32 nFreq, sal_Int32 nBase ) THROWDEF_RTE_IAE
1113 double fFreq = double( nFreq );
1114 double fDCi = GetYearFrac( nNullDate, nLastCoup, nMat, nBase ) * fFreq;
1115 double fDSCi = GetYearFrac( nNullDate, nSettle, nMat, nBase ) * fFreq;
1116 double fAi = GetYearFrac( nNullDate, nLastCoup, nSettle, nBase ) * fFreq;
1118 double p = fRedemp + fDCi * 100.0 * fRate / fFreq;
1119 p /= fDSCi * fYield / fFreq + 1.0;
1120 p -= fAi * 100.0 * fRate / fFreq;
1122 return p;
1126 double GetOddlyield( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nLastCoup,
1127 double fRate, double fPrice, double fRedemp, sal_Int32 nFreq, sal_Int32 nBase ) THROWDEF_RTE_IAE
1129 double fFreq = double( nFreq );
1130 double fDCi = GetYearFrac( nNullDate, nLastCoup, nMat, nBase ) * fFreq;
1131 double fDSCi = GetYearFrac( nNullDate, nSettle, nMat, nBase ) * fFreq;
1132 double fAi = GetYearFrac( nNullDate, nLastCoup, nSettle, nBase ) * fFreq;
1134 double y = fRedemp + fDCi * 100.0 * fRate / fFreq;
1135 y /= fPrice + fAi * 100.0 * fRate / fFreq;
1136 y--;
1137 y *= fFreq / fDSCi;
1139 return y;
1143 double GetRmz( double fZins, double fZzr, double fBw, double fZw, sal_Int32 nF )
1145 double fRmz;
1146 if( fZins == 0.0 )
1147 fRmz = ( fBw + fZw ) / fZzr;
1148 else
1150 double fTerm = pow( 1.0 + fZins, fZzr );
1151 if( nF > 0 )
1152 fRmz = ( fZw * fZins / ( fTerm - 1.0 ) + fBw * fZins / ( 1.0 - 1.0 / fTerm ) ) / ( 1.0 + fZins );
1153 else
1154 fRmz = fZw * fZins / ( fTerm - 1.0 ) + fBw * fZins / ( 1.0 - 1.0 / fTerm );
1157 return -fRmz;
1161 double GetZw( double fZins, double fZzr, double fRmz, double fBw, sal_Int32 nF )
1163 double fZw;
1164 if( fZins == 0.0 )
1165 fZw = fBw + fRmz * fZzr;
1166 else
1168 double fTerm = pow( 1.0 + fZins, fZzr );
1169 if( nF > 0 )
1170 fZw = fBw * fTerm + fRmz * ( 1.0 + fZins ) * ( fTerm - 1.0 ) / fZins;
1171 else
1172 fZw = fBw * fTerm + fRmz * ( fTerm - 1.0 ) / fZins;
1175 return -fZw;
1179 //-----------------------------------------------------------------------------
1180 // financial functions COUP***
1183 //-------
1184 // COUPPCD: find last coupon date before settlement (can be equal to settlement)
1185 void lcl_GetCouppcd( ScaDate& rDate, const ScaDate& rSettle, const ScaDate& rMat, sal_Int32 nFreq )
1186 throw( lang::IllegalArgumentException )
1188 rDate = rMat;
1189 rDate.setYear( rSettle.getYear() );
1190 if( rDate < rSettle )
1191 rDate.addYears( 1 );
1192 while( rDate > rSettle )
1193 rDate.addMonths( -12 / nFreq );
1196 double GetCouppcd( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nFreq, sal_Int32 nBase )
1197 THROWDEF_RTE_IAE
1199 if( nSettle >= nMat || CHK_Freq )
1200 THROW_IAE;
1202 ScaDate aDate;
1203 lcl_GetCouppcd( aDate, ScaDate( nNullDate, nSettle, nBase ), ScaDate( nNullDate, nMat, nBase ), nFreq );
1204 return aDate.getDate( nNullDate );
1208 //-------
1209 // COUPNCD: find first coupon date after settlement (is never equal to settlement)
1210 void lcl_GetCoupncd( ScaDate& rDate, const ScaDate& rSettle, const ScaDate& rMat, sal_Int32 nFreq )
1211 throw( lang::IllegalArgumentException )
1213 rDate = rMat;
1214 rDate.setYear( rSettle.getYear() );
1215 if( rDate > rSettle )
1216 rDate.addYears( -1 );
1217 while( rDate <= rSettle )
1218 rDate.addMonths( 12 / nFreq );
1221 double GetCoupncd( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nFreq, sal_Int32 nBase )
1222 THROWDEF_RTE_IAE
1224 if( nSettle >= nMat || CHK_Freq )
1225 THROW_IAE;
1227 ScaDate aDate;
1228 lcl_GetCoupncd( aDate, ScaDate( nNullDate, nSettle, nBase ), ScaDate( nNullDate, nMat, nBase ), nFreq );
1229 return aDate.getDate( nNullDate );
1233 //-------
1234 // COUPDAYBS: get day count: coupon date before settlement <-> settlement
1235 double GetCoupdaybs( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nFreq, sal_Int32 nBase )
1236 THROWDEF_RTE_IAE
1238 if( nSettle >= nMat || CHK_Freq )
1239 THROW_IAE;
1241 ScaDate aSettle( nNullDate, nSettle, nBase );
1242 ScaDate aDate;
1243 lcl_GetCouppcd( aDate, aSettle, ScaDate( nNullDate, nMat, nBase ), nFreq );
1244 return ScaDate::getDiff( aDate, aSettle );
1248 //-------
1249 // COUPDAYSNC: get day count: settlement <-> coupon date after settlement
1250 double GetCoupdaysnc( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nFreq, sal_Int32 nBase )
1251 THROWDEF_RTE_IAE
1253 if( nSettle >= nMat || CHK_Freq )
1254 THROW_IAE;
1256 if( (nBase != 0) && (nBase != 4) )
1258 ScaDate aSettle( nNullDate, nSettle, nBase );
1259 ScaDate aDate;
1260 lcl_GetCoupncd( aDate, aSettle, ScaDate( nNullDate, nMat, nBase ), nFreq );
1261 return ScaDate::getDiff( aSettle, aDate );
1263 return GetCoupdays( nNullDate, nSettle, nMat, nFreq, nBase ) - GetCoupdaybs( nNullDate, nSettle, nMat, nFreq, nBase );
1267 //-------
1268 // COUPDAYS: get day count: coupon date before settlement <-> coupon date after settlement
1269 double GetCoupdays( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nFreq, sal_Int32 nBase )
1270 THROWDEF_RTE_IAE
1272 if( nSettle >= nMat || CHK_Freq )
1273 THROW_IAE;
1275 if( nBase == 1 )
1277 ScaDate aDate;
1278 lcl_GetCouppcd( aDate, ScaDate( nNullDate, nSettle, nBase ), ScaDate( nNullDate, nMat, nBase ), nFreq );
1279 ScaDate aNextDate( aDate );
1280 aNextDate.addMonths( 12 / nFreq );
1281 return ScaDate::getDiff( aDate, aNextDate );
1283 return static_cast< double >( GetDaysInYear( 0, 0, nBase ) ) / nFreq;
1287 //-------
1288 // COUPNUM: get count of coupon dates
1289 double GetCoupnum( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nFreq, sal_Int32 nBase )
1290 THROWDEF_RTE_IAE
1292 if( nSettle >= nMat || CHK_Freq )
1293 THROW_IAE;
1295 ScaDate aMat( nNullDate, nMat, nBase );
1296 ScaDate aDate;
1297 lcl_GetCouppcd( aDate, ScaDate( nNullDate, nSettle, nBase ), aMat, nFreq );
1298 sal_uInt16 nMonths = (aMat.getYear() - aDate.getYear()) * 12 + aMat.getMonth() - aDate.getMonth();
1299 return static_cast< double >( nMonths * nFreq / 12 );
1308 const sal_uInt32 MyList::nStartSize = 16;
1309 const sal_uInt32 MyList::nIncrSize = 16;
1312 void MyList::_Grow( void )
1314 nSize += nIncrSize;
1316 void** pNewData = new void*[ nSize ];
1317 memcpy( pNewData, pData, nNew * sizeof( void* ) );
1319 delete[] pData;
1320 pData = pNewData;
1324 MyList::MyList( void )
1326 nSize = nStartSize;
1327 pData = new void*[ nSize ];
1328 nNew = nAct = 0;
1332 MyList::~MyList()
1334 delete[] pData;
1338 void MyList::Insert( void* p, sal_uInt32 n )
1340 if( n >= nNew )
1341 Append( p );
1342 else
1344 Grow();
1346 void** pIns = pData + n;
1347 memmove( pIns + 1, pIns, ( nNew - n ) * sizeof( void* ) );
1349 *pIns = p;
1351 nNew++;
1358 StringList::~StringList()
1360 for( STRING* p = ( STRING* ) First() ; p ; p = ( STRING* ) Next() )
1361 delete p;
1365 class AnalysisRscStrArrLoader : public Resource
1367 private:
1368 ResStringArray aStrArray;
1369 public:
1370 AnalysisRscStrArrLoader( sal_uInt16 nRsc, sal_uInt16 nArrayId, ResMgr& rResMgr ) :
1371 Resource( AnalysisResId( nRsc, rResMgr ) ),
1372 aStrArray( AnalysisResId( nArrayId, rResMgr ) )
1374 FreeResource();
1377 const ResStringArray& GetStringArray() const { return aStrArray; }
1383 FuncData::FuncData( const FuncDataBase& r, ResMgr& rResMgr ) :
1384 aIntName( OUString::createFromAscii( r.pIntName ) ),
1385 nUINameID( r.nUINameID ),
1386 nDescrID( r.nDescrID ),
1387 bDouble( r.bDouble ),
1388 bWithOpt( r.bWithOpt ),
1389 nParam( r.nNumOfParams ),
1390 nCompID( r.nCompListID ),
1391 eCat( r.eCat )
1393 AnalysisRscStrArrLoader aArrLoader( RID_ANALYSIS_DEFFUNCTION_NAMES, nCompID, rResMgr );
1394 const ResStringArray& rArr = aArrLoader.GetStringArray();
1396 sal_uInt16 nCount = sal::static_int_cast<sal_uInt16>( rArr.Count() );
1397 sal_uInt16 n;
1399 for( n = 0 ; n < nCount ; n++ )
1400 aCompList.Append( rArr.GetString( n ) );
1404 FuncData::~FuncData()
1409 sal_uInt16 FuncData::GetStrIndex( sal_uInt16 nParamNum ) const
1411 if( !bWithOpt )
1412 nParamNum++;
1414 if( nParamNum > nParam )
1415 return nParam * 2;
1416 else
1417 return nParamNum * 2;
1423 FuncDataList::FuncDataList( ResMgr& rResMgr )
1425 for( sal_uInt16 n = 0 ; n < SAL_N_ELEMENTS(pFuncDatas) ; n++ )
1426 Append( new FuncData( pFuncDatas[ n ], rResMgr ) );
1430 FuncDataList::~FuncDataList()
1432 for( FuncData* p = ( FuncData* ) First() ; p ; p = ( FuncData* ) Next() )
1433 delete p;
1437 const FuncData* FuncDataList::Get( const OUString& aProgrammaticName ) const
1439 if( aLastName == aProgrammaticName )
1440 return Get( nLast );
1442 ( ( FuncDataList* ) this )->aLastName = aProgrammaticName;
1444 sal_uInt32 nE = Count();
1445 for( sal_uInt32 n = 0 ; n < nE ; n++ )
1447 const FuncData* p = Get( n );
1448 if( p->Is( aProgrammaticName ) )
1450 ( ( FuncDataList* ) this )->nLast = n;
1451 return p;
1455 ( ( FuncDataList* ) this )->nLast = 0xFFFFFFFF;
1456 return NULL;
1460 AnalysisResId::AnalysisResId( sal_uInt16 nId, ResMgr& rResMgr ) : ResId( nId, rResMgr )
1467 SortedIndividualInt32List::SortedIndividualInt32List()
1472 SortedIndividualInt32List::~SortedIndividualInt32List()
1477 void SortedIndividualInt32List::Insert( sal_Int32 nDay )
1479 sal_uInt32 nIndex = Count();
1480 while( nIndex )
1482 nIndex--;
1483 sal_Int32 nRef = Get( nIndex );
1484 if( nDay == nRef )
1485 return;
1486 else if( nDay > nRef )
1488 MyList::Insert( (void*)(sal_IntPtr)nDay, nIndex + 1 );
1489 return;
1492 MyList::Insert( (void*)(sal_IntPtr)nDay, 0UL );
1496 void SortedIndividualInt32List::Insert( sal_Int32 nDay, sal_Int32 nNullDate, sal_Bool bInsertOnWeekend )
1498 if( !nDay )
1499 return;
1501 nDay += nNullDate;
1502 if( bInsertOnWeekend || (GetDayOfWeek( nDay ) < 5) )
1503 Insert( nDay );
1507 void SortedIndividualInt32List::Insert(
1508 double fDay, sal_Int32 nNullDate, sal_Bool bInsertOnWeekend ) throw( uno::RuntimeException, lang::IllegalArgumentException )
1510 if( (fDay < -2147483648.0) || (fDay > 2147483649.0) )
1511 throw lang::IllegalArgumentException();
1512 Insert( static_cast< sal_Int32 >( fDay ), nNullDate, bInsertOnWeekend );
1516 sal_Bool SortedIndividualInt32List::Find( sal_Int32 nVal ) const
1518 sal_uInt32 nE = Count();
1520 if( !nE || nVal < Get( 0 ) || nVal > Get( nE - 1 ) )
1521 return sal_False;
1523 // linear search
1525 for( sal_uInt32 n = 0 ; n < nE ; n++ )
1527 sal_Int32 nRef = Get( n );
1529 if( nRef == nVal )
1530 return sal_True;
1531 else if( nRef > nVal )
1532 return sal_False;
1534 return sal_False;
1538 void SortedIndividualInt32List::InsertHolidayList(
1539 const ScaAnyConverter& rAnyConv,
1540 const uno::Any& rHolAny,
1541 sal_Int32 nNullDate,
1542 sal_Bool bInsertOnWeekend ) throw( uno::RuntimeException, lang::IllegalArgumentException )
1544 double fDay;
1545 if( rAnyConv.getDouble( fDay, rHolAny ) )
1546 Insert( fDay, nNullDate, bInsertOnWeekend );
1550 void SortedIndividualInt32List::InsertHolidayList(
1551 ScaAnyConverter& rAnyConv,
1552 const uno::Reference< beans::XPropertySet >& xOptions,
1553 const uno::Any& rHolAny,
1554 sal_Int32 nNullDate,
1555 sal_Bool bInsertOnWeekend ) throw( uno::RuntimeException, lang::IllegalArgumentException )
1557 rAnyConv.init( xOptions );
1558 if( rHolAny.getValueTypeClass() == uno::TypeClass_SEQUENCE )
1560 uno::Sequence< uno::Sequence< uno::Any > > aAnySeq;
1561 if( rHolAny >>= aAnySeq )
1563 const uno::Sequence< uno::Any >* pSeqArray = aAnySeq.getConstArray();
1564 for( sal_Int32 nIndex1 = 0; nIndex1 < aAnySeq.getLength(); nIndex1++ )
1566 const uno::Sequence< uno::Any >& rSubSeq = pSeqArray[ nIndex1 ];
1567 const uno::Any* pAnyArray = rSubSeq.getConstArray();
1569 for( sal_Int32 nIndex2 = 0; nIndex2 < rSubSeq.getLength(); nIndex2++ )
1570 InsertHolidayList( rAnyConv, pAnyArray[ nIndex2 ], nNullDate, bInsertOnWeekend );
1573 else
1574 throw lang::IllegalArgumentException();
1576 else
1577 InsertHolidayList( rAnyConv, rHolAny, nNullDate, bInsertOnWeekend );
1582 //-----------------------------------------------------------------------------
1584 ScaDoubleList::~ScaDoubleList()
1586 for( double* pDbl = const_cast< double* >( First() ); pDbl; pDbl = const_cast< double* >( Next() ) )
1587 delete pDbl;
1591 void ScaDoubleList::Append(
1592 const uno::Sequence< uno::Sequence< double > >& rValueSeq ) throw( uno::RuntimeException, lang::IllegalArgumentException )
1594 const uno::Sequence< double >* pSeqArray = rValueSeq.getConstArray();
1595 for( sal_Int32 nIndex1 = 0; nIndex1 < rValueSeq.getLength(); nIndex1++ )
1597 const uno::Sequence< double >& rSubSeq = pSeqArray[ nIndex1 ];
1598 const double* pArray = rSubSeq.getConstArray();
1599 for( sal_Int32 nIndex2 = 0; nIndex2 < rSubSeq.getLength(); nIndex2++ )
1600 Append( pArray[ nIndex2 ] );
1605 void ScaDoubleList::Append(
1606 const uno::Sequence< uno::Sequence< sal_Int32 > >& rValueSeq ) throw( uno::RuntimeException, lang::IllegalArgumentException )
1608 const uno::Sequence< sal_Int32 >* pSeqArray = rValueSeq.getConstArray();
1609 for( sal_Int32 nIndex1 = 0; nIndex1 < rValueSeq.getLength(); nIndex1++ )
1611 const uno::Sequence< sal_Int32 >& rSubSeq = pSeqArray[ nIndex1 ];
1612 const sal_Int32* pArray = rSubSeq.getConstArray();
1613 for( sal_Int32 nIndex2 = 0; nIndex2 < rSubSeq.getLength(); nIndex2++ )
1614 Append( pArray[ nIndex2 ] );
1620 void ScaDoubleList::Append(
1621 const ScaAnyConverter& rAnyConv,
1622 const uno::Any& rAny,
1623 sal_Bool bIgnoreEmpty ) throw( uno::RuntimeException, lang::IllegalArgumentException )
1625 if( rAny.getValueTypeClass() == uno::TypeClass_SEQUENCE )
1626 Append( rAnyConv, *static_cast< const uno::Sequence< uno::Sequence< uno::Any > >* >( rAny.getValue() ), bIgnoreEmpty );
1627 else
1629 double fValue;
1630 if( rAnyConv.getDouble( fValue, rAny ) )
1631 Append( fValue );
1632 else if( !bIgnoreEmpty )
1633 Append( 0.0 );
1638 void ScaDoubleList::Append(
1639 const ScaAnyConverter& rAnyConv,
1640 const uno::Sequence< uno::Any >& rAnySeq,
1641 sal_Bool bIgnoreEmpty ) throw( uno::RuntimeException, lang::IllegalArgumentException )
1643 const uno::Any* pArray = rAnySeq.getConstArray();
1644 for( sal_Int32 nIndex = 0; nIndex < rAnySeq.getLength(); nIndex++ )
1645 Append( rAnyConv, pArray[ nIndex ], bIgnoreEmpty );
1649 void ScaDoubleList::Append(
1650 const ScaAnyConverter& rAnyConv,
1651 const uno::Sequence< uno::Sequence< uno::Any > >& rAnySeq,
1652 sal_Bool bIgnoreEmpty ) throw( uno::RuntimeException, lang::IllegalArgumentException )
1654 const uno::Sequence< uno::Any >* pArray = rAnySeq.getConstArray();
1655 for( sal_Int32 nIndex = 0; nIndex < rAnySeq.getLength(); nIndex++ )
1656 Append( rAnyConv, pArray[ nIndex ], bIgnoreEmpty );
1661 void ScaDoubleList::Append(
1662 ScaAnyConverter& rAnyConv,
1663 const uno::Reference< beans::XPropertySet >& xOpt,
1664 const uno::Sequence< uno::Any >& rAnySeq,
1665 sal_Bool bIgnoreEmpty ) throw( uno::RuntimeException, lang::IllegalArgumentException )
1667 rAnyConv.init( xOpt );
1668 Append( rAnyConv, rAnySeq, bIgnoreEmpty );
1672 sal_Bool ScaDoubleList::CheckInsert( double ) const throw( uno::RuntimeException, lang::IllegalArgumentException )
1674 return sal_True;
1679 //-----------------------------------------------------------------------------
1681 sal_Bool ScaDoubleListGT0::CheckInsert( double fValue ) const throw( uno::RuntimeException, lang::IllegalArgumentException )
1683 if( fValue < 0.0 )
1684 throw lang::IllegalArgumentException();
1685 return fValue > 0.0;
1690 //-----------------------------------------------------------------------------
1692 sal_Bool ScaDoubleListGE0::CheckInsert( double fValue ) const throw( uno::RuntimeException, lang::IllegalArgumentException )
1694 if( fValue < 0.0 )
1695 throw lang::IllegalArgumentException();
1696 return sal_True;
1701 //-----------------------------------------------------------------------------
1703 Complex::Complex( const STRING& rStr ) THROWDEF_RTE_IAE
1705 if( !ParseString( rStr, *this ) )
1706 THROW_IAE;
1710 inline sal_Bool Complex::IsImagUnit( sal_Unicode c )
1712 return c == 'i' || c == 'j';
1715 sal_Bool Complex::ParseString( const STRING& rStr, Complex& rCompl )
1717 rCompl.c = '\0'; // do not force a symbol, if only real part present
1719 const sal_Unicode* pStr = rStr.getStr();
1721 if( IsImagUnit( *pStr ) && rStr.getLength() == 1)
1723 rCompl.r = 0.0;
1724 rCompl.i = 1.0;
1725 rCompl.c = *pStr;
1726 return sal_True;
1729 double f;
1731 if( !ParseDouble( pStr, f ) )
1732 return sal_False;
1734 switch( *pStr )
1736 case '-': // imag part follows
1737 case '+':
1739 double r = f;
1740 if( IsImagUnit( pStr[ 1 ] ) )
1742 rCompl.c = pStr[ 1 ];
1743 if( pStr[ 2 ] == 0 )
1745 rCompl.r = f;
1746 rCompl.i = ( *pStr == '+' )? 1.0 : -1.0;
1747 return sal_True;
1750 else if( ParseDouble( pStr, f ) && IsImagUnit( *pStr ) )
1752 rCompl.c = *pStr;
1753 pStr++;
1754 if( *pStr == 0 )
1756 rCompl.r = r;
1757 rCompl.i = f;
1758 return sal_True;
1762 break;
1763 case 'j':
1764 case 'i':
1765 rCompl.c = *pStr;
1766 pStr++;
1767 if( *pStr == 0 )
1769 rCompl.i = f;
1770 rCompl.r = 0.0;
1771 return sal_True;
1773 break;
1774 case 0: // only real-part
1775 rCompl.r = f;
1776 rCompl.i = 0.0;
1777 return sal_True;
1780 return sal_False;
1784 STRING Complex::GetString() const THROWDEF_RTE_IAE
1786 static const String aI( 'i' );
1787 static const String aJ( 'j' );
1788 static const String aPlus( '+' );
1789 static const String aMinus( '-' );
1791 CHK_FINITE(r);
1792 CHK_FINITE(i);
1793 STRING aRet;
1795 bool bHasImag = i != 0.0;
1796 bool bHasReal = !bHasImag || (r != 0.0);
1798 if( bHasReal )
1799 aRet = ::GetString( r );
1800 if( bHasImag )
1802 if( i == 1.0 )
1804 if( bHasReal )
1805 aRet += aPlus;
1807 else if( i == -1.0 )
1808 aRet += aMinus;
1809 else
1810 aRet += ::GetString( i, bHasReal );
1811 aRet += (c != 'j') ? aI : aJ;
1814 return aRet;
1818 double Complex::Arg( void ) const THROWDEF_RTE_IAE
1820 if( r == 0.0 && i == 0.0 )
1821 THROW_IAE;
1823 double phi = acos( r / Abs() );
1825 if( i < 0.0 )
1826 phi = -phi;
1828 return phi;
1832 void Complex::Power( double fPower ) THROWDEF_RTE_IAE
1834 if( r == 0.0 && i == 0.0 )
1836 if( fPower > 0 )
1838 r = i = 0.0;
1839 return;
1841 else
1842 THROW_IAE;
1845 double p, phi;
1847 p = Abs();
1849 phi = acos( r / p );
1850 if( i < 0.0 )
1851 phi = -phi;
1853 p = pow( p, fPower );
1854 phi *= fPower;
1856 r = cos( phi ) * p;
1857 i = sin( phi ) * p;
1861 void Complex::Sqrt( void )
1863 static const double fMultConst = 0.7071067811865475; // ...2440084436210485 = 1/sqrt(2)
1864 double p = Abs();
1865 double i_ = sqrt( p - r ) * fMultConst;
1867 r = sqrt( p + r ) * fMultConst;
1868 i = ( i < 0.0 )? -i_ : i_;
1872 void Complex::Sin( void ) THROWDEF_RTE_IAE
1874 if( !::rtl::math::isValidArcArg( r ) )
1875 THROW_IAE;
1877 if( i )
1879 double r_;
1881 r_ = sin( r ) * cosh( i );
1882 i = cos( r ) * sinh( i );
1883 r = r_;
1885 else
1886 r = sin( r );
1890 void Complex::Cos( void ) THROWDEF_RTE_IAE
1892 if( !::rtl::math::isValidArcArg( r ) )
1893 THROW_IAE;
1895 if( i )
1897 double r_;
1899 r_ = cos( r ) * cosh( i );
1900 i = -( sin( r ) * sinh( i ) );
1901 r = r_;
1903 else
1904 r = cos( r );
1908 void Complex::Div( const Complex& z ) THROWDEF_RTE_IAE
1910 if( z.r == 0 && z.i == 0 )
1911 THROW_IAE;
1913 double a1 = r;
1914 double a2 = z.r;
1915 double b1 = i;
1916 double b2 = z.i;
1918 double f = 1.0 / ( a2 * a2 + b2 * b2 );
1920 r = ( a1 * a2 + b1 * b2 ) * f;
1921 i = ( a2 * b1 - a1 * b2 ) * f;
1923 if( !c ) c = z.c;
1927 void Complex::Exp( void )
1929 double fE = exp( r );
1930 r = fE * cos( i );
1931 i = fE * sin( i );
1935 void Complex::Ln( void ) THROWDEF_RTE_IAE
1937 if( r == 0.0 && i == 0.0 )
1938 THROW_IAE;
1940 double fAbs = Abs();
1941 sal_Bool bNegi = i < 0.0;
1943 i = acos( r / fAbs );
1945 if( bNegi )
1946 i = -i;
1948 r = log( fAbs );
1952 void Complex::Log10( void ) THROWDEF_RTE_IAE
1954 Ln();
1955 Mult( 0.434294481903251828 ); // * log10( e )
1959 void Complex::Log2( void ) THROWDEF_RTE_IAE
1961 Ln();
1962 Mult( 1.442695040888963407 ); // * log2( e )
1966 void Complex::Tan(void) THROWDEF_RTE_IAE
1968 if ( i )
1970 if( !::rtl::math::isValidArcArg( 2.0 * r ) )
1971 THROW_IAE;
1972 double fScale =1.0 / ( cos( 2.0 * r ) + cosh( 2.0 * i ));
1973 r = sin( 2.0 * r ) * fScale;
1974 i = sinh( 2.0 * i ) * fScale;
1976 else
1978 if( !::rtl::math::isValidArcArg( r ) )
1979 THROW_IAE;
1980 r = tan( r );
1985 void Complex::Sec( void ) THROWDEF_RTE_IAE
1987 if( i )
1989 if( !::rtl::math::isValidArcArg( 2 * r ) )
1990 THROW_IAE;
1991 double fScale = 1.0 / (cosh( 2.0 * i) + cos ( 2.0 * r));
1992 double r_;
1993 r_ = 2.0 * cos( r ) * cosh( i ) * fScale;
1994 i = 2.0 * sin( r ) * sinh( i ) * fScale;
1995 r = r_;
1997 else
1999 if( !::rtl::math::isValidArcArg( r ) )
2000 THROW_IAE;
2001 r = 1.0 / cos( r );
2006 void Complex::Csc( void ) THROWDEF_RTE_IAE
2008 if( i )
2010 if( !::rtl::math::isValidArcArg( 2 * r ) )
2011 THROW_IAE;
2012 double fScale = 1.0 / (cosh( 2.0 * i) - cos ( 2.0 * r));
2013 double r_;
2014 r_ = 2.0 * sin( r ) * cosh( i ) * fScale;
2015 i = -2.0 * cos( r ) * sinh( i ) * fScale;
2016 r = r_;
2018 else
2020 if( !::rtl::math::isValidArcArg( r ) )
2021 THROW_IAE;
2022 r = 1.0 / sin( r );
2027 void Complex::Cot(void) THROWDEF_RTE_IAE
2029 if ( i )
2031 if( !::rtl::math::isValidArcArg( 2.0 * r ) )
2032 THROW_IAE;
2033 double fScale =1.0 / ( cosh( 2.0 * i ) - cos( 2.0 * r ) );
2034 r = sin( 2.0 * r ) * fScale;
2035 i = - ( sinh( 2.0 * i ) * fScale );
2037 else
2039 if( !::rtl::math::isValidArcArg( r ) )
2040 THROW_IAE;
2041 r = 1.0 / tan( r );
2046 void Complex::Sinh( void ) THROWDEF_RTE_IAE
2048 if( !::rtl::math::isValidArcArg( r ) )
2049 THROW_IAE;
2051 if( i )
2053 double r_;
2054 r_ = sinh( r ) * cos( i );
2055 i = cosh( r ) * sin( i );
2056 r = r_;
2058 else
2059 r = sinh( r );
2063 void Complex::Cosh( void ) THROWDEF_RTE_IAE
2065 if( !::rtl::math::isValidArcArg( r ) )
2066 THROW_IAE;
2068 if( i )
2070 double r_;
2071 r_ = cosh( r ) * cos( i );
2072 i = sinh( r ) * sin( i );
2073 r = r_;
2075 else
2076 r = cosh( r );
2080 void Complex::Sech(void) THROWDEF_RTE_IAE
2082 if ( i )
2084 if( !::rtl::math::isValidArcArg( 2.0 * r ) )
2085 THROW_IAE;
2086 double fScale =1.0 / ( cosh( 2.0 * r ) + cos( 2.0 * i ));
2087 double r_;
2088 r_ = 2.0 * cosh( 2.0 * r ) * cos( i ) * fScale;
2089 i = - (2.0 * sinh( 2.0 * r ) * sin( i ) * fScale );
2090 r = r_ ;
2092 else
2094 if( !::rtl::math::isValidArcArg( r ) )
2095 THROW_IAE;
2096 r = 1.0 / cosh( r );
2101 void Complex::Csch(void) THROWDEF_RTE_IAE
2103 if ( i )
2105 if( !::rtl::math::isValidArcArg( 2.0 * r ) )
2106 THROW_IAE;
2107 double fScale =1.0 / ( cosh( 2.0 * r ) - cos( 2.0 * i ));
2108 double r_;
2109 r_ = 2.0 * sinh( 2.0 * r ) * cos( i ) * fScale;
2110 i = - ( 2.0 * cosh( 2.0 * r ) * sin( i ) * fScale );
2111 r = r_ ;
2113 else
2115 if( !::rtl::math::isValidArcArg( r ) )
2116 THROW_IAE;
2117 r = 1.0 / sinh( r );
2122 ComplexList::~ComplexList()
2124 for( Complex* p = ( Complex* ) First() ; p ; p = ( Complex* ) Next() )
2125 delete p;
2129 void ComplexList::Append( const SEQSEQ( STRING )& r, ComplListAppendHandl eAH ) THROWDEF_RTE_IAE
2131 sal_Int32 n1, n2;
2132 sal_Int32 nE1 = r.getLength();
2133 sal_Int32 nE2;
2134 sal_Bool bEmpty0 = eAH == AH_EmpyAs0;
2135 sal_Bool bErrOnEmpty = eAH == AH_EmptyAsErr;
2137 for( n1 = 0 ; n1 < nE1 ; n1++ )
2139 const SEQ( STRING )& rList = r[ n1 ];
2140 nE2 = rList.getLength();
2142 for( n2 = 0 ; n2 < nE2 ; n2++ )
2144 const STRING& rStr = rList[ n2 ];
2146 if( !rStr.isEmpty() )
2147 Append( new Complex( rStr ) );
2148 else if( bEmpty0 )
2149 Append( new Complex( 0.0 ) );
2150 else if( bErrOnEmpty )
2151 THROW_IAE;
2157 void ComplexList::Append( const SEQ( ANY )& aMultPars, ComplListAppendHandl eAH ) THROWDEF_RTE_IAE
2159 sal_Int32 nEle = aMultPars.getLength();
2160 sal_Bool bEmpty0 = eAH == AH_EmpyAs0;
2161 sal_Bool bErrOnEmpty = eAH == AH_EmptyAsErr;
2163 for( sal_Int32 i = 0 ; i < nEle ; i++ )
2165 const ANY& r = aMultPars[ i ];
2166 switch( r.getValueTypeClass() )
2168 case uno::TypeClass_VOID: break;
2169 case uno::TypeClass_STRING:
2171 const STRING* pStr = ( const STRING* ) r.getValue();
2173 if( !pStr->isEmpty() )
2174 Append( new Complex( *( STRING* ) r.getValue() ) );
2175 else if( bEmpty0 )
2176 Append( new Complex( 0.0 ) );
2177 else if( bErrOnEmpty )
2178 THROW_IAE;
2180 break;
2181 case uno::TypeClass_DOUBLE:
2182 Append( new Complex( *( double* ) r.getValue(), 0.0 ) );
2183 break;
2184 case uno::TypeClass_SEQUENCE:
2186 SEQSEQ( ANY ) aValArr;
2187 if( r >>= aValArr )
2189 sal_Int32 nE = aValArr.getLength();
2190 const SEQ( ANY )* pArr = aValArr.getConstArray();
2191 for( sal_Int32 n = 0 ; n < nE ; n++ )
2192 Append( pArr[ n ], eAH );
2194 else
2195 THROW_IAE;
2197 break;
2198 default:
2199 THROW_IAE;
2207 ConvertData::ConvertData( const sal_Char p[], double fC, ConvertDataClass e, sal_Bool bPrefSupport ) : aName( p, strlen( p ), RTL_TEXTENCODING_MS_1252 )
2209 fConst = fC;
2210 eClass = e;
2211 bPrefixSupport = bPrefSupport;
2214 ConvertData::~ConvertData()
2219 sal_Int16 ConvertData::GetMatchingLevel( const STRING& rRef ) const
2221 STRING aStr = rRef;
2222 sal_Int32 nLen = rRef.getLength();
2223 sal_Int32 nIndex = rRef.lastIndexOf( '^' );
2224 if( nIndex > 0 && nIndex == ( nLen - 2 ) )
2226 const sal_Unicode* p = aStr.getStr();
2227 aStr = STRING( p, nLen - 2 );
2228 aStr += STRING( p[ nLen - 1 ] );
2230 if( aName.equals( aStr ) )
2231 return 0;
2232 else
2234 const sal_Unicode* p = aStr.getStr();
2236 nLen = aStr.getLength();
2237 bool bPref = IsPrefixSupport();
2238 bool bOneChar = (bPref && nLen > 1 && (aName == p + 1));
2239 if (bOneChar || (bPref && nLen > 2 && (aName == p + 2) &&
2240 *p == 'd' && *(p+1) == 'a'))
2242 sal_Int16 n;
2243 switch( *p )
2245 case 'y': n = -24; break; // yocto
2246 case 'z': n = -21; break; // zepto
2247 case 'a': n = -18; break;
2248 case 'f': n = -15; break;
2249 case 'p': n = -12; break;
2250 case 'n': n = -9; break;
2251 case 'u': n = -6; break;
2252 case 'm': n = -3; break;
2253 case 'c': n = -2; break;
2254 case 'd':
2256 if ( bOneChar )
2257 n = -1; // deci
2258 else
2259 n = 1; // deca
2261 break;
2262 case 'e': n = 1; break;
2263 case 'h': n = 2; break;
2264 case 'k': n = 3; break;
2265 case 'M': n = 6; break;
2266 case 'G': n = 9; break;
2267 case 'T': n = 12; break;
2268 case 'P': n = 15; break;
2269 case 'E': n = 18; break;
2270 case 'Z': n = 21; break; // zetta
2271 case 'Y': n = 24; break; // yotta
2272 default:
2273 n = INV_MATCHLEV;
2276 // We could weed some nonsense out, ODFF doesn't say so though.
2277 #if 0
2278 if (n < 0 && Class() == CDC_Information)
2279 n = INV_MATCHLEV; // milli-bits doesn't make sense
2280 #endif
2282 //! <HACK> "cm3" is not 10^-2 m^3 but 10^-6 m^3 !!! ------------------
2283 if( n != INV_MATCHLEV )
2285 sal_Unicode cLast = p[ aStr.getLength() - 1 ];
2286 if( cLast == '2' )
2287 n *= 2;
2288 else if( cLast == '3' )
2289 n *= 3;
2291 //! </HACK> -------------------------------------------------------------------
2293 return n;
2295 else if ( nLen > 2 && ( aName == p + 2 ) && ( Class() == CDC_Information ) )
2297 const sal_Unicode* pStr = aStr.getStr();
2298 if ( *(pStr + 1) != 'i')
2299 return INV_MATCHLEV;
2300 sal_Int16 n;
2301 switch( *pStr )
2303 case 'k': n = 10; break;
2304 case 'M': n = 20; break;
2305 case 'G': n = 30; break;
2306 case 'T': n = 40; break;
2307 case 'P': n = 50; break;
2308 case 'E': n = 60; break;
2309 case 'Z': n = 70; break;
2310 case 'Y': n = 80; break;
2311 default:
2312 n = INV_MATCHLEV;
2314 return n;
2316 else
2317 return INV_MATCHLEV;
2322 double ConvertData::Convert(
2323 double f, const ConvertData& r, sal_Int16 nLevFrom, sal_Int16 nLevTo ) const THROWDEF_RTE_IAE
2325 if( Class() != r.Class() )
2326 THROW_IAE;
2328 sal_Bool bBinFromLev = ( nLevFrom > 0 && ( nLevFrom % 10 ) == 0 );
2329 sal_Bool bBinToLev = ( nLevTo > 0 && ( nLevTo % 10 ) == 0 );
2331 if ( Class() == CDC_Information && ( bBinFromLev || bBinToLev ) )
2333 if ( bBinFromLev && bBinToLev )
2335 nLevFrom = sal::static_int_cast<sal_Int16>( nLevFrom - nLevTo );
2336 f *= r.fConst / fConst;
2337 if( nLevFrom )
2338 f *= pow( 2.0, nLevFrom );
2340 else if ( bBinFromLev )
2341 f *= ( r.fConst / fConst ) * ( pow( 2.0, nLevFrom ) / pow( 10.0, nLevTo ) );
2342 else
2343 f *= ( r.fConst / fConst ) * ( pow( 10.0, nLevFrom ) / pow( 2.0, nLevTo ) );
2344 return f;
2347 nLevFrom = sal::static_int_cast<sal_Int16>( nLevFrom - nLevTo ); // effective level
2349 f *= r.fConst / fConst;
2351 if( nLevFrom )
2352 f = ::rtl::math::pow10Exp( f, nLevFrom );
2354 return f;
2358 double ConvertData::ConvertToBase( double f, sal_Int16 n ) const
2360 return ::rtl::math::pow10Exp( f / fConst, n );
2364 double ConvertData::ConvertFromBase( double f, sal_Int16 n ) const
2366 return ::rtl::math::pow10Exp( f * fConst, -n );
2371 ConvertDataLinear::~ConvertDataLinear()
2375 double ConvertDataLinear::Convert(
2376 double f, const ConvertData& r, sal_Int16 nLevFrom, sal_Int16 nLevTo ) const THROWDEF_RTE_IAE
2378 if( Class() != r.Class() )
2379 THROW_IAE;
2380 return r.ConvertFromBase( ConvertToBase( f, nLevFrom ), nLevTo );
2384 double ConvertDataLinear::ConvertToBase( double f, sal_Int16 n ) const
2386 if( n )
2387 f = ::rtl::math::pow10Exp( f, n );
2389 f /= fConst;
2390 f -= fOffs;
2392 return f;
2396 double ConvertDataLinear::ConvertFromBase( double f, sal_Int16 n ) const
2398 f += fOffs;
2399 f *= fConst;
2401 if( n )
2402 f = ::rtl::math::pow10Exp( f, -n );
2404 return f;
2410 ConvertDataList::ConvertDataList( void )
2412 #define NEWD(str,unit,cl) Append(new ConvertData(str,unit,cl))
2413 #define NEWDP(str,unit,cl) Append(new ConvertData(str,unit,cl,sal_True))
2414 #define NEWL(str,unit,offs,cl) Append(new ConvertDataLinear(str,unit,offs,cl))
2415 #define NEWLP(str,unit,offs,cl) Append(new ConvertDataLinear(str,unit,offs,cl,sal_True))
2417 // *** are extra and not standard Excel Analysis Addin!
2419 // MASS: 1 Gram is...
2420 NEWDP( "g", 1.0000000000000000E00, CDC_Mass ); // Gram
2421 NEWD( "sg", 6.8522050005347800E-05, CDC_Mass ); // Pieces
2422 NEWD( "lbm", 2.2046229146913400E-03, CDC_Mass ); // Pound (commercial weight)
2423 NEWDP( "u", 6.0221370000000000E23, CDC_Mass ); // U (atomic mass)
2424 NEWD( "ozm", 3.5273971800362700E-02, CDC_Mass ); // Ounce (commercial weight)
2425 NEWD( "stone", 1.574730e-04, CDC_Mass ); // *** Stone
2426 NEWD( "ton", 1.102311e-06, CDC_Mass ); // *** Ton
2427 NEWD( "grain", 1.543236E01, CDC_Mass ); // *** Grain
2428 NEWD( "pweight", 7.054792E-01, CDC_Mass ); // *** Pennyweight
2429 NEWD( "hweight", 1.968413E-05, CDC_Mass ); // *** Hundredweight
2430 NEWD( "shweight", 2.204623E-05, CDC_Mass ); // *** Shorthundredweight
2431 NEWD( "brton", 9.842065E-07, CDC_Mass ); // *** Gross Registered Ton
2432 NEWD( "cwt", 2.2046226218487758E-05, CDC_Mass ); // U.S. (short) hundredweight
2433 NEWD( "shweight", 2.2046226218487758E-05, CDC_Mass ); // U.S. (short) hundredweight also
2434 NEWD( "uk_cwt", 1.9684130552221213E-05, CDC_Mass ); // Imperial hundredweight
2435 NEWD( "lcwt", 1.9684130552221213E-05, CDC_Mass ); // Imperial hundredweight also
2436 NEWD( "hweight", 1.9684130552221213E-05, CDC_Mass ); // Imperial hundredweight also
2437 NEWD( "uk_ton", 9.8420652761106063E-07, CDC_Mass ); // Imperial ton
2438 NEWD( "LTON", 9.8420652761106063E-07, CDC_Mass ); // Imperial ton also
2440 // LENGTH: 1 Meter is...
2441 NEWDP( "m", 1.0000000000000000E00, CDC_Length ); // Meter
2442 NEWD( "mi", 6.2137119223733397E-04, CDC_Length ); // Britsh Mile 6,21371192237333969617434184363e-4
2443 NEWD( "Nmi", 5.3995680345572354E-04, CDC_Length ); // Nautical Mile 5,39956803455723542116630669546e-4
2444 NEWD( "in", 3.9370078740157480E01, CDC_Length ); // Inch 39,37007874015748031496062992126
2445 NEWD( "ft", 3.2808398950131234E00, CDC_Length ); // Foot 3,2808398950131233595800524934383
2446 NEWD( "yd", 1.0936132983377078E00, CDC_Length ); // Yard 1,0936132983377077865266841644794
2447 NEWDP( "ang", 1.0000000000000000E10, CDC_Length ); // Angstroem
2448 NEWD( "Pica", 2.8346456692913386E03, CDC_Length ); // Pica (1/72 Inch) 2834,6456692913385826771653543307
2449 NEWD( "ell", 8.748906E-01, CDC_Length ); // *** Ell
2450 NEWDP( "parsec", 3.240779E-17, CDC_Length ); // *** Parsec
2451 NEWDP( "pc", 3.240779E-17, CDC_Length ); // *** Parsec also
2452 NEWDP( "lightyear", 1.0570234557732930E-16, CDC_Length ); // *** Light Year
2453 NEWDP( "ly", 1.0570234557732930E-16, CDC_Length ); // *** Light Year also
2454 NEWD( "survey_mi", 6.2136994949494949E-04, CDC_Length ); // U.S. survey mile
2456 // TIME: 1 Second is...
2457 NEWD( "yr", 3.1688087814028950E-08, CDC_Time ); // Year
2458 NEWD( "day", 1.1574074074074074E-05, CDC_Time ); // Day
2459 NEWD( "d", 1.1574074074074074E-05, CDC_Time ); // Day also
2460 NEWD( "hr", 2.7777777777777778E-04, CDC_Time ); // Hour
2461 NEWD( "mn", 1.6666666666666667E-02, CDC_Time ); // Minute
2462 NEWD( "min", 1.6666666666666667E-02, CDC_Time ); // Minute also
2463 NEWDP( "sec", 1.0000000000000000E00, CDC_Time ); // Second
2464 NEWDP( "s", 1.0000000000000000E00, CDC_Time ); // Second also
2466 // PRESSURE: 1 Pascal is...
2467 NEWDP( "Pa", 1.0000000000000000E00, CDC_Pressure ); // Pascal
2468 NEWDP( "atm", 9.8692329999819300E-06, CDC_Pressure ); // Atmosphere
2469 NEWDP( "at", 9.8692329999819300E-06, CDC_Pressure ); // Atmosphere also
2470 NEWDP( "mmHg", 7.5006170799862700E-03, CDC_Pressure ); // mm Hg (Mercury)
2471 NEWD( "Torr", 7.5006380000000000E-03, CDC_Pressure ); // *** Torr
2472 NEWD( "psi", 1.4503770000000000E-04, CDC_Pressure ); // *** Psi
2474 // FORCE: 1 Newton is...
2475 NEWDP( "N", 1.0000000000000000E00, CDC_Force ); // Newton
2476 NEWDP( "dyn", 1.0000000000000000E05, CDC_Force ); // Dyn
2477 NEWDP( "dy", 1.0000000000000000E05, CDC_Force ); // Dyn also
2478 NEWD( "lbf", 2.24808923655339E-01, CDC_Force ); // Pound-Force
2479 NEWDP( "pond", 1.019716E02, CDC_Force ); // *** Pond
2481 // ENERGY: 1 Joule is...
2482 NEWDP( "J", 1.0000000000000000E00, CDC_Energy ); // Joule
2483 NEWDP( "e", 1.0000000000000000E07, CDC_Energy ); // Erg -> http://www.chemie.fu-berlin.de/chemistry/general/si.html
2484 NEWDP( "c", 2.3900624947346700E-01, CDC_Energy ); // Thermodynamical Calorie
2485 NEWDP( "cal", 2.3884619064201700E-01, CDC_Energy ); // Calorie
2486 NEWDP( "eV", 6.2414570000000000E18, CDC_Energy ); // Electronvolt
2487 NEWDP( "ev", 6.2414570000000000E18, CDC_Energy ); // Electronvolt also
2488 NEWD( "HPh", 3.7250611111111111E-07, CDC_Energy ); // Horsepower Hours
2489 NEWD( "hh", 3.7250611111111111E-07, CDC_Energy ); // Horsepower Hours also
2490 NEWDP( "Wh", 2.7777777777777778E-04, CDC_Energy ); // Watt Hours
2491 NEWDP( "wh", 2.7777777777777778E-04, CDC_Energy ); // Watt Hours also
2492 NEWD( "flb", 2.37304222192651E01, CDC_Energy ); // Foot Pound
2493 NEWD( "BTU", 9.4781506734901500E-04, CDC_Energy ); // British Thermal Unit
2494 NEWD( "btu", 9.4781506734901500E-04, CDC_Energy ); // British Thermal Unit also
2496 // POWER: 1 Watt is...
2497 NEWDP( "W", 1.0000000000000000E00, CDC_Power ); // Watt
2498 NEWDP( "w", 1.0000000000000000E00, CDC_Power ); // Watt also
2499 NEWD( "HP", 1.341022E-03, CDC_Power ); // Horsepower
2500 NEWD( "h", 1.341022E-03, CDC_Power ); // Horsepower also
2501 NEWD( "PS", 1.359622E-03, CDC_Power ); // *** German Pferdestaerke
2503 // MAGNETISM: 1 Tesla is...
2504 NEWDP( "T", 1.0000000000000000E00, CDC_Magnetism ); // Tesla
2505 NEWDP( "ga", 1.0000000000000000E04, CDC_Magnetism ); // Gauss
2507 // TEMERATURE: 1 Kelvin is...
2508 NEWL( "C", 1.0000000000000000E00, -2.7315000000000000E02, CDC_Temperature ); // Celsius
2509 NEWL( "cel", 1.0000000000000000E00, -2.7315000000000000E02, CDC_Temperature ); // Celsius also
2510 NEWL( "F", 1.8000000000000000E00, -2.5537222222222222E02, CDC_Temperature ); // Fahrenheit
2511 NEWL( "fah", 1.8000000000000000E00, -2.5537222222222222E02, CDC_Temperature ); // Fahrenheit also
2512 NEWLP( "K", 1.0000000000000000E00, +0.0000000000000000E00, CDC_Temperature ); // Kelvin
2513 NEWLP( "kel", 1.0000000000000000E00, +0.0000000000000000E00, CDC_Temperature ); // Kelvin also
2514 NEWL( "Reau", 8.0000000000000000E-01, -2.7315000000000000E02, CDC_Temperature ); // *** Reaumur
2515 NEWL( "Rank", 1.8000000000000000E00, +0.0000000000000000E00, CDC_Temperature ); // *** Rankine
2517 // VOLUMNE: 1 Liter is...
2518 NEWD( "tsp", 2.0288413621105798E02, CDC_Volume ); // US teaspoon 1/768 gallon
2519 NEWD( "tbs", 6.7628045403685994E01, CDC_Volume ); // US tablespoon 1/256 gallon
2520 NEWD( "oz", 3.3814022701842997E01, CDC_Volume ); // Ounce Liquid 1/128 gallon
2521 NEWD( "cup", 4.2267528377303746E00, CDC_Volume ); // Cup 1/16 gallon
2522 NEWD( "pt", 2.1133764188651873E00, CDC_Volume ); // US Pint 1/8 gallon
2523 NEWD( "us_pt", 2.1133764188651873E00, CDC_Volume ); // US Pint also
2524 NEWD( "uk_pt", 1.7597539863927023E00, CDC_Volume ); // UK Pint 1/8 imperial gallon
2525 NEWD( "qt", 1.0566882094325937E00, CDC_Volume ); // Quart 1/4 gallon
2526 NEWD( "gal", 2.6417205235814842E-01, CDC_Volume ); // Gallon 1/3.785411784
2527 NEWDP( "l", 1.0000000000000000E00, CDC_Volume ); // Liter
2528 NEWDP( "L", 1.0000000000000000E00, CDC_Volume ); // Liter also
2529 NEWDP( "lt", 1.0000000000000000E00, CDC_Volume ); // Liter also
2530 NEWDP( "m3", 1.0000000000000000E-03, CDC_Volume ); // *** Cubic Meter
2531 NEWD( "mi3", 2.3991275857892772E-13, CDC_Volume ); // *** Cubic Britsh Mile
2532 NEWD( "Nmi3", 1.5742621468581148E-13, CDC_Volume ); // *** Cubic Nautical Mile
2533 NEWD( "in3", 6.1023744094732284E01, CDC_Volume ); // *** Cubic Inch
2534 NEWD( "ft3", 3.5314666721488590E-02, CDC_Volume ); // *** Cubic Foot
2535 NEWD( "yd3", 1.3079506193143922E-03, CDC_Volume ); // *** Cubic Yard
2536 NEWDP( "ang3", 1.0000000000000000E27, CDC_Volume ); // *** Cubic Angstroem
2537 NEWD( "Pica3", 2.2776990435870636E07, CDC_Volume ); // *** Cubic Pica
2538 NEWD( "barrel", 6.2898107704321051E-03, CDC_Volume ); // *** Barrel (=42gal)
2539 NEWD( "bushel", 2.837759E-02, CDC_Volume ); // *** Bushel
2540 NEWD( "regton", 3.531467E-04, CDC_Volume ); // *** Register ton
2541 NEWD( "GRT", 3.531467E-04, CDC_Volume ); // *** Register ton also
2542 NEWD( "Schooner", 2.3529411764705882E00, CDC_Volume ); // *** austr. Schooner
2543 NEWD( "Middy", 3.5087719298245614E00, CDC_Volume ); // *** austr. Middy
2544 NEWD( "Glass", 5.0000000000000000E00, CDC_Volume ); // *** austr. Glass
2545 NEWD( "Sixpack", 0.5, CDC_Volume ); // ***
2546 NEWD( "Humpen", 2.0, CDC_Volume ); // ***
2547 NEWD( "ly3", 1.1810108125623799E-51, CDC_Volume ); // *** Cubic light-year
2548 NEWD( "MTON", 1.4125866688595436E00, CDC_Volume ); // *** Measurement ton
2549 NEWD( "tspm", 5.0000000000000000E02, CDC_Volume ); // *** Modern teaspoon
2550 NEWD( "uk_gal", 2.1996924829908779E-01, CDC_Volume ); // U.K. / Imperial gallon 1/4.54609
2551 NEWD( "uk_qt", 8.7987699319635115E-01, CDC_Volume ); // U.K. / Imperial quart 1/4 imperial gallon
2553 // 1 Square Meter is...
2554 NEWDP( "m2", 1.0000000000000000E00, CDC_Area ); // *** Square Meter
2555 NEWD( "mi2", 3.8610215854244585E-07, CDC_Area ); // *** Square Britsh Mile
2556 NEWD( "Nmi2", 2.9155334959812286E-07, CDC_Area ); // *** Square Nautical Mile
2557 NEWD( "in2", 1.5500031000062000E03, CDC_Area ); // *** Square Inch
2558 NEWD( "ft2", 1.0763910416709722E01, CDC_Area ); // *** Square Foot
2559 NEWD( "yd2", 1.1959900463010803E00, CDC_Area ); // *** Square Yard
2560 NEWDP( "ang2", 1.0000000000000000E20, CDC_Area ); // *** Square Angstroem
2561 NEWD( "Pica2", 8.0352160704321409E06, CDC_Area ); // *** Square Pica
2562 NEWD( "Morgen", 4.0000000000000000E-04, CDC_Area ); // *** Morgen
2563 NEWDP( "ar", 1.000000E-02, CDC_Area ); // *** Ar
2564 NEWD( "acre", 2.471053815E-04, CDC_Area ); // *** Acre
2565 NEWD( "uk_acre", 2.4710538146716534E-04, CDC_Area ); // *** International acre
2566 NEWD( "us_acre", 2.4710439304662790E-04, CDC_Area ); // *** U.S. survey/statute acre
2567 NEWD( "ly2", 1.1172985860549147E-32, CDC_Area ); // *** Square Light-year
2568 NEWD( "ha", 1.000000E-04, CDC_Area ); // *** Hectare
2569 NEWD( "Quadratlatschen",5.6689342403628117914,CDC_Area ); // ***
2571 // SPEED: 1 Meter per Second is...
2572 NEWDP( "m/s", 1.0000000000000000E00, CDC_Speed ); // *** Meters per Second
2573 NEWDP( "m/sec", 1.0000000000000000E00, CDC_Speed ); // *** Meters per Second also
2574 NEWDP( "m/h", 3.6000000000000000E03, CDC_Speed ); // *** Meters per Hour
2575 NEWDP( "m/hr", 3.6000000000000000E03, CDC_Speed ); // *** Meters per Hour also
2576 NEWD( "mph", 2.2369362920544023E00, CDC_Speed ); // *** Britsh Miles per Hour
2577 NEWD( "kn", 1.9438444924406048E00, CDC_Speed ); // *** Knot = Nautical Miles per Hour
2578 NEWD( "admkn", 1.9438446603753486E00, CDC_Speed ); // *** Admiralty Knot
2579 NEWD( "wahnsinnige Geschwindigkeit", 2.0494886343432328E-14, CDC_Speed ); // ***
2580 NEWD( "ludicrous speed", 2.0494886343432328E-14, CDC_Speed ); // ***
2581 NEWD( "laecherliche Geschwindigkeit", 4.0156958471424288E-06, CDC_Speed); // ***
2582 NEWD( "ridiculous speed", 4.0156958471424288E-06, CDC_Speed); // ***
2584 // INFORMATION: 1 Bit is...
2585 NEWDP( "bit", 1.00E00, CDC_Information); // *** Bit
2586 NEWDP( "byte", 1.25E-01, CDC_Information); // *** Byte
2590 ConvertDataList::~ConvertDataList()
2592 for( ConvertData* p = First() ; p ; p = Next() )
2593 delete p;
2597 double ConvertDataList::Convert( double fVal, const STRING& rFrom, const STRING& rTo ) THROWDEF_RTE_IAE
2599 ConvertData* pFrom = NULL;
2600 ConvertData* pTo = NULL;
2601 sal_Bool bSearchFrom = sal_True;
2602 sal_Bool bSearchTo = sal_True;
2603 sal_Int16 nLevelFrom = 0;
2604 sal_Int16 nLevelTo = 0;
2606 ConvertData* p = First();
2607 while( p && ( bSearchFrom || bSearchTo ) )
2609 if( bSearchFrom )
2611 sal_Int16 n = p->GetMatchingLevel( rFrom );
2612 if( n != INV_MATCHLEV )
2614 if( n )
2615 { // only first match for partial equality rulz a little bit more
2616 pFrom = p;
2617 nLevelFrom = n;
2619 else
2620 { // ... but exact match rulz most
2621 pFrom = p;
2622 bSearchFrom = sal_False;
2623 nLevelFrom = n;
2628 if( bSearchTo )
2630 sal_Int16 n = p->GetMatchingLevel( rTo );
2631 if( n != INV_MATCHLEV )
2633 if( n )
2634 { // only first match for partial equality rulz a little bit more
2635 pTo = p;
2636 nLevelTo = n;
2638 else
2639 { // ... but exact match rulz most
2640 pTo = p;
2641 bSearchTo = sal_False;
2642 nLevelTo = n;
2647 p = Next();
2650 if( pFrom && pTo )
2651 return pFrom->Convert( fVal, *pTo, nLevelFrom, nLevelTo );
2652 else
2653 THROW_IAE;
2658 //-----------------------------------------------------------------------------
2660 ScaDate::ScaDate() :
2661 nOrigDay( 1 ),
2662 nDay( 1 ),
2663 nMonth( 1 ),
2664 nYear( 1900 ),
2665 bLastDayMode( sal_True ),
2666 bLastDay( sal_False ),
2667 b30Days( sal_False ),
2668 bUSMode( sal_False )
2672 ScaDate::ScaDate( sal_Int32 nNullDate, sal_Int32 nDate, sal_Int32 nBase )
2674 DaysToDate( nNullDate + nDate, nOrigDay, nMonth, nYear );
2675 bLastDayMode = (nBase != 5);
2676 bLastDay = (nOrigDay >= ::DaysInMonth( nMonth, nYear ));
2677 b30Days = (nBase == 0) || (nBase == 4);
2678 bUSMode = (nBase == 0);
2679 setDay();
2682 ScaDate::ScaDate( const ScaDate& rCopy ) :
2683 nOrigDay( rCopy.nOrigDay ),
2684 nDay( rCopy.nDay ),
2685 nMonth( rCopy.nMonth ),
2686 nYear( rCopy.nYear ),
2687 bLastDayMode( rCopy.bLastDayMode ),
2688 bLastDay( rCopy.bLastDay ),
2689 b30Days( rCopy.b30Days ),
2690 bUSMode( rCopy.bUSMode )
2694 ScaDate& ScaDate::operator=( const ScaDate& rCopy )
2696 if( this != &rCopy )
2698 nOrigDay = rCopy.nOrigDay;
2699 nDay = rCopy.nDay;
2700 nMonth = rCopy.nMonth;
2701 nYear = rCopy.nYear;
2702 bLastDayMode = rCopy.bLastDayMode;
2703 bLastDay = rCopy.bLastDay;
2704 b30Days = rCopy.b30Days;
2705 bUSMode = rCopy.bUSMode;
2707 return *this;
2710 void ScaDate::setDay()
2712 if( b30Days )
2714 // 30-days-mode: set nDay to 30 if original was last day in month
2715 nDay = Min( nOrigDay, static_cast< sal_uInt16 >( 30 ) );
2716 if( bLastDay || (nDay >= ::DaysInMonth( nMonth, nYear )) )
2717 nDay = 30;
2719 else
2721 // set nDay to last day in this month if original was last day
2722 sal_uInt16 nLastDay = ::DaysInMonth( nMonth, nYear );
2723 nDay = bLastDay ? nLastDay : Min( nOrigDay, nLastDay );
2727 sal_Int32 ScaDate::getDaysInMonthRange( sal_uInt16 nFrom, sal_uInt16 nTo ) const
2729 if( nFrom > nTo )
2730 return 0;
2732 sal_Int32 nRet = 0;
2733 if( b30Days )
2734 nRet = (nTo - nFrom + 1) * 30;
2735 else
2737 for( sal_uInt16 nMonthIx = nFrom; nMonthIx <= nTo; ++nMonthIx )
2738 nRet += getDaysInMonth( nMonthIx );
2740 return nRet;
2743 sal_Int32 ScaDate::getDaysInYearRange( sal_uInt16 nFrom, sal_uInt16 nTo ) const
2745 if( nFrom > nTo )
2746 return 0;
2748 return b30Days ? ((nTo - nFrom + 1) * 360) : ::GetDaysInYears( nFrom, nTo );
2751 void ScaDate::doAddYears( sal_Int32 nYearCount ) throw( lang::IllegalArgumentException )
2753 sal_Int32 nNewYear = nYearCount + nYear;
2754 if( (nNewYear < 0) || (nNewYear > 0x7FFF) )
2755 throw lang::IllegalArgumentException();
2756 nYear = static_cast< sal_uInt16 >( nNewYear );
2759 void ScaDate::addMonths( sal_Int32 nMonthCount ) throw( lang::IllegalArgumentException )
2761 sal_Int32 nNewMonth = nMonthCount + nMonth;
2762 if( nNewMonth > 12 )
2764 --nNewMonth;
2765 doAddYears( nNewMonth / 12 );
2766 nMonth = static_cast< sal_uInt16 >( nNewMonth % 12 ) + 1;
2768 else if( nNewMonth < 1 )
2770 doAddYears( nNewMonth / 12 - 1 );
2771 nMonth = static_cast< sal_uInt16 >( nNewMonth % 12 + 12 );
2773 else
2774 nMonth = static_cast< sal_uInt16 >( nNewMonth );
2775 setDay();
2778 sal_Int32 ScaDate::getDate( sal_Int32 nNullDate ) const
2780 sal_uInt16 nLastDay = ::DaysInMonth( nMonth, nYear );
2781 sal_uInt16 nRealDay = (bLastDayMode && bLastDay) ? nLastDay : Min( nLastDay, nOrigDay );
2782 return ::DateToDays( nRealDay, nMonth, nYear ) - nNullDate;
2785 sal_Int32 ScaDate::getDiff( const ScaDate& rFrom, const ScaDate& rTo ) throw( lang::IllegalArgumentException )
2787 if( rFrom > rTo )
2788 return getDiff( rTo, rFrom );
2790 sal_Int32 nDiff = 0;
2791 ScaDate aFrom( rFrom );
2792 ScaDate aTo( rTo );
2794 if( rTo.b30Days )
2796 // corrections for base 0 (US NASD)
2797 if( rTo.bUSMode )
2799 if( ((rFrom.nMonth == 2) || (rFrom.nDay < 30)) && (aTo.nOrigDay == 31) )
2800 aTo.nDay = 31;
2801 else if( (aTo.nMonth == 2) && aTo.bLastDay )
2802 aTo.nDay = ::DaysInMonth( 2, aTo.nYear );
2804 // corrections for base 4 (Europe)
2805 else
2807 if( (aFrom.nMonth == 2) && (aFrom.nDay == 30) )
2808 aFrom.nDay = ::DaysInMonth( 2, aFrom.nYear );
2809 if( (aTo.nMonth == 2) && (aTo.nDay == 30) )
2810 aTo.nDay = ::DaysInMonth( 2, aTo.nYear );
2814 if( (aFrom.nYear < aTo.nYear) || ((aFrom.nYear == aTo.nYear) && (aFrom.nMonth < aTo.nMonth)) )
2816 // move aFrom to 1st day of next month
2817 nDiff = aFrom.getDaysInMonth() - aFrom.nDay + 1;
2818 aFrom.nOrigDay = aFrom.nDay = 1;
2819 aFrom.bLastDay = sal_False;
2820 aFrom.addMonths( 1 );
2822 if( aFrom.nYear < aTo.nYear )
2824 // move aFrom to 1st day of next year
2825 nDiff += aFrom.getDaysInMonthRange( aFrom.nMonth, 12 );
2826 aFrom.addMonths( 13 - aFrom.nMonth );
2828 // move aFrom to 1st day of this year
2829 nDiff += aFrom.getDaysInYearRange( aFrom.nYear, aTo.nYear - 1 );
2830 aFrom.addYears( aTo.nYear - aFrom.nYear );
2833 // move aFrom to 1st day of this month
2834 nDiff += aFrom.getDaysInMonthRange( aFrom.nMonth, aTo.nMonth - 1 );
2835 aFrom.addMonths( aTo.nMonth - aFrom.nMonth );
2837 // finally add remaining days in this month
2838 nDiff += aTo.nDay - aFrom.nDay;
2839 return nDiff > 0 ? nDiff : 0;
2842 sal_Bool ScaDate::operator<( const ScaDate& rCmp ) const
2844 if( nYear != rCmp.nYear )
2845 return nYear < rCmp.nYear;
2846 if( nMonth != rCmp.nMonth )
2847 return nMonth < rCmp.nMonth;
2848 if( nDay != rCmp.nDay )
2849 return nDay < rCmp.nDay;
2850 if( bLastDay || rCmp.bLastDay )
2851 return !bLastDay && rCmp.bLastDay;
2852 return nOrigDay < rCmp.nOrigDay;
2857 //-----------------------------------------------------------------------------
2859 ScaAnyConverter::ScaAnyConverter( const uno::Reference< lang::XMultiServiceFactory >& xServiceFact ) :
2860 bHasValidFormat( sal_False )
2862 if( xServiceFact.is() )
2864 uno::Reference< uno::XInterface > xInstance = xServiceFact->createInstance(
2865 OUString(RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.util.NumberFormatter" )) );
2866 xFormatter = uno::Reference< util::XNumberFormatter >( xInstance, uno::UNO_QUERY );
2870 ScaAnyConverter::~ScaAnyConverter()
2874 void ScaAnyConverter::init( const uno::Reference< beans::XPropertySet >& xPropSet ) throw( uno::RuntimeException )
2876 // try to get default number format
2877 bHasValidFormat = sal_False;
2878 if( xFormatter.is() )
2880 // get XFormatsSupplier from outer XPropertySet
2881 uno::Reference< util::XNumberFormatsSupplier > xFormatsSupp( xPropSet, uno::UNO_QUERY );
2882 if( xFormatsSupp.is() )
2884 // get XNumberFormatTypes from XNumberFormatsSupplier to get standard index
2885 uno::Reference< util::XNumberFormats > xFormats( xFormatsSupp->getNumberFormats() );
2886 uno::Reference< util::XNumberFormatTypes > xFormatTypes( xFormats, uno::UNO_QUERY );
2887 if( xFormatTypes.is() )
2889 lang::Locale eLocale;
2890 nDefaultFormat = xFormatTypes->getStandardIndex( eLocale );
2891 xFormatter->attachNumberFormatsSupplier( xFormatsSupp );
2892 bHasValidFormat = sal_True;
2898 double ScaAnyConverter::convertToDouble( const OUString& rString ) const throw( lang::IllegalArgumentException )
2900 double fValue = 0.0;
2901 if( bHasValidFormat )
2905 fValue = xFormatter->convertStringToNumber( nDefaultFormat, rString );
2907 catch( uno::Exception& )
2909 throw lang::IllegalArgumentException();
2912 else
2914 rtl_math_ConversionStatus eStatus;
2915 sal_Int32 nEnd;
2916 fValue = ::rtl::math::stringToDouble( rString, '.', ',', &eStatus, &nEnd );
2917 if( (eStatus != rtl_math_ConversionStatus_Ok) || (nEnd < rString.getLength()) )
2918 throw lang::IllegalArgumentException();
2920 return fValue;
2923 sal_Bool ScaAnyConverter::getDouble(
2924 double& rfResult,
2925 const uno::Any& rAny ) const throw( lang::IllegalArgumentException )
2927 rfResult = 0.0;
2928 sal_Bool bContainsVal = sal_True;
2929 switch( rAny.getValueTypeClass() )
2931 case uno::TypeClass_VOID:
2932 bContainsVal = sal_False;
2933 break;
2934 case uno::TypeClass_DOUBLE:
2935 rAny >>= rfResult;
2936 break;
2937 case uno::TypeClass_STRING:
2939 const OUString* pString = static_cast< const OUString* >( rAny.getValue() );
2940 if( !pString->isEmpty() )
2941 rfResult = convertToDouble( *pString );
2942 else
2943 bContainsVal = sal_False;
2945 break;
2946 default:
2947 throw lang::IllegalArgumentException();
2949 return bContainsVal;
2952 sal_Bool ScaAnyConverter::getDouble(
2953 double& rfResult,
2954 const uno::Reference< beans::XPropertySet >& xPropSet,
2955 const uno::Any& rAny ) throw( uno::RuntimeException, lang::IllegalArgumentException )
2957 init( xPropSet );
2958 return getDouble( rfResult, rAny );
2961 double ScaAnyConverter::getDouble(
2962 const uno::Reference< beans::XPropertySet >& xPropSet,
2963 const uno::Any& rAny,
2964 double fDefault ) throw( uno::RuntimeException, lang::IllegalArgumentException )
2966 double fResult;
2967 if( !getDouble( fResult, xPropSet, rAny ) )
2968 fResult = fDefault;
2969 return fResult;
2972 sal_Bool ScaAnyConverter::getInt32(
2973 sal_Int32& rnResult,
2974 const uno::Reference< beans::XPropertySet >& xPropSet,
2975 const uno::Any& rAny ) throw( uno::RuntimeException, lang::IllegalArgumentException )
2977 double fResult;
2978 sal_Bool bContainsVal = getDouble( fResult, xPropSet, rAny );
2979 if( (fResult <= -2147483649.0) || (fResult >= 2147483648.0) )
2980 throw lang::IllegalArgumentException();
2982 rnResult = static_cast< sal_Int32 >( fResult );
2983 return bContainsVal;
2986 sal_Int32 ScaAnyConverter::getInt32(
2987 const uno::Reference< beans::XPropertySet >& xPropSet,
2988 const uno::Any& rAny,
2989 sal_Int32 nDefault ) throw( uno::RuntimeException, lang::IllegalArgumentException )
2991 sal_Int32 nResult;
2992 if( !getInt32( nResult, xPropSet, rAny ) )
2993 nResult = nDefault;
2994 return nResult;
2999 //-----------------------------------------------------------------------------
3002 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */