update dev300-m58
[ooovba.git] / scaddins / source / analysis / analysishelper.cxx
blobb6f01b97bc56da4421bd7a43e74538b82d19feba
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: analysishelper.cxx,v $
10 * $Revision: 1.58 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 #include <com/sun/star/util/XNumberFormatTypes.hpp>
33 #include <string.h>
34 #include <stdio.h>
35 #include <tools/resary.hxx>
36 #include <rtl/math.hxx>
37 #include "analysishelper.hxx"
38 #include "analysis.hrc"
40 using namespace ::rtl;
41 using namespace ::com::sun::star;
45 #define UNIQUE sal_False // function name does not exist in Calc
46 #define DOUBLE sal_True // function name exists in Calc
48 #define STDPAR sal_False // all parameters are described
49 #define INTPAR sal_True // first parameter is internal
51 #define FUNCDATA( FUNCNAME, DBL, OPT, NUMOFPAR, CAT ) \
52 { "get" #FUNCNAME, ANALYSIS_FUNCNAME_##FUNCNAME, ANALYSIS_##FUNCNAME, DBL, OPT, ANALYSIS_DEFFUNCNAME_##FUNCNAME, NUMOFPAR, CAT }
54 const FuncDataBase pFuncDatas[] =
56 // UNIQUE or INTPAR or
57 // function name DOUBLE STDPAR # of param category
58 FUNCDATA( Workday, UNIQUE, INTPAR, 3, FDCat_DateTime ),
59 FUNCDATA( Yearfrac, UNIQUE, INTPAR, 3, FDCat_DateTime ),
60 FUNCDATA( Edate, UNIQUE, INTPAR, 2, FDCat_DateTime ),
61 FUNCDATA( Weeknum, DOUBLE, INTPAR, 2, FDCat_DateTime ),
62 FUNCDATA( Eomonth, UNIQUE, INTPAR, 2, FDCat_DateTime ),
63 FUNCDATA( Networkdays, UNIQUE, INTPAR, 3, FDCat_DateTime ),
64 FUNCDATA( Iseven, DOUBLE, STDPAR, 1, FDCat_Inf ),
65 FUNCDATA( Isodd, DOUBLE, STDPAR, 1, FDCat_Inf ),
66 FUNCDATA( Multinomial, UNIQUE, STDPAR, 1, FDCat_Math ),
67 FUNCDATA( Seriessum, UNIQUE, STDPAR, 4, FDCat_Math ),
68 FUNCDATA( Quotient, UNIQUE, STDPAR, 2, FDCat_Math ),
69 FUNCDATA( Mround, UNIQUE, STDPAR, 2, FDCat_Math ),
70 FUNCDATA( Sqrtpi, UNIQUE, STDPAR, 1, FDCat_Math ),
71 FUNCDATA( Randbetween, UNIQUE, STDPAR, 2, FDCat_Math ),
72 FUNCDATA( Gcd, DOUBLE, INTPAR, 1, FDCat_Math ),
73 FUNCDATA( Lcm, DOUBLE, INTPAR, 1, FDCat_Math ),
74 FUNCDATA( Besseli, UNIQUE, STDPAR, 2, FDCat_Tech ),
75 FUNCDATA( Besselj, UNIQUE, STDPAR, 2, FDCat_Tech ),
76 FUNCDATA( Besselk, UNIQUE, STDPAR, 2, FDCat_Tech ),
77 FUNCDATA( Bessely, UNIQUE, STDPAR, 2, FDCat_Tech ),
78 FUNCDATA( Bin2Oct, UNIQUE, INTPAR, 2, FDCat_Tech ),
79 FUNCDATA( Bin2Dec, UNIQUE, STDPAR, 1, FDCat_Tech ),
80 FUNCDATA( Bin2Hex, UNIQUE, INTPAR, 2, FDCat_Tech ),
81 FUNCDATA( Oct2Bin, UNIQUE, INTPAR, 2, FDCat_Tech ),
82 FUNCDATA( Oct2Dec, UNIQUE, STDPAR, 1, FDCat_Tech ),
83 FUNCDATA( Oct2Hex, UNIQUE, INTPAR, 2, FDCat_Tech ),
84 FUNCDATA( Dec2Bin, UNIQUE, INTPAR, 2, FDCat_Tech ),
85 FUNCDATA( Dec2Hex, UNIQUE, INTPAR, 2, FDCat_Tech ),
86 FUNCDATA( Dec2Oct, UNIQUE, INTPAR, 2, FDCat_Tech ),
87 FUNCDATA( Hex2Bin, UNIQUE, INTPAR, 2, FDCat_Tech ),
88 FUNCDATA( Hex2Dec, UNIQUE, STDPAR, 1, FDCat_Tech ),
89 FUNCDATA( Hex2Oct, UNIQUE, INTPAR, 2, FDCat_Tech ),
90 FUNCDATA( Delta, UNIQUE, INTPAR, 2, FDCat_Tech ),
91 FUNCDATA( Erf, UNIQUE, INTPAR, 2, FDCat_Tech ),
92 FUNCDATA( Erfc, UNIQUE, STDPAR, 1, FDCat_Tech ),
93 FUNCDATA( Gestep, UNIQUE, INTPAR, 2, FDCat_Tech ),
94 FUNCDATA( Factdouble, UNIQUE, STDPAR, 1, FDCat_Tech ),
95 FUNCDATA( Imabs, UNIQUE, STDPAR, 1, FDCat_Tech ),
96 FUNCDATA( Imaginary, UNIQUE, STDPAR, 1, FDCat_Tech ),
97 FUNCDATA( Impower, UNIQUE, STDPAR, 2, FDCat_Tech ),
98 FUNCDATA( Imargument, UNIQUE, STDPAR, 1, FDCat_Tech ),
99 FUNCDATA( Imcos, UNIQUE, STDPAR, 1, FDCat_Tech ),
100 FUNCDATA( Imdiv, UNIQUE, STDPAR, 2, FDCat_Tech ),
101 FUNCDATA( Imexp, UNIQUE, STDPAR, 1, FDCat_Tech ),
102 FUNCDATA( Imconjugate, UNIQUE, STDPAR, 1, FDCat_Tech ),
103 FUNCDATA( Imln, UNIQUE, STDPAR, 1, FDCat_Tech ),
104 FUNCDATA( Imlog10, UNIQUE, STDPAR, 1, FDCat_Tech ),
105 FUNCDATA( Imlog2, UNIQUE, STDPAR, 1, FDCat_Tech ),
106 FUNCDATA( Improduct, UNIQUE, INTPAR, 2, FDCat_Tech ),
107 FUNCDATA( Imreal, UNIQUE, STDPAR, 1, FDCat_Tech ),
108 FUNCDATA( Imsin, UNIQUE, STDPAR, 1, FDCat_Tech ),
109 FUNCDATA( Imsub, UNIQUE, STDPAR, 2, FDCat_Tech ),
110 FUNCDATA( Imsqrt, UNIQUE, STDPAR, 1, FDCat_Tech ),
111 FUNCDATA( Imsum, UNIQUE, INTPAR, 1, FDCat_Tech ),
112 FUNCDATA( Complex, UNIQUE, STDPAR, 3, FDCat_Tech ),
113 FUNCDATA( Convert, DOUBLE, STDPAR, 3, FDCat_Tech ),
114 FUNCDATA( Amordegrc, UNIQUE, INTPAR, 7, FDCat_Finance ),
115 FUNCDATA( Amorlinc, UNIQUE, INTPAR, 7, FDCat_Finance ),
116 FUNCDATA( Accrint, UNIQUE, INTPAR, 7, FDCat_Finance ),
117 FUNCDATA( Accrintm, UNIQUE, INTPAR, 5, FDCat_Finance ),
118 FUNCDATA( Received, UNIQUE, INTPAR, 5, FDCat_Finance ),
119 FUNCDATA( Disc, UNIQUE, INTPAR, 5, FDCat_Finance ),
120 FUNCDATA( Duration, DOUBLE, INTPAR, 6, FDCat_Finance ),
121 FUNCDATA( Effect, DOUBLE, STDPAR, 2, FDCat_Finance ),
122 FUNCDATA( Cumprinc, DOUBLE, STDPAR, 6, FDCat_Finance ),
123 FUNCDATA( Cumipmt, DOUBLE, STDPAR, 6, FDCat_Finance ),
124 FUNCDATA( Price, UNIQUE, INTPAR, 7, FDCat_Finance ),
125 FUNCDATA( Pricedisc, UNIQUE, INTPAR, 5, FDCat_Finance ),
126 FUNCDATA( Pricemat, UNIQUE, INTPAR, 6, FDCat_Finance ),
127 FUNCDATA( Mduration, UNIQUE, INTPAR, 6, FDCat_Finance ),
128 FUNCDATA( Nominal, DOUBLE, STDPAR, 2, FDCat_Finance ),
129 FUNCDATA( Dollarfr, UNIQUE, STDPAR, 2, FDCat_Finance ),
130 FUNCDATA( Dollarde, UNIQUE, STDPAR, 2, FDCat_Finance ),
131 FUNCDATA( Yield, UNIQUE, INTPAR, 7, FDCat_Finance ),
132 FUNCDATA( Yielddisc, UNIQUE, INTPAR, 5, FDCat_Finance ),
133 FUNCDATA( Yieldmat, UNIQUE, INTPAR, 6, FDCat_Finance ),
134 FUNCDATA( Tbilleq, UNIQUE, INTPAR, 3, FDCat_Finance ),
135 FUNCDATA( Tbillprice, UNIQUE, INTPAR, 3, FDCat_Finance ),
136 FUNCDATA( Tbillyield, UNIQUE, INTPAR, 3, FDCat_Finance ),
137 FUNCDATA( Oddfprice, UNIQUE, INTPAR, 9, FDCat_Finance ),
138 FUNCDATA( Oddfyield, UNIQUE, INTPAR, 9, FDCat_Finance ),
139 FUNCDATA( Oddlprice, UNIQUE, INTPAR, 8, FDCat_Finance ),
140 FUNCDATA( Oddlyield, UNIQUE, INTPAR, 8, FDCat_Finance ),
141 FUNCDATA( Xirr, UNIQUE, INTPAR, 3, FDCat_Finance ),
142 FUNCDATA( Xnpv, UNIQUE, STDPAR, 3, FDCat_Finance ),
143 FUNCDATA( Intrate, UNIQUE, INTPAR, 5, FDCat_Finance ),
144 FUNCDATA( Coupncd, UNIQUE, INTPAR, 4, FDCat_Finance ),
145 FUNCDATA( Coupdays, UNIQUE, INTPAR, 4, FDCat_Finance ),
146 FUNCDATA( Coupdaysnc, UNIQUE, INTPAR, 4, FDCat_Finance ),
147 FUNCDATA( Coupdaybs, UNIQUE, INTPAR, 4, FDCat_Finance ),
148 FUNCDATA( Couppcd, UNIQUE, INTPAR, 4, FDCat_Finance ),
149 FUNCDATA( Coupnum, UNIQUE, INTPAR, 4, FDCat_Finance ),
150 FUNCDATA( Fvschedule, UNIQUE, STDPAR, 2, FDCat_Finance )
152 #undef FUNCDATA
155 sal_uInt16 DaysInMonth( sal_uInt16 nMonth, sal_uInt16 nYear )
157 if( (nMonth == 2) && IsLeapYear( nYear ) )
158 return 29;
159 static const sal_uInt16 aDaysInMonth[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
160 return aDaysInMonth[ nMonth ];
165 * Convert a date to a count of days starting from 01/01/0001
167 * The internal representation of a Date used in this Addin
168 * is the number of days between 01/01/0001 and the date
169 * this function converts a Day , Month, Year representation
170 * to this internal Date value.
174 sal_Int32 DateToDays( sal_uInt16 nDay, sal_uInt16 nMonth, sal_uInt16 nYear )
176 sal_Int32 nDays = ((sal_Int32)nYear-1) * 365;
177 nDays += ((nYear-1) / 4) - ((nYear-1) / 100) + ((nYear-1) / 400);
179 for( sal_uInt16 i = 1; i < nMonth; i++ )
180 nDays += DaysInMonth(i,nYear);
181 nDays += nDay;
183 return nDays;
188 * Convert a count of days starting from 01/01/0001 to a date
190 * The internal representation of a Date used in this Addin
191 * is the number of days between 01/01/0001 and the date
192 * this function converts this internal Date value
193 * to a Day , Month, Year representation of a Date.
197 void DaysToDate( sal_Int32 nDays, sal_uInt16& rDay, sal_uInt16& rMonth, sal_uInt16& rYear )
198 throw( lang::IllegalArgumentException )
200 if( nDays < 0 )
201 throw lang::IllegalArgumentException();
203 sal_Int32 nTempDays;
204 sal_Int32 i = 0;
205 sal_Bool bCalc;
209 nTempDays = nDays;
210 rYear = (sal_uInt16)((nTempDays / 365) - i);
211 nTempDays -= ((sal_Int32) rYear -1) * 365;
212 nTempDays -= (( rYear -1) / 4) - (( rYear -1) / 100) + ((rYear -1) / 400);
213 bCalc = sal_False;
214 if ( nTempDays < 1 )
216 i++;
217 bCalc = sal_True;
219 else
221 if ( nTempDays > 365 )
223 if ( (nTempDays != 366) || !IsLeapYear( rYear ) )
225 i--;
226 bCalc = sal_True;
231 while ( bCalc );
233 rMonth = 1;
234 while ( (sal_Int32)nTempDays > DaysInMonth( rMonth, rYear ) )
236 nTempDays -= DaysInMonth( rMonth, rYear );
237 rMonth++;
239 rDay = (sal_uInt16)nTempDays;
244 * Get the null date used by the spreadsheet document
246 * The internal representation of a Date used in this Addin
247 * is the number of days between 01/01/0001 and the date
248 * this function returns this internal Date value for the document null date
252 sal_Int32 GetNullDate( constREFXPS& xOpt ) THROWDEF_RTE
254 if( xOpt.is() )
258 ANY aAny = xOpt->getPropertyValue( STRFROMASCII( "NullDate" ) );
259 util::Date aDate;
260 if( aAny >>= aDate )
261 return DateToDays( aDate.Day, aDate.Month, aDate.Year );
263 catch( uno::Exception& )
268 // no null date available -> no calculations possible
269 throw uno::RuntimeException();
273 sal_Int32 GetDiffDate360(
274 sal_uInt16 nDay1, sal_uInt16 nMonth1, sal_uInt16 nYear1, sal_Bool bLeapYear1,
275 sal_uInt16 nDay2, sal_uInt16 nMonth2, sal_uInt16 nYear2,
276 sal_Bool bUSAMethod )
278 if( nDay1 == 31 )
279 nDay1--;
280 else if( bUSAMethod && ( nMonth1 == 2 && ( nDay1 == 29 || ( nDay1 == 28 && !bLeapYear1 ) ) ) )
281 nDay1 = 30;
283 if( nDay2 == 31 )
285 if( bUSAMethod && nDay1 != 30 )
287 //aDate2 += 1; -> 1.xx.yyyy
288 nDay2 = 1;
289 if( nMonth2 == 12 )
291 nYear2++;
292 nMonth2 = 1;
294 else
295 nMonth2++;
297 else
298 nDay2 = 30;
301 return nDay2 + nMonth2 * 30 + nYear2 * 360 - nDay1 - nMonth1 * 30 - nYear1 * 360;
305 sal_Int32 GetDiffDate360( sal_Int32 nNullDate, sal_Int32 nDate1, sal_Int32 nDate2, sal_Bool bUSAMethod )
307 nDate1 += nNullDate;
308 nDate2 += nNullDate;
310 sal_uInt16 nDay1, nMonth1, nYear1, nDay2, nMonth2, nYear2;
312 DaysToDate( nDate1, nDay1, nMonth1, nYear1 );
313 DaysToDate( nDate2, nDay2, nMonth2, nYear2 );
315 return GetDiffDate360( nDay1, nMonth1, nYear1, IsLeapYear( nYear1 ), nDay2, nMonth2, nYear2, bUSAMethod );
319 sal_Int32 GetDaysInYears( sal_uInt16 nYear1, sal_uInt16 nYear2 )
321 sal_uInt16 nLeaps = 0;
322 for( sal_uInt16 n = nYear1 ; n <= nYear2 ; n++ )
324 if( IsLeapYear( n ) )
325 nLeaps++;
328 sal_uInt32 nSum = 1;
329 nSum += nYear2;
330 nSum -= nYear1;
331 nSum *= 365;
332 nSum += nLeaps;
334 return nSum;
338 void GetDiffParam( sal_Int32 nNullDate, sal_Int32 nStartDate, sal_Int32 nEndDate, sal_Int32 nMode,
339 sal_uInt16& rYears, sal_Int32& rDayDiffPart, sal_Int32& rDaysInYear ) THROWDEF_RTE_IAE
341 if( nStartDate > nEndDate )
343 sal_Int32 n = nEndDate;
344 nEndDate = nStartDate;
345 nStartDate = n;
348 sal_Int32 nDate1 = nStartDate + nNullDate;
349 sal_Int32 nDate2 = nEndDate + nNullDate;
351 sal_uInt16 nDay1, nDay2;
352 sal_uInt16 nMonth1, nMonth2;
353 sal_uInt16 nYear1, nYear2;
355 DaysToDate( nDate1, nDay1, nMonth1, nYear1 );
356 DaysToDate( nDate2, nDay2, nMonth2, nYear2 );
358 sal_uInt16 nYears;
360 sal_Int32 nDayDiff, nDaysInYear;
362 switch( nMode )
364 case 0: // 0=USA (NASD) 30/360
365 case 4: // 4=Europe 30/360
366 nDaysInYear = 360;
367 nYears = nYear2 - nYear1;
368 nDayDiff = GetDiffDate360( nDay1, nMonth1, nYear1, IsLeapYear( nYear1 ),
369 nDay2, nMonth2, nYear2, nMode == 0 ) - nYears * nDaysInYear;
370 break;
371 case 1: // 1=exact/exact
372 nYears = nYear2 - nYear1;
374 nDaysInYear = IsLeapYear( nYear1 )? 366 : 365;
376 if( nYears && ( nMonth1 > nMonth2 || ( nMonth1 == nMonth2 && nDay1 > nDay2 ) ) )
377 nYears--;
379 if( nYears )
380 nDayDiff = nDate2 - DateToDays( nDay1, nMonth1, nYear2 );
381 else
382 nDayDiff = nDate2 - nDate1;
384 if( nDayDiff < 0 )
385 nDayDiff += nDaysInYear;
387 break;
388 case 2: // 2=exact/360
389 nDaysInYear = 360;
390 nYears = sal_uInt16( ( nDate2 - nDate1 ) / nDaysInYear );
391 nDayDiff = nDate2 - nDate1;
392 nDayDiff %= nDaysInYear;
393 break;
394 case 3: //3=exact/365
395 nDaysInYear = 365;
396 nYears = sal_uInt16( ( nDate2 - nDate1 ) / nDaysInYear );
397 nDayDiff = nDate2 - nDate1;
398 nDayDiff %= nDaysInYear;
399 break;
400 default:
401 THROW_IAE;
404 rYears = nYears;
405 rDayDiffPart = nDayDiff;
406 rDaysInYear = nDaysInYear;
410 sal_Int32 GetDiffDate( sal_Int32 nNullDate, sal_Int32 nStartDate, sal_Int32 nEndDate, sal_Int32 nMode,
411 sal_Int32* pOptDaysIn1stYear ) THROWDEF_RTE_IAE
413 sal_Bool bNeg = nStartDate > nEndDate;
415 if( bNeg )
417 sal_Int32 n = nEndDate;
418 nEndDate = nStartDate;
419 nStartDate = n;
422 sal_Int32 nRet;
424 switch( nMode )
426 case 0: // 0=USA (NASD) 30/360
427 case 4: // 4=Europe 30/360
429 sal_uInt16 nD1, nM1, nY1, nD2, nM2, nY2;
431 nStartDate += nNullDate;
432 nEndDate += nNullDate;
434 DaysToDate( nStartDate, nD1, nM1, nY1 );
435 DaysToDate( nEndDate, nD2, nM2, nY2 );
437 sal_Bool bLeap = IsLeapYear( nY1 );
438 sal_Int32 nDays, nMonths/*, nYears*/;
440 nMonths = nM2 - nM1;
441 nDays = nD2 - nD1;
443 nMonths += ( nY2 - nY1 ) * 12;
445 nRet = nMonths * 30 + nDays;
446 if( nMode == 0 && nM1 == 2 && nM2 != 2 && nY1 == nY2 )
447 nRet -= bLeap? 1 : 2;
449 if( pOptDaysIn1stYear )
450 *pOptDaysIn1stYear = 360;
452 break;
453 case 1: // 1=exact/exact
454 if( pOptDaysIn1stYear )
456 sal_uInt16 nD, nM, nY;
458 DaysToDate( nStartDate + nNullDate, nD, nM, nY );
460 *pOptDaysIn1stYear = IsLeapYear( nY )? 366 : 365;
462 nRet = nEndDate - nStartDate;
463 break;
464 case 2: // 2=exact/360
465 nRet = nEndDate - nStartDate;
466 if( pOptDaysIn1stYear )
467 *pOptDaysIn1stYear = 360;
468 break;
469 case 3: //3=exact/365
470 nRet = nEndDate - nStartDate;
471 if( pOptDaysIn1stYear )
472 *pOptDaysIn1stYear = 365;
473 break;
474 default:
475 THROW_IAE;
478 return bNeg? -nRet : nRet;
482 double GetYearDiff( sal_Int32 nNullDate, sal_Int32 nStartDate, sal_Int32 nEndDate, sal_Int32 nMode ) THROWDEF_RTE_IAE
484 sal_Int32 nDays1stYear;
485 sal_Int32 nTotalDays = GetDiffDate( nNullDate, nStartDate, nEndDate, nMode, &nDays1stYear );
487 return double( nTotalDays ) / double( nDays1stYear );
491 sal_Int32 GetDaysInYear( sal_Int32 nNullDate, sal_Int32 nDate, sal_Int32 nMode ) THROWDEF_RTE_IAE
493 switch( nMode )
495 case 0: // 0=USA (NASD) 30/360
496 case 2: // 2=exact/360
497 case 4: // 4=Europe 30/360
498 return 360;
499 case 1: // 1=exact/exact
501 sal_uInt16 nD, nM, nY;
502 nDate += nNullDate;
503 DaysToDate( nDate, nD, nM, nY );
504 return IsLeapYear( nY )? 366 : 365;
506 case 3: //3=exact/365
507 return 365;
508 default:
509 THROW_IAE;
514 double GetYearFrac( sal_Int32 nNullDate, sal_Int32 nStartDate, sal_Int32 nEndDate, sal_Int32 nMode ) THROWDEF_RTE_IAE
516 if( nStartDate == nEndDate )
517 return 0.0; // nothing to do...
519 sal_uInt16 nYears;
520 sal_Int32 nDayDiff, nDaysInYear;
522 GetDiffParam( nNullDate, nStartDate, nEndDate, nMode, nYears, nDayDiff, nDaysInYear );
524 return double( nYears ) + double( nDayDiff ) / double( nDaysInYear );
528 double Fak( sal_Int32 n )
530 if( n > 0 )
532 double fRet = n;
533 double f = n - 1;
535 while( f >= 2.0 )
537 fRet *= f;
538 f--;
541 return fRet;
543 else if( !n )
544 return 1.0;
545 else
546 return 0.0;
550 double GetGcd( double f1, double f2 )
552 double f = fmod( f1, f2 );
553 while( f > 0.0 )
555 f1 = f2;
556 f2 = f;
557 f = fmod( f1, f2 );
560 return f2;
564 double ConvertToDec( const STRING& aStr, sal_uInt16 nBase, sal_uInt16 nCharLim ) THROWDEF_RTE_IAE
566 if ( nBase < 2 || nBase > 36 )
567 THROW_IAE;
569 sal_uInt32 nStrLen = aStr.getLength();
570 if( nStrLen > nCharLim )
571 THROW_IAE;
572 else if( !nStrLen )
573 return 0.0;
575 double fVal = 0.0;
577 register const sal_Unicode* p = aStr.getStr();
579 sal_uInt16 nFirstDig = 0;
580 sal_Bool bFirstDig = sal_True;
581 double fBase = nBase;
583 while ( *p )
585 sal_uInt16 n;
587 if( '0' <= *p && *p <= '9' )
588 n = *p - '0';
589 else if( 'A' <= *p && *p <= 'Z' )
590 n = 10 + ( *p - 'A' );
591 else if ( 'a' <= *p && *p <= 'z' )
592 n = 10 + ( *p - 'a' );
593 else
594 n = nBase;
596 if( n < nBase )
598 if( bFirstDig )
600 bFirstDig = sal_False;
601 nFirstDig = n;
603 fVal = fVal * fBase + double( n );
605 else
606 // illegal char!
607 THROW_IAE;
609 p++;
613 if( nStrLen == nCharLim && !bFirstDig && (nFirstDig >= nBase / 2) )
614 { // handling negativ values
615 fVal = ( pow( double( nBase ), double( nCharLim ) ) - fVal ); // complement
616 fVal *= -1.0;
619 return fVal;
623 static inline sal_Char GetMaxChar( sal_uInt16 nBase )
625 const sal_Char* c = "--123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
626 return c[ nBase ];
630 STRING ConvertFromDec( double fNum, double fMin, double fMax, sal_uInt16 nBase,
631 sal_Int32 nPlaces, sal_Int32 nMaxPlaces, sal_Bool bUsePlaces ) THROWDEF_RTE_IAE
633 fNum = ::rtl::math::approxFloor( fNum );
634 fMin = ::rtl::math::approxFloor( fMin );
635 fMax = ::rtl::math::approxFloor( fMax );
637 if( fNum < fMin || fNum > fMax || ( bUsePlaces && ( nPlaces <= 0 || nPlaces > nMaxPlaces ) ) )
638 THROW_IAE;
640 sal_Int64 nNum = static_cast< sal_Int64 >( fNum );
641 sal_Bool bNeg = nNum < 0;
642 if( bNeg )
643 nNum = sal_Int64( pow( double( nBase ), double( nMaxPlaces ) ) ) + nNum;
645 STRING aRet( STRING::valueOf( nNum, nBase ).toAsciiUpperCase() );
648 if( bUsePlaces )
650 sal_Int32 nLen = aRet.getLength();
651 if( !bNeg && nLen > nPlaces )
653 THROW_IAE;
655 else if( ( bNeg && nLen < nMaxPlaces ) || ( !bNeg && nLen < nPlaces ) )
657 sal_Int32 nLeft = nPlaces - nLen;
658 sal_Char* p = new sal_Char[ nLeft + 1 ];
659 memset( p, bNeg? GetMaxChar( nBase ) : '0', nLeft );
660 p[ nLeft ] = 0x00;
661 STRING aTmp( p, nLeft, RTL_TEXTENCODING_MS_1252 );
662 aTmp += aRet;
663 aRet = aTmp;
665 delete[] p;
669 return aRet;
672 /** Approximation algorithm for erf for 0 < x < 0.65. */
673 void Erf0065( double x, double& fVal )
675 static const double pn[] = {
676 1.12837916709551256,
677 1.35894887627277916E-1,
678 4.03259488531795274E-2,
679 1.20339380863079457E-3,
680 6.49254556481904354E-5
682 static const double qn[] = {
683 1.00000000000000000,
684 4.53767041780002545E-1,
685 8.69936222615385890E-2,
686 8.49717371168693357E-3,
687 3.64915280629351082E-4
690 double fPSum = 0.0;
691 double fQSum = 0.0;
692 double fXPow = 1.0;
693 for ( unsigned int i = 0; i <= 4; ++i )
695 fPSum += pn[i]*fXPow;
696 fQSum += qn[i]*fXPow;
697 fXPow *= x*x;
699 fVal = x * fPSum / fQSum;
702 /** Approximation algorithm for erfc for 0.65 < x < 6.0. */
703 void Erfc0600( double x, double& fVal )
705 double fPSum = 0.0;
706 double fQSum = 0.0;
707 double fXPow = 1.0;
708 const double *pn;
709 const double *qn;
711 if ( x < 2.2 )
713 static const double pn22[] = {
714 9.99999992049799098E-1,
715 1.33154163936765307,
716 8.78115804155881782E-1,
717 3.31899559578213215E-1,
718 7.14193832506776067E-2,
719 7.06940843763253131E-3
721 static const double qn22[] = {
722 1.00000000000000000,
723 2.45992070144245533,
724 2.65383972869775752,
725 1.61876655543871376,
726 5.94651311286481502E-1,
727 1.26579413030177940E-1,
728 1.25304936549413393E-2
730 pn = pn22;
731 qn = qn22;
733 else /* if ( x < 6.0 ) this is true, but the compiler does not know */
735 static const double pn60[] = {
736 9.99921140009714409E-1,
737 1.62356584489366647,
738 1.26739901455873222,
739 5.81528574177741135E-1,
740 1.57289620742838702E-1,
741 2.25716982919217555E-2
743 static const double qn60[] = {
744 1.00000000000000000,
745 2.75143870676376208,
746 3.37367334657284535,
747 2.38574194785344389,
748 1.05074004614827206,
749 2.78788439273628983E-1,
750 4.00072964526861362E-2
752 pn = pn60;
753 qn = qn60;
756 for ( unsigned int i = 0; i < 6; ++i )
758 fPSum += pn[i]*fXPow;
759 fQSum += qn[i]*fXPow;
760 fXPow *= x;
762 fQSum += qn[6]*fXPow;
763 fVal = exp( -1.0*x*x )* fPSum / fQSum;
766 /** Approximation algorithm for erfc for 6.0 < x < 26.54 (but used for all
767 x > 6.0). */
768 void Erfc2654( double x, double& fVal )
770 static const double pn[] = {
771 5.64189583547756078E-1,
772 8.80253746105525775,
773 3.84683103716117320E1,
774 4.77209965874436377E1,
775 8.08040729052301677
777 static const double qn[] = {
778 1.00000000000000000,
779 1.61020914205869003E1,
780 7.54843505665954743E1,
781 1.12123870801026015E2,
782 3.73997570145040850E1
785 double fPSum = 0.0;
786 double fQSum = 0.0;
787 double fXPow = 1.0;
789 for ( unsigned int i = 0; i <= 4; ++i )
791 fPSum += pn[i]*fXPow;
792 fQSum += qn[i]*fXPow;
793 fXPow /= x*x;
795 fVal = exp(-1.0*x*x)*fPSum / (x*fQSum);
798 double Erfc( double );
800 /** Parent error function (erf) that calls different algorithms based on the
801 value of x. It takes care of cases where x is negative as erf is an odd
802 function i.e. erf(-x) = -erf(x).
804 Kramer, W., and Blomquist, F., 2000, Algorithms with Guaranteed Error Bounds
805 for the Error Function and the Complementary Error Function
807 http://www.math.uni-wuppertal.de/wrswt/literatur_en.html
809 @author Kohei Yoshida <kohei@openoffice.org>
811 @see #i55735#
813 double Erf( double x )
815 if( x == 0.0 )
816 return 0.0;
818 bool bNegative = false;
819 if ( x < 0.0 )
821 x = fabs( x );
822 bNegative = true;
825 double fErf = 1.0;
826 if ( x < 1.0e-10 )
827 fErf = (double) (x*1.1283791670955125738961589031215452L);
828 else if ( x < 0.65 )
829 Erf0065( x, fErf );
830 else
831 fErf = 1.0 - Erfc( x );
833 if ( bNegative )
834 fErf *= -1.0;
836 return fErf;
839 /** Parent complementary error function (erfc) that calls different algorithms
840 based on the value of x. It takes care of cases where x is negative as erfc
841 satisfies relationship erfc(-x) = 2 - erfc(x). See the comment for Erf(x)
842 for the source publication.
844 @author Kohei Yoshida <kohei@openoffice.org>
846 @see #i55735#
848 double Erfc( double x )
850 if ( x == 0.0 )
851 return 1.0;
853 bool bNegative = false;
854 if ( x < 0.0 )
856 x = fabs( x );
857 bNegative = true;
860 double fErfc = 0.0;
861 if ( x >= 0.65 )
863 if ( x < 6.0 )
864 Erfc0600( x, fErfc );
865 else
866 Erfc2654( x, fErfc );
868 else
869 fErfc = 1.0 - Erf( x );
871 if ( bNegative )
872 fErfc = 2.0 - fErfc;
874 return fErfc;
877 inline sal_Bool IsNum( sal_Unicode c )
879 return c >= '0' && c <= '9';
883 inline sal_Bool IsComma( sal_Unicode c )
885 return c == '.' || c == ',';
889 inline sal_Bool IsExpStart( sal_Unicode c )
891 return c == 'e' || c == 'E';
895 inline sal_Bool IsImagUnit( sal_Unicode c )
897 return c == 'i' || c == 'j';
901 inline sal_uInt16 GetVal( sal_Unicode c )
903 return sal_uInt16( c - '0' );
907 sal_Bool ParseDouble( const sal_Unicode*& rp, double& rRet )
909 double fInt = 0.0;
910 double fFrac = 0.0;
911 double fMult = 0.1; // multiplier to multiply digits with, when adding fractional ones
912 sal_Int32 nExp = 0;
913 sal_Int32 nMaxExp = 307;
914 sal_uInt16 nDigCnt = 18; // max. number of digits to read in, rest doesn't matter
916 enum State { S_End = 0, S_Sign, S_IntStart, S_Int, S_IgnoreIntDigs, S_Frac, S_IgnoreFracDigs, S_ExpSign, S_Exp };
918 State eS = S_Sign;
920 sal_Bool bNegNum = sal_False;
921 sal_Bool bNegExp = sal_False;
923 const sal_Unicode* p = rp;
924 sal_Unicode c;
926 while( eS )
928 c = *p;
929 switch( eS )
931 case S_Sign:
932 if( IsNum( c ) )
934 fInt = GetVal( c );
935 nDigCnt--;
936 eS = S_Int;
938 else if( c == '-' )
940 bNegNum = sal_True;
941 eS = S_IntStart;
943 else if( c == '+' )
944 eS = S_IntStart;
945 else if( IsComma( c ) )
946 eS = S_Frac;
947 else
948 return sal_False;
949 break;
950 case S_IntStart:
951 if( IsNum( c ) )
953 fInt = GetVal( c );
954 nDigCnt--;
955 eS = S_Int;
957 else if( IsComma( c ) )
958 eS = S_Frac;
959 else if( IsImagUnit( c ) )
961 rRet = 0.0;
962 return sal_True;
964 else
965 return sal_False;
966 break;
967 case S_Int:
968 if( IsNum( c ) )
970 fInt *= 10.0;
971 fInt += double( GetVal( c ) );
972 nDigCnt--;
973 if( !nDigCnt )
974 eS = S_IgnoreIntDigs;
976 else if( IsComma( c ) )
977 eS = S_Frac;
978 else if( IsExpStart( c ) )
979 eS = S_ExpSign;
980 else
981 eS = S_End;
982 break;
983 case S_IgnoreIntDigs:
984 if( IsNum( c ) )
985 nExp++; // just multiply num with 10... ;-)
986 else if( IsComma( c ) )
987 eS = S_Frac;
988 else if( IsExpStart( c ) )
989 eS = S_ExpSign;
990 else
991 eS = S_End;
992 break;
993 case S_Frac:
994 if( IsNum( c ) )
996 fFrac += double( GetVal( c ) ) * fMult;
997 nDigCnt--;
998 if( nDigCnt )
999 fMult *= 0.1;
1000 else
1001 eS = S_IgnoreFracDigs;
1003 else if( IsExpStart( c ) )
1004 eS = S_ExpSign;
1005 else
1006 eS = S_End;
1007 break;
1008 case S_IgnoreFracDigs:
1009 if( IsExpStart( c ) )
1010 eS = S_ExpSign;
1011 else if( !IsNum( c ) )
1012 eS = S_End;
1013 break;
1014 case S_ExpSign:
1015 if( IsNum( c ) )
1017 nExp = GetVal( c );
1018 eS = S_Exp;
1020 else if( c == '-' )
1022 bNegExp = sal_True;
1023 eS = S_Exp;
1025 else if( c != '+' )
1026 eS = S_End;
1027 break;
1028 case S_Exp:
1029 if( IsNum( c ) )
1031 nExp *= 10;
1032 nExp += GetVal( c );
1033 if( nExp > nMaxExp )
1034 return sal_False;
1036 else
1037 eS = S_End;
1038 break;
1039 case S_End: // to avoid compiler warning
1040 break; // loop exits anyway
1043 p++;
1046 p--; // set pointer back to last
1047 rp = p;
1049 fInt += fFrac;
1050 sal_Int32 nLog10 = sal_Int32( log10( fInt ) );
1052 if( bNegExp )
1053 nExp = -nExp;
1055 if( nLog10 + nExp > nMaxExp )
1056 return sal_False;
1058 fInt = ::rtl::math::pow10Exp( fInt, nExp );
1060 if( bNegNum )
1061 fInt = -fInt;
1063 rRet = fInt;
1065 return sal_True;
1069 STRING GetString( double f, sal_Bool bLeadingSign, sal_uInt16 nMaxDig )
1071 const int nBuff = 256;
1072 sal_Char aBuff[ nBuff + 1 ];
1073 const char* pFormStr = bLeadingSign? "%+.*g" : "%.*g";
1074 int nLen = snprintf( aBuff, nBuff, pFormStr, int( nMaxDig ), f );
1075 // you never know which underlying implementation you get ...
1076 aBuff[nBuff] = 0;
1077 if ( nLen < 0 || nLen > nBuff )
1078 nLen = strlen( aBuff );
1080 STRING aRet( aBuff, nLen, RTL_TEXTENCODING_MS_1252 );
1082 return aRet;
1086 double GetAmordegrc( sal_Int32 nNullDate, double fCost, sal_Int32 nDate, sal_Int32 nFirstPer,
1087 double fRestVal, double fPer, double fRate, sal_Int32 nBase ) THROWDEF_RTE_IAE
1089 if( nBase == 2 )
1090 THROW_IAE;
1092 sal_uInt32 nPer = sal_uInt32( fPer );
1093 double fUsePer = 1.0 / fRate;
1094 double fAmorCoeff;
1096 if( fUsePer < 3.0 )
1097 fAmorCoeff = 1.0;
1098 else if( fUsePer < 5.0 )
1099 fAmorCoeff = 1.5;
1100 else if( fUsePer <= 6.0 )
1101 fAmorCoeff = 2.0;
1102 else
1103 fAmorCoeff = 2.5;
1105 fRate *= fAmorCoeff;
1106 double fNRate = ::rtl::math::round( GetYearFrac( nNullDate, nDate, nFirstPer, nBase ) * fRate * fCost, 0 );
1107 fCost -= fNRate;
1108 double fRest = fCost - fRestVal; // Anschaffungskosten - Restwert - Summe aller Abschreibungen
1110 for( sal_uInt32 n = 0 ; n < nPer ; n++ )
1112 fNRate = ::rtl::math::round( fRate * fCost, 0 );
1113 fRest -= fNRate;
1115 if( fRest < 0.0 )
1117 switch( nPer - n )
1119 case 0:
1120 case 1:
1121 return ::rtl::math::round( fCost * 0.5, 0 );
1122 default:
1123 return 0.0;
1127 fCost -= fNRate;
1130 return fNRate;
1134 double GetAmorlinc( sal_Int32 nNullDate, double fCost, sal_Int32 nDate, sal_Int32 nFirstPer,
1135 double fRestVal, double fPer, double fRate, sal_Int32 nBase ) THROWDEF_RTE_IAE
1137 if( nBase == 2 )
1138 THROW_IAE;
1140 sal_uInt32 nPer = sal_uInt32( fPer );
1141 double fOneRate = fCost * fRate;
1142 double fCostDelta = fCost - fRestVal;
1143 double f0Rate = GetYearFrac( nNullDate, nDate, nFirstPer, nBase ) * fRate * fCost;
1144 sal_uInt32 nNumOfFullPeriods = sal_uInt32( ( fCost - fRestVal - f0Rate) / fOneRate );
1146 if( nPer == 0 )
1147 return f0Rate;
1148 else if( nPer <= nNumOfFullPeriods )
1149 return fOneRate;
1150 else if( nPer == nNumOfFullPeriods + 1 )
1151 return fCostDelta - fOneRate * nNumOfFullPeriods - f0Rate;
1152 else
1153 return 0.0;
1157 double GetDuration( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, double fCoup,
1158 double fYield, sal_Int32 nFreq, sal_Int32 nBase ) THROWDEF_RTE_IAE
1160 double fYearfrac = GetYearFrac( nNullDate, nSettle, nMat, nBase );
1161 double fNumOfCoups = GetCoupnum( nNullDate, nSettle, nMat, nFreq, nBase );
1162 double fDur = 0.0;
1163 const double f100 = 100.0;
1164 fCoup *= f100 / double( nFreq ); // fCoup is used as cash flow
1165 fYield /= nFreq;
1166 fYield += 1.0;
1168 double nDiff = fYearfrac * nFreq - fNumOfCoups;
1170 double t;
1172 for( t = 1.0 ; t < fNumOfCoups ; t++ )
1173 fDur += ( t + nDiff ) * ( fCoup ) / pow( fYield, t + nDiff );
1175 fDur += ( fNumOfCoups + nDiff ) * ( fCoup + f100 ) / pow( fYield, fNumOfCoups + nDiff );
1177 double p = 0.0;
1178 for( t = 1.0 ; t < fNumOfCoups ; t++ )
1179 p += fCoup / pow( fYield, t + nDiff );
1181 p += ( fCoup + f100 ) / pow( fYield, fNumOfCoups + nDiff );
1183 fDur /= p;
1184 fDur /= double( nFreq );
1186 return fDur;
1190 double GetYieldmat( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nIssue,
1191 double fRate, double fPrice, sal_Int32 nBase ) THROWDEF_RTE_IAE
1193 double fIssMat = GetYearFrac( nNullDate, nIssue, nMat, nBase );
1194 double fIssSet = GetYearFrac( nNullDate, nIssue, nSettle, nBase );
1195 double fSetMat = GetYearFrac( nNullDate, nSettle, nMat, nBase );
1197 double y = 1.0 + fIssMat * fRate;
1198 y /= fPrice / 100.0 + fIssSet * fRate;
1199 y--;
1200 y /= fSetMat;
1202 return y;
1206 double GetOddfprice( sal_Int32 /*nNullDate*/, sal_Int32 /*nSettle*/, sal_Int32 /*nMat*/, sal_Int32 /*nIssue*/,
1207 sal_Int32 /*nFirstCoup*/, double /*fRate*/, double /*fYield*/, double /*fRedemp*/, sal_Int32 /*nFreq*/,
1208 sal_Int32 /*nBase*/ ) THROWDEF_RTE_IAE
1210 THROW_RTE; // #87380#
1212 double fN = GetCoupnum( nNullDate, nSettle, nMat, nFreq, nBase ) - 1.0;
1213 double fNq = GetCoupnum( nNullDate, nSettle, nFirstCoup, nFreq, nBase ) - 1.0;
1214 double fDSC = GetCoupdaysnc( nNullDate, nSettle, nFirstCoup, nFreq, nBase );
1215 double fDSC_E = fDSC / GetCoupdays( nNullDate, nSettle, nMat, nFreq, nBase );
1216 double fNC = GetCoupnum( nNullDate, nIssue, nFirstCoup, nFreq, nBase );
1217 sal_uInt32 nNC = sal_uInt32( fNC );
1218 sal_uInt16 nMonthDelta = 12 / sal_uInt16( nFreq );
1220 sal_uInt32 i;
1221 double f1YieldFreq = 1.0 + fYield / double( nFreq );
1222 double f100RateFreq = 100.0 * fRate / double( nFreq );
1224 double* pDC = new double[ nNC + 1 ];
1225 double* pNL = new double[ nNC + 1 ];
1226 double* pA = new double[ nNC + 1 ];
1228 pDC[ 0 ] = pNL[ 0 ] = pA[ 0 ] = 1.0;
1230 ScaDate aStartDate( nNullDate, nSettle, nBase );
1231 ScaDate aNextCoup( nNullDate, nFirstCoup, nBase );
1232 if( nNC )
1234 pDC[ 1 ] = ScaDate::GetDiff( aStartDate, aNextCoup );
1235 pNL[ 1 ] = GetCoupdays( nNullDate, nSettle, nFirstCoup, nFreq, nBase );
1236 pA[ 1 ] = pDC[ 1 ];
1237 ScaDate aPre;
1238 for( i = 1 ; i <= nNC ; i++ )
1240 aPre = aStartDate;
1241 aStartDate.addMonths( nMonthDelta );
1242 aNextCoup.addMonths( nMonthDelta );
1243 pDC[ i ] = ScaDate::GetDiff( aPre, aStartDate );
1244 pNL[ i ] = GetCoupdays( nNullDate, aStartDate.GetDate( nNullDate ), aNextCoup.GetDate( nNullDate ),
1245 nFreq, nBase );
1246 pA[ i ] = ScaDate::GetDiff( aStartDate, aNextCoup );
1250 double fT1 = fRedemp / pow( f1YieldFreq, fN + fNq + fDSC_E );
1252 double fT2 = 0.0;
1253 for( i = 1 ; i <= nNC ; i++ )
1254 fT2 += pDC[ i ] / pNL[ i ];
1255 fT2 *= f100RateFreq / pow( f1YieldFreq, fNq + fDSC_E );
1257 double fT3 = 0.0;
1258 for( double k = 2.0 ; k <= fN ; k++ )
1259 fT3 += 1.0 / pow( f1YieldFreq, k - fNq + fDSC_E );
1260 fT3 *= f100RateFreq;
1262 double fT4 = 0.0;
1263 for( i = 1 ; i <= nNC ; i++ )
1264 fT4 += pA[ i ] / pNL[ i ];
1265 fT4 *= f100RateFreq;
1267 if( nNC )
1269 delete pDC;
1270 delete pNL;
1271 delete pA;
1274 return fT1 + fT2 + fT3 - fT4;
1279 double getYield_( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, double fCoup, double fPrice,
1280 double fRedemp, sal_Int32 nFreq, sal_Int32 nBase ) THROWDEF_RTE_IAE
1282 double fRate = fCoup;
1283 double fPriceN = 0.0;
1284 double fYield1 = 0.0;
1285 double fYield2 = 1.0;
1286 double fPrice1 = getPrice_( nNullDate, nSettle, nMat, fRate, fYield1, fRedemp, nFreq, nBase );
1287 double fPrice2 = getPrice_( nNullDate, nSettle, nMat, fRate, fYield2, fRedemp, nFreq, nBase );
1288 double fYieldN = ( fYield2 - fYield1 ) * 0.5;
1290 for( sal_uInt32 nIter = 0 ; nIter < 100 && fPriceN != fPrice ; nIter++ )
1292 fPriceN = getPrice_( nNullDate, nSettle, nMat, fRate, fYieldN, fRedemp, nFreq, nBase );
1294 if( fPrice == fPrice1 )
1295 return fYield1;
1296 else if( fPrice == fPrice2 )
1297 return fYield2;
1298 else if( fPrice == fPriceN )
1299 return fYieldN;
1300 else if( fPrice < fPrice2 )
1302 fYield2 *= 2.0;
1303 fPrice2 = getPrice_( nNullDate, nSettle, nMat, fRate, fYield2, fRedemp, nFreq, nBase );
1305 fYieldN = ( fYield2 - fYield1 ) * 0.5;
1307 else
1309 if( fPrice < fPriceN )
1311 fYield1 = fYieldN;
1312 fPrice1 = fPriceN;
1314 else
1316 fYield2 = fYieldN;
1317 fPrice2 = fPriceN;
1320 fYieldN = fYield2 - ( fYield2 - fYield1 ) * ( ( fPrice - fPrice2 ) / ( fPrice1 - fPrice2 ) );
1324 if( fabs( fPrice - fPriceN ) > fPrice / 100.0 )
1325 THROW_IAE; // result not precise enough
1327 return fYieldN;
1331 double getPrice_( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, double fRate, double fYield,
1332 double fRedemp, sal_Int32 nFreq, sal_Int32 nBase ) THROWDEF_RTE_IAE
1334 double fFreq = nFreq;
1336 double fE = GetCoupdays( nNullDate, nSettle, nMat, nFreq, nBase );
1337 double fDSC_E = GetCoupdaysnc( nNullDate, nSettle, nMat, nFreq, nBase ) / fE;
1338 double fN = GetCoupnum( nNullDate, nSettle, nMat, nFreq, nBase );
1339 double fA = GetCoupdaybs( nNullDate, nSettle, nMat, nFreq, nBase );
1341 double fRet = fRedemp / ( pow( 1.0 + fYield / fFreq, fN - 1.0 + fDSC_E ) );
1342 fRet -= 100.0 * fRate / fFreq * fA / fE;
1344 double fT1 = 100.0 * fRate / fFreq;
1345 double fT2 = 1.0 + fYield / fFreq;
1347 for( double fK = 0.0 ; fK < fN ; fK++ )
1348 fRet += fT1 / pow( fT2, fK + fDSC_E );
1350 return fRet;
1354 double GetOddfyield( sal_Int32 /*nNullDate*/, sal_Int32 /*nSettle*/, sal_Int32 /*nMat*/, sal_Int32 /*nIssue*/,
1355 sal_Int32 /*nFirstCoup*/, double /*fRate*/, double /*fPrice*/, double /*fRedemp*/, sal_Int32 /*nFreq*/,
1356 sal_Int32 /*nBase*/ ) THROWDEF_RTE_IAE
1358 THROW_RTE; // #87380#
1360 //GetOddfprice( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nIssue,
1361 //sal_Int32 nFirstCoup, double fRate, double fYield, double fRedemp, sal_Int32 nFreq,
1362 //sal_Int32 nBase )
1363 double fPriceN = 0.0;
1364 double fYield1 = 0.0;
1365 double fYield2 = 1.0;
1366 double fPrice1 = GetOddfprice( nNullDate, nSettle, nMat, nIssue, nFirstCoup, fRate, fYield1, fRedemp, nFreq, nBase );
1367 double fPrice2 = GetOddfprice( nNullDate, nSettle, nMat, nIssue, nFirstCoup, fRate, fYield2, fRedemp, nFreq, nBase );
1368 double fYieldN = ( fYield2 - fYield1 ) * 0.5;
1370 for( sal_uInt32 nIter = 0 ; nIter < 100 && fPriceN != fPrice ; nIter++ )
1372 fPriceN = GetOddfprice( nNullDate, nSettle, nMat, nIssue, nFirstCoup, fRate, fYieldN, fRedemp, nFreq, nBase );
1374 if( fPrice == fPrice1 )
1375 return fYield1;
1376 else if( fPrice == fPrice2 )
1377 return fYield2;
1378 else if( fPrice == fPriceN )
1379 return fYieldN;
1380 else if( fPrice < fPrice2 )
1382 fYield2 *= 2.0;
1383 fPrice2 = GetOddfprice( nNullDate, nSettle, nMat, nIssue, nFirstCoup, fRate, fYield2, fRedemp, nFreq, nBase );
1385 fYieldN = ( fYield2 - fYield1 ) * 0.5;
1387 else
1389 if( fPrice < fPriceN )
1391 fYield1 = fYieldN;
1392 fPrice1 = fPriceN;
1394 else
1396 fYield2 = fYieldN;
1397 fPrice2 = fPriceN;
1400 fYieldN = fYield2 - ( fYield2 - fYield1 ) * ( ( fPrice - fPrice2 ) / ( fPrice1 - fPrice2 ) );
1404 if( fabs( fPrice - fPriceN ) > fPrice / 100.0 )
1405 THROW_IAE; // result not precise enough
1407 return fYieldN;
1412 double GetOddlprice( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nLastCoup,
1413 double fRate, double fYield, double fRedemp, sal_Int32 nFreq, sal_Int32 nBase ) THROWDEF_RTE_IAE
1415 double fFreq = double( nFreq );
1416 double fDCi = GetYearFrac( nNullDate, nLastCoup, nMat, nBase ) * fFreq;
1417 double fDSCi = GetYearFrac( nNullDate, nSettle, nMat, nBase ) * fFreq;
1418 double fAi = GetYearFrac( nNullDate, nLastCoup, nSettle, nBase ) * fFreq;
1420 double p = fRedemp + fDCi * 100.0 * fRate / fFreq;
1421 p /= fDSCi * fYield / fFreq + 1.0;
1422 p -= fAi * 100.0 * fRate / fFreq;
1424 return p;
1428 double GetOddlyield( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nLastCoup,
1429 double fRate, double fPrice, double fRedemp, sal_Int32 nFreq, sal_Int32 nBase ) THROWDEF_RTE_IAE
1431 double fFreq = double( nFreq );
1432 double fDCi = GetYearFrac( nNullDate, nLastCoup, nMat, nBase ) * fFreq;
1433 double fDSCi = GetYearFrac( nNullDate, nSettle, nMat, nBase ) * fFreq;
1434 double fAi = GetYearFrac( nNullDate, nLastCoup, nSettle, nBase ) * fFreq;
1436 double y = fRedemp + fDCi * 100.0 * fRate / fFreq;
1437 y /= fPrice + fAi * 100.0 * fRate / fFreq;
1438 y--;
1439 y *= fFreq / fDSCi;
1441 return y;
1445 double GetRmz( double fZins, double fZzr, double fBw, double fZw, sal_Int32 nF )
1447 double fRmz;
1448 if( fZins == 0.0 )
1449 fRmz = ( fBw + fZw ) / fZzr;
1450 else
1452 double fTerm = pow( 1.0 + fZins, fZzr );
1453 if( nF > 0 )
1454 fRmz = ( fZw * fZins / ( fTerm - 1.0 ) + fBw * fZins / ( 1.0 - 1.0 / fTerm ) ) / ( 1.0 + fZins );
1455 else
1456 fRmz = fZw * fZins / ( fTerm - 1.0 ) + fBw * fZins / ( 1.0 - 1.0 / fTerm );
1459 return -fRmz;
1463 double GetZw( double fZins, double fZzr, double fRmz, double fBw, sal_Int32 nF )
1465 double fZw;
1466 if( fZins == 0.0 )
1467 fZw = fBw + fRmz * fZzr;
1468 else
1470 double fTerm = pow( 1.0 + fZins, fZzr );
1471 if( nF > 0 )
1472 fZw = fBw * fTerm + fRmz * ( 1.0 + fZins ) * ( fTerm - 1.0 ) / fZins;
1473 else
1474 fZw = fBw * fTerm + fRmz * ( fTerm - 1.0 ) / fZins;
1477 return -fZw;
1481 /*double TBillYield( constREFXPS& xOpt, sal_Int32 nSettle, sal_Int32 nMat, double fPrice ) THROWDEF_RTE_IAE
1483 sal_Int32 nDiff = GetDiffDate360( xOpt, nSettle, nMat, sal_True );
1485 if( fPrice <= 0.0 || nSettle >= nMat || nDiff > 360 )
1486 THROW_IAE;
1488 double fRet = 100.0;
1489 fRet /= fPrice;
1490 fRet--;
1491 fRet *= double( nDiff );
1492 fRet /= 360.0;
1494 return fRet;
1498 //-----------------------------------------------------------------------------
1499 // financial functions COUP***
1502 //-------
1503 // COUPPCD: find last coupon date before settlement (can be equal to settlement)
1504 void lcl_GetCouppcd( ScaDate& rDate, const ScaDate& rSettle, const ScaDate& rMat, sal_Int32 nFreq )
1505 throw( lang::IllegalArgumentException )
1507 rDate = rMat;
1508 rDate.setYear( rSettle.getYear() );
1509 if( rDate < rSettle )
1510 rDate.addYears( 1 );
1511 while( rDate > rSettle )
1512 rDate.addMonths( -12 / nFreq );
1515 double GetCouppcd( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nFreq, sal_Int32 nBase )
1516 THROWDEF_RTE_IAE
1518 if( nSettle >= nMat || CHK_Freq )
1519 THROW_IAE;
1521 ScaDate aDate;
1522 lcl_GetCouppcd( aDate, ScaDate( nNullDate, nSettle, nBase ), ScaDate( nNullDate, nMat, nBase ), nFreq );
1523 return aDate.getDate( nNullDate );
1527 //-------
1528 // COUPNCD: find first coupon date after settlement (is never equal to settlement)
1529 void lcl_GetCoupncd( ScaDate& rDate, const ScaDate& rSettle, const ScaDate& rMat, sal_Int32 nFreq )
1530 throw( lang::IllegalArgumentException )
1532 rDate = rMat;
1533 rDate.setYear( rSettle.getYear() );
1534 if( rDate > rSettle )
1535 rDate.addYears( -1 );
1536 while( rDate <= rSettle )
1537 rDate.addMonths( 12 / nFreq );
1540 double GetCoupncd( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nFreq, sal_Int32 nBase )
1541 THROWDEF_RTE_IAE
1543 if( nSettle >= nMat || CHK_Freq )
1544 THROW_IAE;
1546 ScaDate aDate;
1547 lcl_GetCoupncd( aDate, ScaDate( nNullDate, nSettle, nBase ), ScaDate( nNullDate, nMat, nBase ), nFreq );
1548 return aDate.getDate( nNullDate );
1552 //-------
1553 // COUPDAYBS: get day count: coupon date before settlement <-> settlement
1554 double GetCoupdaybs( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nFreq, sal_Int32 nBase )
1555 THROWDEF_RTE_IAE
1557 if( nSettle >= nMat || CHK_Freq )
1558 THROW_IAE;
1560 ScaDate aSettle( nNullDate, nSettle, nBase );
1561 ScaDate aDate;
1562 lcl_GetCouppcd( aDate, aSettle, ScaDate( nNullDate, nMat, nBase ), nFreq );
1563 return ScaDate::getDiff( aDate, aSettle );
1567 //-------
1568 // COUPDAYSNC: get day count: settlement <-> coupon date after settlement
1569 double GetCoupdaysnc( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nFreq, sal_Int32 nBase )
1570 THROWDEF_RTE_IAE
1572 if( nSettle >= nMat || CHK_Freq )
1573 THROW_IAE;
1575 if( (nBase != 0) && (nBase != 4) )
1577 ScaDate aSettle( nNullDate, nSettle, nBase );
1578 ScaDate aDate;
1579 lcl_GetCoupncd( aDate, aSettle, ScaDate( nNullDate, nMat, nBase ), nFreq );
1580 return ScaDate::getDiff( aSettle, aDate );
1582 return GetCoupdays( nNullDate, nSettle, nMat, nFreq, nBase ) - GetCoupdaybs( nNullDate, nSettle, nMat, nFreq, nBase );
1586 //-------
1587 // COUPDAYS: get day count: coupon date before settlement <-> coupon date after settlement
1588 double GetCoupdays( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nFreq, sal_Int32 nBase )
1589 THROWDEF_RTE_IAE
1591 if( nSettle >= nMat || CHK_Freq )
1592 THROW_IAE;
1594 if( nBase == 1 )
1596 ScaDate aDate;
1597 lcl_GetCouppcd( aDate, ScaDate( nNullDate, nSettle, nBase ), ScaDate( nNullDate, nMat, nBase ), nFreq );
1598 ScaDate aNextDate( aDate );
1599 aNextDate.addMonths( 12 / nFreq );
1600 return ScaDate::getDiff( aDate, aNextDate );
1602 return static_cast< double >( GetDaysInYear( 0, 0, nBase ) ) / nFreq;
1606 //-------
1607 // COUPNUM: get count of coupon dates
1608 double GetCoupnum( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nFreq, sal_Int32 nBase )
1609 THROWDEF_RTE_IAE
1611 if( nSettle >= nMat || CHK_Freq )
1612 THROW_IAE;
1614 ScaDate aMat( nNullDate, nMat, nBase );
1615 ScaDate aDate;
1616 lcl_GetCouppcd( aDate, ScaDate( nNullDate, nSettle, nBase ), aMat, nFreq );
1617 sal_uInt16 nMonths = (aMat.getYear() - aDate.getYear()) * 12 + aMat.getMonth() - aDate.getMonth();
1618 return static_cast< double >( nMonths * nFreq / 12 );
1627 const sal_uInt32 MyList::nStartSize = 16;
1628 const sal_uInt32 MyList::nIncrSize = 16;
1631 void MyList::_Grow( void )
1633 nSize += nIncrSize;
1635 void** pNewData = new void*[ nSize ];
1636 memcpy( pNewData, pData, nNew * sizeof( void* ) );
1638 delete[] pData;
1639 pData = pNewData;
1643 MyList::MyList( void )
1645 nSize = nStartSize;
1646 pData = new void*[ nSize ];
1647 nNew = nAct = 0;
1651 MyList::~MyList()
1653 delete[] pData;
1657 void MyList::Insert( void* p, sal_uInt32 n )
1659 if( n >= nNew )
1660 Append( p );
1661 else
1663 Grow();
1665 void** pIns = pData + n;
1666 memmove( pIns + 1, pIns, ( nNew - n ) * sizeof( void* ) );
1668 *pIns = p;
1670 nNew++;
1677 StringList::~StringList()
1679 for( STRING* p = ( STRING* ) First() ; p ; p = ( STRING* ) Next() )
1680 delete p;
1684 class AnalysisRscStrArrLoader : public Resource
1686 private:
1687 ResStringArray aStrArray;
1688 public:
1689 AnalysisRscStrArrLoader( sal_uInt16 nRsc, sal_uInt16 nArrayId, ResMgr& rResMgr ) :
1690 Resource( AnalysisResId( nRsc, rResMgr ) ),
1691 aStrArray( AnalysisResId( nArrayId, rResMgr ) )
1693 FreeResource();
1696 const ResStringArray& GetStringArray() const { return aStrArray; }
1702 FuncData::FuncData( const FuncDataBase& r, ResMgr& rResMgr ) :
1703 aIntName( OUString::createFromAscii( r.pIntName ) ),
1704 nUINameID( r.nUINameID ),
1705 nDescrID( r.nDescrID ),
1706 bDouble( r.bDouble ),
1707 bWithOpt( r.bWithOpt ),
1708 nParam( r.nNumOfParams ),
1709 nCompID( r.nCompListID ),
1710 eCat( r.eCat )
1712 AnalysisRscStrArrLoader aArrLoader( RID_ANALYSIS_DEFFUNCTION_NAMES, nCompID, rResMgr );
1713 // ResStringArray aDefFuncNameArray( AnalysisResId( nCompID, rResMgr ) );
1714 const ResStringArray& rArr = aArrLoader.GetStringArray();
1716 sal_uInt16 nCount = sal::static_int_cast<sal_uInt16>( rArr.Count() );
1717 sal_uInt16 n;
1719 for( n = 0 ; n < nCount ; n++ )
1720 aCompList.Append( rArr.GetString( n ) );
1724 FuncData::~FuncData()
1729 sal_uInt16 FuncData::GetStrIndex( sal_uInt16 nParamNum ) const
1731 if( !bWithOpt )
1732 nParamNum++;
1734 if( nParamNum > nParam )
1735 return nParam * 2;
1736 else
1737 return nParamNum * 2;
1743 FuncDataList::FuncDataList( ResMgr& rResMgr )
1745 const sal_uInt32 nNum = sizeof( pFuncDatas ) / sizeof( FuncDataBase );
1747 for( sal_uInt16 n = 0 ; n < nNum ; n++ )
1748 Append( new FuncData( pFuncDatas[ n ], rResMgr ) );
1752 FuncDataList::~FuncDataList()
1754 for( FuncData* p = ( FuncData* ) First() ; p ; p = ( FuncData* ) Next() )
1755 delete p;
1759 const FuncData* FuncDataList::Get( const OUString& aProgrammaticName ) const
1761 if( aLastName == aProgrammaticName )
1762 return Get( nLast );
1764 ( ( FuncDataList* ) this )->aLastName = aProgrammaticName;
1766 sal_uInt32 nE = Count();
1767 for( sal_uInt32 n = 0 ; n < nE ; n++ )
1769 const FuncData* p = Get( n );
1770 if( p->Is( aProgrammaticName ) )
1772 ( ( FuncDataList* ) this )->nLast = n;
1773 return p;
1777 ( ( FuncDataList* ) this )->nLast = 0xFFFFFFFF;
1778 return NULL;
1782 AnalysisResId::AnalysisResId( sal_uInt16 nId, ResMgr& rResMgr ) : ResId( nId, rResMgr )
1789 SortedIndividualInt32List::SortedIndividualInt32List()
1794 SortedIndividualInt32List::~SortedIndividualInt32List()
1799 void SortedIndividualInt32List::Insert( sal_Int32 nDay )
1801 sal_uInt32 nIndex = Count();
1802 while( nIndex )
1804 nIndex--;
1805 sal_Int32 nRef = Get( nIndex );
1806 if( nDay == nRef )
1807 return;
1808 else if( nDay > nRef )
1810 MyList::Insert( (void*) nDay, nIndex + 1 );
1811 return;
1814 MyList::Insert( (void*) nDay, 0UL );
1818 void SortedIndividualInt32List::Insert( sal_Int32 nDay, sal_Int32 nNullDate, sal_Bool bInsertOnWeekend )
1820 if( !nDay )
1821 return;
1823 nDay += nNullDate;
1824 if( bInsertOnWeekend || (GetDayOfWeek( nDay ) < 5) )
1825 Insert( nDay );
1829 void SortedIndividualInt32List::Insert(
1830 double fDay, sal_Int32 nNullDate, sal_Bool bInsertOnWeekend ) throw( uno::RuntimeException, lang::IllegalArgumentException )
1832 if( (fDay < -2147483648.0) || (fDay > 2147483649.0) )
1833 throw lang::IllegalArgumentException();
1834 Insert( static_cast< sal_Int32 >( fDay ), nNullDate, bInsertOnWeekend );
1838 sal_Bool SortedIndividualInt32List::Find( sal_Int32 nVal ) const
1840 sal_uInt32 nE = Count();
1842 if( !nE || nVal < Get( 0 ) || nVal > Get( nE - 1 ) )
1843 return sal_False;
1845 // linear search
1847 for( sal_uInt32 n = 0 ; n < nE ; n++ )
1849 sal_Int32 nRef = Get( n );
1851 if( nRef == nVal )
1852 return sal_True;
1853 else if( nRef > nVal )
1854 return sal_False;
1856 return sal_False;
1860 void SortedIndividualInt32List::InsertHolidayList(
1861 const ScaAnyConverter& rAnyConv,
1862 const uno::Any& rHolAny,
1863 sal_Int32 nNullDate,
1864 sal_Bool bInsertOnWeekend ) throw( uno::RuntimeException, lang::IllegalArgumentException )
1866 double fDay;
1867 if( rAnyConv.getDouble( fDay, rHolAny ) )
1868 Insert( fDay, nNullDate, bInsertOnWeekend );
1872 void SortedIndividualInt32List::InsertHolidayList(
1873 ScaAnyConverter& rAnyConv,
1874 const uno::Reference< beans::XPropertySet >& xOptions,
1875 const uno::Any& rHolAny,
1876 sal_Int32 nNullDate,
1877 sal_Bool bInsertOnWeekend ) throw( uno::RuntimeException, lang::IllegalArgumentException )
1879 rAnyConv.init( xOptions );
1880 if( rHolAny.getValueTypeClass() == uno::TypeClass_SEQUENCE )
1882 uno::Sequence< uno::Sequence< uno::Any > > aAnySeq;
1883 if( rHolAny >>= aAnySeq )
1885 const uno::Sequence< uno::Any >* pSeqArray = aAnySeq.getConstArray();
1886 for( sal_Int32 nIndex1 = 0; nIndex1 < aAnySeq.getLength(); nIndex1++ )
1888 const uno::Sequence< uno::Any >& rSubSeq = pSeqArray[ nIndex1 ];
1889 const uno::Any* pAnyArray = rSubSeq.getConstArray();
1891 for( sal_Int32 nIndex2 = 0; nIndex2 < rSubSeq.getLength(); nIndex2++ )
1892 InsertHolidayList( rAnyConv, pAnyArray[ nIndex2 ], nNullDate, bInsertOnWeekend );
1895 else
1896 throw lang::IllegalArgumentException();
1898 else
1899 InsertHolidayList( rAnyConv, rHolAny, nNullDate, bInsertOnWeekend );
1904 //-----------------------------------------------------------------------------
1906 ScaDoubleList::~ScaDoubleList()
1908 for( double* pDbl = const_cast< double* >( First() ); pDbl; pDbl = const_cast< double* >( Next() ) )
1909 delete pDbl;
1913 void ScaDoubleList::Append(
1914 const uno::Sequence< uno::Sequence< double > >& rValueSeq ) throw( uno::RuntimeException, lang::IllegalArgumentException )
1916 const uno::Sequence< double >* pSeqArray = rValueSeq.getConstArray();
1917 for( sal_Int32 nIndex1 = 0; nIndex1 < rValueSeq.getLength(); nIndex1++ )
1919 const uno::Sequence< double >& rSubSeq = pSeqArray[ nIndex1 ];
1920 const double* pArray = rSubSeq.getConstArray();
1921 for( sal_Int32 nIndex2 = 0; nIndex2 < rSubSeq.getLength(); nIndex2++ )
1922 Append( pArray[ nIndex2 ] );
1927 void ScaDoubleList::Append(
1928 const uno::Sequence< uno::Sequence< sal_Int32 > >& rValueSeq ) throw( uno::RuntimeException, lang::IllegalArgumentException )
1930 const uno::Sequence< sal_Int32 >* pSeqArray = rValueSeq.getConstArray();
1931 for( sal_Int32 nIndex1 = 0; nIndex1 < rValueSeq.getLength(); nIndex1++ )
1933 const uno::Sequence< sal_Int32 >& rSubSeq = pSeqArray[ nIndex1 ];
1934 const sal_Int32* pArray = rSubSeq.getConstArray();
1935 for( sal_Int32 nIndex2 = 0; nIndex2 < rSubSeq.getLength(); nIndex2++ )
1936 Append( pArray[ nIndex2 ] );
1942 void ScaDoubleList::Append(
1943 const ScaAnyConverter& rAnyConv,
1944 const uno::Any& rAny,
1945 sal_Bool bIgnoreEmpty ) throw( uno::RuntimeException, lang::IllegalArgumentException )
1947 if( rAny.getValueTypeClass() == uno::TypeClass_SEQUENCE )
1948 Append( rAnyConv, *static_cast< const uno::Sequence< uno::Sequence< uno::Any > >* >( rAny.getValue() ), bIgnoreEmpty );
1949 else
1951 double fValue;
1952 if( rAnyConv.getDouble( fValue, rAny ) )
1953 Append( fValue );
1954 else if( !bIgnoreEmpty )
1955 Append( 0.0 );
1960 void ScaDoubleList::Append(
1961 const ScaAnyConverter& rAnyConv,
1962 const uno::Sequence< uno::Any >& rAnySeq,
1963 sal_Bool bIgnoreEmpty ) throw( uno::RuntimeException, lang::IllegalArgumentException )
1965 const uno::Any* pArray = rAnySeq.getConstArray();
1966 for( sal_Int32 nIndex = 0; nIndex < rAnySeq.getLength(); nIndex++ )
1967 Append( rAnyConv, pArray[ nIndex ], bIgnoreEmpty );
1971 void ScaDoubleList::Append(
1972 const ScaAnyConverter& rAnyConv,
1973 const uno::Sequence< uno::Sequence< uno::Any > >& rAnySeq,
1974 sal_Bool bIgnoreEmpty ) throw( uno::RuntimeException, lang::IllegalArgumentException )
1976 const uno::Sequence< uno::Any >* pArray = rAnySeq.getConstArray();
1977 for( sal_Int32 nIndex = 0; nIndex < rAnySeq.getLength(); nIndex++ )
1978 Append( rAnyConv, pArray[ nIndex ], bIgnoreEmpty );
1983 void ScaDoubleList::Append(
1984 ScaAnyConverter& rAnyConv,
1985 const uno::Reference< beans::XPropertySet >& xOpt,
1986 const uno::Sequence< uno::Any >& rAnySeq,
1987 sal_Bool bIgnoreEmpty ) throw( uno::RuntimeException, lang::IllegalArgumentException )
1989 rAnyConv.init( xOpt );
1990 Append( rAnyConv, rAnySeq, bIgnoreEmpty );
1994 sal_Bool ScaDoubleList::CheckInsert( double ) const throw( uno::RuntimeException, lang::IllegalArgumentException )
1996 return sal_True;
2001 //-----------------------------------------------------------------------------
2003 sal_Bool ScaDoubleListGT0::CheckInsert( double fValue ) const throw( uno::RuntimeException, lang::IllegalArgumentException )
2005 if( fValue < 0.0 )
2006 throw lang::IllegalArgumentException();
2007 return fValue > 0.0;
2012 //-----------------------------------------------------------------------------
2014 sal_Bool ScaDoubleListGE0::CheckInsert( double fValue ) const throw( uno::RuntimeException, lang::IllegalArgumentException )
2016 if( fValue < 0.0 )
2017 throw lang::IllegalArgumentException();
2018 return sal_True;
2023 //-----------------------------------------------------------------------------
2025 Complex::Complex( const STRING& rStr ) THROWDEF_RTE_IAE
2027 if( !ParseString( rStr, *this ) )
2028 THROW_IAE;
2032 inline sal_Bool Complex::IsImagUnit( sal_Unicode c )
2034 return c == 'i' || c == 'j';
2037 sal_Bool Complex::ParseString( const STRING& rStr, Complex& rCompl )
2039 rCompl.c = '\0'; // do not force a symbol, if only real part present
2041 const sal_Unicode* pStr = ( const sal_Unicode * ) rStr;
2043 if( IsImagUnit( *pStr ) && rStr.getLength() == 1)
2045 rCompl.r = 0.0;
2046 rCompl.i = 1.0;
2047 rCompl.c = *pStr;
2048 return sal_True;
2051 double f;
2053 if( !ParseDouble( pStr, f ) )
2054 return sal_False;
2056 switch( *pStr )
2058 case '-': // imag part follows
2059 case '+':
2061 double r = f;
2062 if( IsImagUnit( pStr[ 1 ] ) )
2064 rCompl.c = pStr[ 1 ];
2065 if( pStr[ 2 ] == 0 )
2067 rCompl.r = f;
2068 rCompl.i = ( *pStr == '+' )? 1.0 : -1.0;
2069 return sal_True;
2072 else if( ParseDouble( pStr, f ) && IsImagUnit( *pStr ) )
2074 rCompl.c = *pStr;
2075 pStr++;
2076 if( *pStr == 0 )
2078 rCompl.r = r;
2079 rCompl.i = f;
2080 return sal_True;
2084 break;
2085 case 'j':
2086 case 'i':
2087 rCompl.c = *pStr;
2088 pStr++;
2089 if( *pStr == 0 )
2091 rCompl.i = f;
2092 rCompl.r = 0.0;
2093 return sal_True;
2095 break;
2096 case 0: // only real-part
2097 rCompl.r = f;
2098 rCompl.i = 0.0;
2099 return sal_True;
2102 return sal_False;
2106 STRING Complex::GetString() const THROWDEF_RTE_IAE
2108 static const String aI( 'i' );
2109 static const String aJ( 'j' );
2110 static const String aPlus( '+' );
2111 static const String aMinus( '-' );
2113 CHK_FINITE(r);
2114 CHK_FINITE(i);
2115 STRING aRet;
2117 bool bHasImag = i != 0.0;
2118 bool bHasReal = !bHasImag || (r != 0.0);
2120 if( bHasReal )
2121 aRet = ::GetString( r );
2122 if( bHasImag )
2124 if( i == 1.0 )
2126 if( bHasReal )
2127 aRet += aPlus;
2129 else if( i == -1.0 )
2130 aRet += aMinus;
2131 else
2132 aRet += ::GetString( i, bHasReal );
2133 aRet += (c != 'j') ? aI : aJ;
2136 return aRet;
2140 double Complex::Arg( void ) const THROWDEF_RTE_IAE
2142 if( r == 0.0 && i == 0.0 )
2143 THROW_IAE;
2145 double phi = acos( r / Abs() );
2147 if( i < 0.0 )
2148 phi = -phi;
2150 return phi;
2154 void Complex::Power( double fPower ) THROWDEF_RTE_IAE
2156 if( r == 0.0 && i == 0.0 )
2158 if( fPower > 0 )
2160 r = i = 0.0;
2161 return;
2163 else
2164 THROW_IAE;
2167 double p, phi;
2169 p = Abs();
2171 phi = acos( r / p );
2172 if( i < 0.0 )
2173 phi = -phi;
2175 p = pow( p, fPower );
2176 phi *= fPower;
2178 r = cos( phi ) * p;
2179 i = sin( phi ) * p;
2183 void Complex::Sqrt( void )
2185 static const double fMultConst = 0.7071067811865475; // ...2440084436210485 = 1/sqrt(2)
2186 double p = Abs();
2187 double i_ = sqrt( p - r ) * fMultConst;
2189 r = sqrt( p + r ) * fMultConst;
2190 i = ( i < 0.0 )? -i_ : i_;
2194 inline BOOL SinOverflow( double f )
2196 return fabs( f ) >= 134217728;
2200 void Complex::Sin( void ) THROWDEF_RTE_IAE
2202 if( SinOverflow( r ) )
2203 THROW_IAE;
2205 if( i )
2207 double r_;
2209 r_ = sin( r ) * cosh( i );
2210 i = cos( r ) * sinh( i );
2211 r = r_;
2213 else
2214 r = sin( r );
2218 void Complex::Cos( void ) THROWDEF_RTE_IAE
2220 if( SinOverflow( r ) )
2221 THROW_IAE;
2223 if( i )
2225 double r_;
2227 r_ = cos( r ) * cosh( i );
2228 i = -( sin( r ) * sinh( i ) );
2229 r = r_;
2231 else
2232 r = cos( r );
2236 void Complex::Div( const Complex& z ) THROWDEF_RTE_IAE
2238 if( z.r == 0 && z.i == 0 )
2239 THROW_IAE;
2241 double a1 = r;
2242 double a2 = z.r;
2243 double b1 = i;
2244 double b2 = z.i;
2246 double f = 1.0 / ( a2 * a2 + b2 * b2 );
2248 r = ( a1 * a2 + b1 * b2 ) * f;
2249 i = ( a2 * b1 - a1 * b2 ) * f;
2251 if( !c ) c = z.c;
2255 void Complex::Exp( void )
2257 double fE = exp( r );
2258 r = fE * cos( i );
2259 i = fE * sin( i );
2263 void Complex::Ln( void ) THROWDEF_RTE_IAE
2265 if( r == 0.0 && i == 0.0 )
2266 THROW_IAE;
2268 double fAbs = Abs();
2269 sal_Bool bNegi = i < 0.0;
2271 i = acos( r / fAbs );
2273 if( bNegi )
2274 i = -i;
2276 r = log( fAbs );
2280 void Complex::Log10( void ) THROWDEF_RTE_IAE
2282 Ln();
2283 Mult( 0.434294481903251828 ); // * log10( e )
2287 void Complex::Log2( void ) THROWDEF_RTE_IAE
2289 Ln();
2290 Mult( 1.442695040888963407 ); // * log2( e )
2296 ComplexList::~ComplexList()
2298 for( Complex* p = ( Complex* ) First() ; p ; p = ( Complex* ) Next() )
2299 delete p;
2303 void ComplexList::Append( const SEQSEQ( STRING )& r, ComplListAppendHandl eAH ) THROWDEF_RTE_IAE
2305 sal_Int32 n1, n2;
2306 sal_Int32 nE1 = r.getLength();
2307 sal_Int32 nE2;
2308 sal_Bool bEmpty0 = eAH == AH_EmpyAs0;
2309 sal_Bool bErrOnEmpty = eAH == AH_EmptyAsErr;
2311 for( n1 = 0 ; n1 < nE1 ; n1++ )
2313 const SEQ( STRING )& rList = r[ n1 ];
2314 nE2 = rList.getLength();
2316 for( n2 = 0 ; n2 < nE2 ; n2++ )
2318 const STRING& rStr = rList[ n2 ];
2320 if( rStr.getLength() )
2321 Append( new Complex( rStr ) );
2322 else if( bEmpty0 )
2323 Append( new Complex( 0.0 ) );
2324 else if( bErrOnEmpty )
2325 THROW_IAE;
2331 void ComplexList::Append( const SEQ( ANY )& aMultPars, ComplListAppendHandl eAH ) THROWDEF_RTE_IAE
2333 sal_Int32 nEle = aMultPars.getLength();
2334 sal_Bool bEmpty0 = eAH == AH_EmpyAs0;
2335 sal_Bool bErrOnEmpty = eAH == AH_EmptyAsErr;
2337 for( sal_Int32 i = 0 ; i < nEle ; i++ )
2339 const ANY& r = aMultPars[ i ];
2340 switch( r.getValueTypeClass() )
2342 case uno::TypeClass_VOID: break;
2343 case uno::TypeClass_STRING:
2345 const STRING* pStr = ( const STRING* ) r.getValue();
2347 if( pStr->getLength() )
2348 Append( new Complex( *( STRING* ) r.getValue() ) );
2349 else if( bEmpty0 )
2350 Append( new Complex( 0.0 ) );
2351 else if( bErrOnEmpty )
2352 THROW_IAE;
2354 break;
2355 case uno::TypeClass_DOUBLE:
2356 Append( new Complex( *( double* ) r.getValue(), 0.0 ) );
2357 break;
2358 case uno::TypeClass_SEQUENCE:
2360 SEQSEQ( ANY ) aValArr;
2361 if( r >>= aValArr )
2363 sal_Int32 nE = aValArr.getLength();
2364 const SEQ( ANY )* pArr = aValArr.getConstArray();
2365 for( sal_Int32 n = 0 ; n < nE ; n++ )
2366 Append( pArr[ n ], eAH );
2368 else
2369 THROW_IAE;
2371 break;
2372 default:
2373 THROW_IAE;
2381 ConvertData::ConvertData( const sal_Char p[], double fC, ConvertDataClass e ) : aName( p, strlen( p ), RTL_TEXTENCODING_MS_1252 )
2383 fConst = fC;
2384 eClass = e;
2387 ConvertData::~ConvertData()
2392 sal_Int16 ConvertData::GetMatchingLevel( const STRING& rRef ) const
2394 if( aName.equals( rRef ) )
2395 return 0;
2396 else
2398 const sal_Unicode* p = rRef.getStr();
2400 if ( aName == p + 1 )
2402 sal_Int16 n;
2403 switch( *p )
2405 case 'y': n = -24; break; // yocto
2406 case 'z': n = -21; break; // zepto
2407 case 'a': n = -18; break;
2408 case 'f': n = -15; break;
2409 case 'p': n = -12; break;
2410 case 'n': n = -9; break;
2411 case 'u': n = -6; break;
2412 case 'm': n = -3; break;
2413 case 'c': n = -2; break;
2414 case 'd': n = -1; break;
2415 case 'e': n = 1; break;
2416 case 'h': n = 2; break;
2417 case 'k': n = 3; break;
2418 case 'M': n = 6; break;
2419 case 'G': n = 9; break;
2420 case 'T': n = 12; break;
2421 case 'P': n = 15; break;
2422 case 'E': n = 18; break;
2423 case 'Z': n = 21; break; // zetta
2424 case 'Y': n = 24; break; // yotta
2425 default:
2426 n = INV_MATCHLEV;
2429 //! <HACK> #100616# "cm3" is not 10^-2 m^3 but 10^-6 m^3 !!! ------------------
2430 if( n != INV_MATCHLEV )
2432 sal_Unicode cLast = p[ rRef.getLength() - 1 ];
2433 if( cLast == '2' )
2434 n *= 2;
2435 else if( cLast == '3' )
2436 n *= 3;
2438 //! </HACK> -------------------------------------------------------------------
2440 return n;
2442 else
2443 return INV_MATCHLEV;
2448 double ConvertData::Convert(
2449 double f, const ConvertData& r, sal_Int16 nLevFrom, sal_Int16 nLevTo ) const THROWDEF_RTE_IAE
2451 if( Class() != r.Class() )
2452 THROW_IAE;
2454 nLevFrom = sal::static_int_cast<sal_Int16>( nLevFrom - nLevTo ); // effective level
2456 f *= r.fConst / fConst;
2458 if( nLevFrom )
2459 f = ::rtl::math::pow10Exp( f, nLevFrom );
2461 return f;
2465 double ConvertData::ConvertToBase( double f, sal_Int16 n ) const
2467 return ::rtl::math::pow10Exp( f / fConst, n );
2471 double ConvertData::ConvertFromBase( double f, sal_Int16 n ) const
2473 return ::rtl::math::pow10Exp( f * fConst, -n );
2478 ConvertDataLinear::~ConvertDataLinear()
2482 double ConvertDataLinear::Convert(
2483 double f, const ConvertData& r, sal_Int16 nLevFrom, sal_Int16 nLevTo ) const THROWDEF_RTE_IAE
2485 if( Class() != r.Class() )
2486 THROW_IAE;
2488 // return ::rtl::math::round( r.ConvertFromBase( ConvertToBase( f, nLevFrom ), nLevTo ), 13 );
2489 return r.ConvertFromBase( ConvertToBase( f, nLevFrom ), nLevTo );
2493 double ConvertDataLinear::ConvertToBase( double f, sal_Int16 n ) const
2495 if( n )
2496 f = ::rtl::math::pow10Exp( f, n );
2498 f /= fConst;
2499 f -= fOffs;
2501 return f;
2505 double ConvertDataLinear::ConvertFromBase( double f, sal_Int16 n ) const
2507 f += fOffs;
2508 f *= fConst;
2510 if( n )
2511 f = ::rtl::math::pow10Exp( f, -n );
2513 return f;
2519 ConvertDataList::ConvertDataList( void )
2521 #define NEWD(str,unit,cl) Append(new ConvertData(str,unit,cl))
2522 #define NEWL(str,unit,offs,cl) Append(new ConvertDataLinear(str,unit,offs,cl))
2524 // *** are extra and not standard Excel Analysis Addin!
2526 // MASS: 1 Gram is...
2527 NEWD( "g", 1.0000000000000000E00, CDC_Mass ); // Gram
2528 NEWD( "sg", 6.8522050005347800E-05, CDC_Mass ); // Pieces
2529 NEWD( "lbm", 2.2046229146913400E-03, CDC_Mass ); // Pound (commercial weight)
2530 NEWD( "u", 6.0221370000000000E23, CDC_Mass ); // U (atomic mass)
2531 NEWD( "ozm", 3.5273971800362700E-02, CDC_Mass ); // Ounce (commercial weight)
2532 NEWD( "stone", 1.574730e-04, CDC_Mass ); // *** Stone
2533 NEWD( "ton", 1.102311e-06, CDC_Mass ); // *** Ton
2534 NEWD( "grain", 1.543236E01, CDC_Mass ); // *** Grain
2535 NEWD( "pweight", 7.054792E-01, CDC_Mass ); // *** Pennyweight
2536 NEWD( "hweight", 1.968413E-05, CDC_Mass ); // *** Hundredweight
2537 NEWD( "shweight", 2.204623E-05, CDC_Mass ); // *** Shorthundredweight
2538 NEWD( "brton", 9.842065E-07, CDC_Mass ); // *** Gross Registered Ton
2540 // LENGTH: 1 Meter is...
2541 NEWD( "m", 1.0000000000000000E00, CDC_Length ); // Meter
2542 NEWD( "mi", 6.2137119223733397E-04, CDC_Length ); // Britsh Mile 6,21371192237333969617434184363e-4
2543 NEWD( "Nmi", 5.3995680345572354E-04, CDC_Length ); // Nautical Mile 5,39956803455723542116630669546e-4
2544 NEWD( "in", 3.9370078740157480E01, CDC_Length ); // Inch 39,37007874015748031496062992126
2545 NEWD( "ft", 3.2808398950131234E00, CDC_Length ); // Foot 3,2808398950131233595800524934383
2546 NEWD( "yd", 1.0936132983377078E00, CDC_Length ); // Yard 1,0936132983377077865266841644794
2547 NEWD( "ang", 1.0000000000000000E10, CDC_Length ); // Angstroem
2548 NEWD( "Pica", 2.8346456692913386E03, CDC_Length ); // Pica (1/72 Inch) 2834,6456692913385826771653543307
2549 NEWD( "ell", 8.748906E-01, CDC_Length ); // *** Ell
2550 NEWD( "parsec", 3.240779E-17, CDC_Length ); // *** Parsec
2551 NEWD( "lightyear", 1.0570234557732930E-16, CDC_Length ); // *** Light Year
2553 // TIME: 1 Second is...
2554 NEWD( "yr", 3.1688087814028950E-08, CDC_Time ); // Year
2555 NEWD( "day", 1.1574074074074074E-05, CDC_Time ); // Day
2556 NEWD( "hr", 2.7777777777777778E-04, CDC_Time ); // Hour
2557 NEWD( "mn", 1.6666666666666667E-02, CDC_Time ); // Minute
2558 NEWD( "sec", 1.0000000000000000E00, CDC_Time ); // Second
2560 // PRESSURE: 1 Pascal is...
2561 NEWD( "Pa", 1.0000000000000000E00, CDC_Pressure ); // Pascal
2562 NEWD( "atm", 9.8692329999819300E-06, CDC_Pressure ); // Atmoshpere
2563 NEWD( "mmHg", 7.5006170799862700E-03, CDC_Pressure ); // mm Hg (Mercury)
2564 NEWD( "Torr", 7.5006380000000000E-03, CDC_Pressure ); // *** Torr
2565 NEWD( "psi", 1.4503770000000000E-04, CDC_Pressure ); // *** Psi
2567 // FORCE: 1 Newton is...
2568 NEWD( "N", 1.0000000000000000E00, CDC_Force ); // Newton
2569 NEWD( "dyn", 1.0000000000000000E05, CDC_Force ); // Dyn
2570 NEWD( "lbf", 2.24808923655339E-01, CDC_Force ); // Pound-Force
2571 NEWD( "pond", 1.019716E02, CDC_Force ); // *** Pond
2573 // ENERGY: 1 Joule is...
2574 NEWD( "J", 1.0000000000000000E00, CDC_Energy ); // Joule
2575 NEWD( "e", 1.0000000000000000E07, CDC_Energy ); // Erg -> http://www.chemie.fu-berlin.de/chemistry/general/si.html
2576 // NEWD( "e", 9.99999519343231E06, CDC_Energy ); // Erg
2577 NEWD( "c", 2.3900624947346700E-01, CDC_Energy ); // Thermodynamical Calorie
2578 NEWD( "cal", 2.3884619064201700E-01, CDC_Energy ); // Calorie
2579 NEWD( "eV", 6.2414570000000000E18, CDC_Energy ); // Electronvolt
2580 NEWD( "HPh", 3.7250611111111111E-07, CDC_Energy ); // Horsepower Hours
2581 // NEWD( "HPh", 3.72506430801000E-07, CDC_Energy ); // Horsepower Hours
2582 NEWD( "Wh", 2.7777777777777778E-04, CDC_Energy ); // Watt Hours
2583 NEWD( "flb", 2.37304222192651E01, CDC_Energy ); // Foot Pound
2584 NEWD( "BTU", 9.4781506734901500E-04, CDC_Energy ); // British Thermal Unit
2586 // POWER: 1 Watt is...
2587 NEWD( "W", 1.0000000000000000E00, CDC_Power ); // Watt
2588 NEWD( "HP", 1.341022E-03, CDC_Power ); // Horsepower
2589 NEWD( "PS", 1.359622E-03, CDC_Power ); // *** German Pferdestaerke
2590 // NEWD( "HP", 1.4102006031908E-03, CDC_Power ); // Excel seams to be a little bit wrong... either this doesn't fit to J -> HPh
2592 // MAGNETISM: 1 Tesla is...
2593 NEWD( "T", 1.0000000000000000E00, CDC_Magnetism ); // Tesla
2594 NEWD( "ga", 1.0000000000000000E04, CDC_Magnetism ); // Gauss
2596 // TEMERATURE: 1 Kelvin is...
2597 NEWL( "C", 1.0000000000000000E00, -2.7315000000000000E02, CDC_Temperature ); // Celsius
2598 NEWL( "F", 1.8000000000000000E00, -2.5537222222222222E02, CDC_Temperature ); // Fahrenheit
2599 NEWL( "K", 1.0000000000000000E00, +0.0000000000000000E00, CDC_Temperature ); // Kelvin
2600 NEWL( "Reau", 8.0000000000000000E-01, -2.7315000000000000E02, CDC_Temperature ); // *** Reaumur
2601 NEWL( "Rank", 1.8000000000000000E00, +0.0000000000000000E00, CDC_Temperature ); // *** Rankine
2603 // VOLUMNE: 1 Liter is...
2604 NEWD( "tsp", 2.0284000000000000E02, CDC_Volume ); // Teaspoon
2605 NEWD( "tbs", 6.7613333333333333E01, CDC_Volume ); // Tablespoon
2606 NEWD( "oz", 3.3806666666666667E01, CDC_Volume ); // Ounce Liquid
2607 NEWD( "cup", 4.2258333333333333E00, CDC_Volume ); // Cup
2608 NEWD( "pt", 2.1129166666666667E00, CDC_Volume ); // US Pint
2609 NEWD( "uk_pt", 1.75975569552166E00, CDC_Volume ); // UK Pint
2610 NEWD( "qt", 1.0564583333333333E00, CDC_Volume ); // Quart
2611 NEWD( "gal", 2.6411458333333333E-01, CDC_Volume ); // Gallone
2612 NEWD( "l", 1.0000000000000000E00, CDC_Volume ); // Liter
2613 NEWD( "m3", 1.0000000000000000E-03, CDC_Volume ); // *** Cubic Meter
2614 NEWD( "mi3", 2.3991275857892772E-13, CDC_Volume ); // *** Cubic Britsh Mile
2615 NEWD( "Nmi3", 1.5742621468581148E-13, CDC_Volume ); // *** Cubic Nautical Mile
2616 NEWD( "in3", 6.1023744094732284E01, CDC_Volume ); // *** Cubic Inch
2617 NEWD( "ft3", 3.5314666721488590E-02, CDC_Volume ); // *** Cubic Foot
2618 NEWD( "yd3", 1.3079506193143922E-03, CDC_Volume ); // *** Cubic Yard
2619 NEWD( "ang3", 1.0000000000000000E27, CDC_Volume ); // *** Cubic Angstroem
2620 NEWD( "Pica3", 2.2776990435870636E07, CDC_Volume ); // *** Cubic Pica
2621 NEWD( "barrel", 6.289811E-03, CDC_Volume ); // *** Barrel (=42gal?)
2622 NEWD( "bushel", 2.837759E-02, CDC_Volume ); // *** Bushel
2623 NEWD( "regton", 3.531467E-04, CDC_Volume ); // *** Register ton
2624 NEWD( "Schooner", 2.3529411764705882E00, CDC_Volume ); // *** austr. Schooner
2625 NEWD( "Middy", 3.5087719298245614E00, CDC_Volume ); // *** austr. Middy
2626 NEWD( "Glass", 5.0000000000000000E00, CDC_Volume ); // *** austr. Glass
2627 NEWD( "Sixpack", 0.5, CDC_Volume ); // ***
2628 NEWD( "Humpen", 2.0, CDC_Volume ); // ***
2630 // 1 Square Meter is...
2631 NEWD( "m2", 1.0000000000000000E00, CDC_Area ); // *** Square Meter
2632 NEWD( "mi2", 3.8610215854244585E-07, CDC_Area ); // *** Square Britsh Mile
2633 NEWD( "Nmi2", 2.9155334959812286E-07, CDC_Area ); // *** Square Nautical Mile
2634 NEWD( "in2", 1.5500031000062000E03, CDC_Area ); // *** Square Inch
2635 NEWD( "ft2", 1.0763910416709722E01, CDC_Area ); // *** Square Foot
2636 NEWD( "yd2", 1.1959900463010803E00, CDC_Area ); // *** Square Yard
2637 NEWD( "ang2", 1.0000000000000000E20, CDC_Area ); // *** Square Angstroem
2638 NEWD( "Pica2", 8.0352160704321409E06, CDC_Area ); // *** Square Pica
2639 NEWD( "Morgen", 4.0000000000000000E-04, CDC_Area ); // *** Morgen
2640 NEWD( "ar", 1.000000E-02, CDC_Area ); // *** Ar
2641 NEWD( "acre", 2.471053815E-04, CDC_Area ); // *** Acre
2642 NEWD( "ha", 1.000000E-04, CDC_Area ); // *** Hectare
2643 NEWD( "Quadratlatschen",5.6689342403628117914,CDC_Area ); // ***
2645 // SPEED: 1 Meter per Second is...
2646 NEWD( "m/s", 1.0000000000000000E00, CDC_Speed ); // *** Meters per Second
2647 NEWD( "m/h", 3.6000000000000000E03, CDC_Speed ); // *** Meters per Hour
2648 NEWD( "mph", 2.2369362920544023E00, CDC_Speed ); // *** Britsh Miles per Hour
2649 NEWD( "kn", 1.9438444924406048E00, CDC_Speed ); // *** Knot = Nautical Miles per Hour
2650 NEWD( "admkn", 1.9438446603753486E00, CDC_Speed ); // *** Admiralty Knot
2651 NEWD( "wahnsinnige Geschwindigkeit", 2.0494886343432328E-14, CDC_Speed ); // ***
2652 NEWD( "ludicrous speed", 2.0494886343432328E-14, CDC_Speed ); // ***
2653 NEWD( "laecherliche Geschwindigkeit", 4.0156958471424288E-06, CDC_Speed); // ***
2654 NEWD( "ridiculous speed", 4.0156958471424288E-06, CDC_Speed); // ***
2658 ConvertDataList::~ConvertDataList()
2660 for( ConvertData* p = First() ; p ; p = Next() )
2661 delete p;
2665 double ConvertDataList::Convert( double fVal, const STRING& rFrom, const STRING& rTo ) THROWDEF_RTE_IAE
2667 // This will not catch illegal units
2668 // if( rFrom == rTo )
2669 // return fVal;
2671 ConvertData* pFrom = NULL;
2672 ConvertData* pTo = NULL;
2673 sal_Bool bSearchFrom = sal_True;
2674 sal_Bool bSearchTo = sal_True;
2675 sal_Int16 nLevelFrom = 0;
2676 sal_Int16 nLevelTo = 0;
2678 ConvertData* p = First();
2679 while( p && ( bSearchFrom || bSearchTo ) )
2681 if( bSearchFrom )
2683 sal_Int16 n = p->GetMatchingLevel( rFrom );
2684 if( n != INV_MATCHLEV )
2686 if( n )
2687 { // only first match for partial equality rulz a little bit more
2688 pFrom = p;
2689 nLevelFrom = n;
2691 else
2692 { // ... but exact match rulz most
2693 pFrom = p;
2694 bSearchFrom = sal_False;
2695 nLevelFrom = n;
2700 if( bSearchTo )
2702 sal_Int16 n = p->GetMatchingLevel( rTo );
2703 if( n != INV_MATCHLEV )
2705 if( n )
2706 { // only first match for partial equality rulz a little bit more
2707 pTo = p;
2708 nLevelTo = n;
2710 else
2711 { // ... but exact match rulz most
2712 pTo = p;
2713 bSearchTo = sal_False;
2714 nLevelTo = n;
2719 p = Next();
2722 if( pFrom && pTo )
2723 return pFrom->Convert( fVal, *pTo, nLevelFrom, nLevelTo );
2724 else
2725 THROW_IAE;
2730 //-----------------------------------------------------------------------------
2732 ScaDate::ScaDate() :
2733 nOrigDay( 1 ),
2734 nDay( 1 ),
2735 nMonth( 1 ),
2736 nYear( 1900 ),
2737 bLastDayMode( sal_True ),
2738 bLastDay( sal_False ),
2739 b30Days( sal_False ),
2740 bUSMode( sal_False )
2744 ScaDate::ScaDate( sal_Int32 nNullDate, sal_Int32 nDate, sal_Int32 nBase )
2746 DaysToDate( nNullDate + nDate, nOrigDay, nMonth, nYear );
2747 bLastDayMode = (nBase != 5);
2748 bLastDay = (nOrigDay >= ::DaysInMonth( nMonth, nYear ));
2749 b30Days = (nBase == 0) || (nBase == 4);
2750 bUSMode = (nBase == 0);
2751 setDay();
2754 ScaDate::ScaDate( const ScaDate& rCopy ) :
2755 nOrigDay( rCopy.nOrigDay ),
2756 nDay( rCopy.nDay ),
2757 nMonth( rCopy.nMonth ),
2758 nYear( rCopy.nYear ),
2759 bLastDayMode( rCopy.bLastDayMode ),
2760 bLastDay( rCopy.bLastDay ),
2761 b30Days( rCopy.b30Days ),
2762 bUSMode( rCopy.bUSMode )
2766 ScaDate& ScaDate::operator=( const ScaDate& rCopy )
2768 if( this != &rCopy )
2770 nOrigDay = rCopy.nOrigDay;
2771 nDay = rCopy.nDay;
2772 nMonth = rCopy.nMonth;
2773 nYear = rCopy.nYear;
2774 bLastDayMode = rCopy.bLastDayMode;
2775 bLastDay = rCopy.bLastDay;
2776 b30Days = rCopy.b30Days;
2777 bUSMode = rCopy.bUSMode;
2779 return *this;
2782 void ScaDate::setDay()
2784 if( b30Days )
2786 // 30-days-mode: set nDay to 30 if original was last day in month
2787 nDay = Min( nOrigDay, static_cast< sal_uInt16 >( 30 ) );
2788 if( bLastDay || (nDay >= ::DaysInMonth( nMonth, nYear )) )
2789 nDay = 30;
2791 else
2793 // set nDay to last day in this month if original was last day
2794 sal_uInt16 nLastDay = ::DaysInMonth( nMonth, nYear );
2795 nDay = bLastDay ? nLastDay : Min( nOrigDay, nLastDay );
2799 sal_Int32 ScaDate::getDaysInMonthRange( sal_uInt16 nFrom, sal_uInt16 nTo ) const
2801 if( nFrom > nTo )
2802 return 0;
2804 sal_Int32 nRet = 0;
2805 if( b30Days )
2806 nRet = (nTo - nFrom + 1) * 30;
2807 else
2809 for( sal_uInt16 nMonthIx = nFrom; nMonthIx <= nTo; ++nMonthIx )
2810 nRet += getDaysInMonth( nMonthIx );
2812 return nRet;
2815 sal_Int32 ScaDate::getDaysInYearRange( sal_uInt16 nFrom, sal_uInt16 nTo ) const
2817 if( nFrom > nTo )
2818 return 0;
2820 return b30Days ? ((nTo - nFrom + 1) * 360) : ::GetDaysInYears( nFrom, nTo );
2823 void ScaDate::doAddYears( sal_Int32 nYearCount ) throw( lang::IllegalArgumentException )
2825 sal_Int32 nNewYear = nYearCount + nYear;
2826 if( (nNewYear < 0) || (nNewYear > 0x7FFF) )
2827 throw lang::IllegalArgumentException();
2828 nYear = static_cast< sal_uInt16 >( nNewYear );
2831 void ScaDate::addMonths( sal_Int32 nMonthCount ) throw( lang::IllegalArgumentException )
2833 sal_Int32 nNewMonth = nMonthCount + nMonth;
2834 if( nNewMonth > 12 )
2836 --nNewMonth;
2837 doAddYears( nNewMonth / 12 );
2838 nMonth = static_cast< sal_uInt16 >( nNewMonth % 12 ) + 1;
2840 else if( nNewMonth < 1 )
2842 doAddYears( nNewMonth / 12 - 1 );
2843 nMonth = static_cast< sal_uInt16 >( nNewMonth % 12 + 12 );
2845 else
2846 nMonth = static_cast< sal_uInt16 >( nNewMonth );
2847 setDay();
2850 sal_Int32 ScaDate::getDate( sal_Int32 nNullDate ) const
2852 sal_uInt16 nLastDay = ::DaysInMonth( nMonth, nYear );
2853 sal_uInt16 nRealDay = (bLastDayMode && bLastDay) ? nLastDay : Min( nLastDay, nOrigDay );
2854 return ::DateToDays( nRealDay, nMonth, nYear ) - nNullDate;
2857 sal_Int32 ScaDate::getDiff( const ScaDate& rFrom, const ScaDate& rTo ) throw( lang::IllegalArgumentException )
2859 if( rFrom > rTo )
2860 return getDiff( rTo, rFrom );
2862 sal_Int32 nDiff = 0;
2863 ScaDate aFrom( rFrom );
2864 ScaDate aTo( rTo );
2866 if( rTo.b30Days )
2868 // corrections for base 0 (US NASD)
2869 if( rTo.bUSMode )
2871 if( ((rFrom.nMonth == 2) || (rFrom.nDay < 30)) && (aTo.nOrigDay == 31) )
2872 aTo.nDay = 31;
2873 else if( (aTo.nMonth == 2) && aTo.bLastDay )
2874 aTo.nDay = ::DaysInMonth( 2, aTo.nYear );
2876 // corrections for base 4 (Europe)
2877 else
2879 if( (aFrom.nMonth == 2) && (aFrom.nDay == 30) )
2880 aFrom.nDay = ::DaysInMonth( 2, aFrom.nYear );
2881 if( (aTo.nMonth == 2) && (aTo.nDay == 30) )
2882 aTo.nDay = ::DaysInMonth( 2, aTo.nYear );
2886 if( (aFrom.nYear < aTo.nYear) || ((aFrom.nYear == aTo.nYear) && (aFrom.nMonth < aTo.nMonth)) )
2888 // move aFrom to 1st day of next month
2889 nDiff = aFrom.getDaysInMonth() - aFrom.nDay + 1;
2890 aFrom.nOrigDay = aFrom.nDay = 1;
2891 aFrom.bLastDay = sal_False;
2892 aFrom.addMonths( 1 );
2894 if( aFrom.nYear < aTo.nYear )
2896 // move aFrom to 1st day of next year
2897 nDiff += aFrom.getDaysInMonthRange( aFrom.nMonth, 12 );
2898 aFrom.addMonths( 13 - aFrom.nMonth );
2900 // move aFrom to 1st day of this year
2901 nDiff += aFrom.getDaysInYearRange( aFrom.nYear, aTo.nYear - 1 );
2902 aFrom.addYears( aTo.nYear - aFrom.nYear );
2905 // move aFrom to 1st day of this month
2906 nDiff += aFrom.getDaysInMonthRange( aFrom.nMonth, aTo.nMonth - 1 );
2907 aFrom.addMonths( aTo.nMonth - aFrom.nMonth );
2909 // finally add remaining days in this month
2910 nDiff += aTo.nDay - aFrom.nDay;
2911 return nDiff > 0 ? nDiff : 0;
2914 sal_Bool ScaDate::operator<( const ScaDate& rCmp ) const
2916 if( nYear != rCmp.nYear )
2917 return nYear < rCmp.nYear;
2918 if( nMonth != rCmp.nMonth )
2919 return nMonth < rCmp.nMonth;
2920 if( nDay != rCmp.nDay )
2921 return nDay < rCmp.nDay;
2922 if( bLastDay || rCmp.bLastDay )
2923 return !bLastDay && rCmp.bLastDay;
2924 return nOrigDay < rCmp.nOrigDay;
2929 //-----------------------------------------------------------------------------
2931 ScaAnyConverter::ScaAnyConverter( const uno::Reference< lang::XMultiServiceFactory >& xServiceFact ) :
2932 bHasValidFormat( sal_False )
2934 if( xServiceFact.is() )
2936 uno::Reference< uno::XInterface > xInstance = xServiceFact->createInstance(
2937 OUString::createFromAscii( "com.sun.star.util.NumberFormatter" ) );
2938 xFormatter = uno::Reference< util::XNumberFormatter >( xInstance, uno::UNO_QUERY );
2942 ScaAnyConverter::~ScaAnyConverter()
2946 void ScaAnyConverter::init( const uno::Reference< beans::XPropertySet >& xPropSet ) throw( uno::RuntimeException )
2948 // try to get default number format
2949 bHasValidFormat = sal_False;
2950 if( xFormatter.is() )
2952 // get XFormatsSupplier from outer XPropertySet
2953 uno::Reference< util::XNumberFormatsSupplier > xFormatsSupp( xPropSet, uno::UNO_QUERY );
2954 if( xFormatsSupp.is() )
2956 // get XNumberFormatTypes from XNumberFormatsSupplier to get standard index
2957 uno::Reference< util::XNumberFormats > xFormats( xFormatsSupp->getNumberFormats() );
2958 uno::Reference< util::XNumberFormatTypes > xFormatTypes( xFormats, uno::UNO_QUERY );
2959 if( xFormatTypes.is() )
2961 lang::Locale eLocale;
2962 nDefaultFormat = xFormatTypes->getStandardIndex( eLocale );
2963 xFormatter->attachNumberFormatsSupplier( xFormatsSupp );
2964 bHasValidFormat = sal_True;
2970 double ScaAnyConverter::convertToDouble( const OUString& rString ) const throw( lang::IllegalArgumentException )
2972 double fValue = 0.0;
2973 if( bHasValidFormat )
2977 fValue = xFormatter->convertStringToNumber( nDefaultFormat, rString );
2979 catch( uno::Exception& )
2981 throw lang::IllegalArgumentException();
2984 else
2986 rtl_math_ConversionStatus eStatus;
2987 sal_Int32 nEnd;
2988 fValue = ::rtl::math::stringToDouble( rString, '.', ',', &eStatus, &nEnd );
2989 if( (eStatus != rtl_math_ConversionStatus_Ok) || (nEnd < rString.getLength()) )
2990 throw lang::IllegalArgumentException();
2992 return fValue;
2995 sal_Bool ScaAnyConverter::getDouble(
2996 double& rfResult,
2997 const uno::Any& rAny ) const throw( lang::IllegalArgumentException )
2999 rfResult = 0.0;
3000 sal_Bool bContainsVal = sal_True;
3001 switch( rAny.getValueTypeClass() )
3003 case uno::TypeClass_VOID:
3004 bContainsVal = sal_False;
3005 break;
3006 case uno::TypeClass_DOUBLE:
3007 rAny >>= rfResult;
3008 break;
3009 case uno::TypeClass_STRING:
3011 const OUString* pString = static_cast< const OUString* >( rAny.getValue() );
3012 if( pString->getLength() )
3013 rfResult = convertToDouble( *pString );
3014 else
3015 bContainsVal = sal_False;
3017 break;
3018 default:
3019 throw lang::IllegalArgumentException();
3021 return bContainsVal;
3024 sal_Bool ScaAnyConverter::getDouble(
3025 double& rfResult,
3026 const uno::Reference< beans::XPropertySet >& xPropSet,
3027 const uno::Any& rAny ) throw( uno::RuntimeException, lang::IllegalArgumentException )
3029 init( xPropSet );
3030 return getDouble( rfResult, rAny );
3033 double ScaAnyConverter::getDouble(
3034 const uno::Reference< beans::XPropertySet >& xPropSet,
3035 const uno::Any& rAny,
3036 double fDefault ) throw( uno::RuntimeException, lang::IllegalArgumentException )
3038 double fResult;
3039 if( !getDouble( fResult, xPropSet, rAny ) )
3040 fResult = fDefault;
3041 return fResult;
3044 sal_Bool ScaAnyConverter::getInt32(
3045 sal_Int32& rnResult,
3046 const uno::Reference< beans::XPropertySet >& xPropSet,
3047 const uno::Any& rAny ) throw( uno::RuntimeException, lang::IllegalArgumentException )
3049 double fResult;
3050 sal_Bool bContainsVal = getDouble( fResult, xPropSet, rAny );
3051 if( (fResult <= -2147483649.0) || (fResult >= 2147483648.0) )
3052 throw lang::IllegalArgumentException();
3054 rnResult = static_cast< sal_Int32 >( fResult );
3055 return bContainsVal;
3058 sal_Int32 ScaAnyConverter::getInt32(
3059 const uno::Reference< beans::XPropertySet >& xPropSet,
3060 const uno::Any& rAny,
3061 sal_Int32 nDefault ) throw( uno::RuntimeException, lang::IllegalArgumentException )
3063 sal_Int32 nResult;
3064 if( !getInt32( nResult, xPropSet, rAny ) )
3065 nResult = nDefault;
3066 return nResult;
3071 //-----------------------------------------------------------------------------