Update ooo320-m1
[ooovba.git] / scaddins / source / analysis / analysishelper.cxx
blob249db0ae5a2eaf10edc35d2c5438b3fbd3433fcd
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 // implementation moved to module sal, see #i97091#
673 double Erf( double x )
675 return ::rtl::math::erf(x);
678 // implementation moved to module sal, see #i97091#
679 double Erfc( double x )
681 return ::rtl::math::erfc(x);
684 inline sal_Bool IsNum( sal_Unicode c )
686 return c >= '0' && c <= '9';
690 inline sal_Bool IsComma( sal_Unicode c )
692 return c == '.' || c == ',';
696 inline sal_Bool IsExpStart( sal_Unicode c )
698 return c == 'e' || c == 'E';
702 inline sal_Bool IsImagUnit( sal_Unicode c )
704 return c == 'i' || c == 'j';
708 inline sal_uInt16 GetVal( sal_Unicode c )
710 return sal_uInt16( c - '0' );
714 sal_Bool ParseDouble( const sal_Unicode*& rp, double& rRet )
716 double fInt = 0.0;
717 double fFrac = 0.0;
718 double fMult = 0.1; // multiplier to multiply digits with, when adding fractional ones
719 sal_Int32 nExp = 0;
720 sal_Int32 nMaxExp = 307;
721 sal_uInt16 nDigCnt = 18; // max. number of digits to read in, rest doesn't matter
723 enum State { S_End = 0, S_Sign, S_IntStart, S_Int, S_IgnoreIntDigs, S_Frac, S_IgnoreFracDigs, S_ExpSign, S_Exp };
725 State eS = S_Sign;
727 sal_Bool bNegNum = sal_False;
728 sal_Bool bNegExp = sal_False;
730 const sal_Unicode* p = rp;
731 sal_Unicode c;
733 while( eS )
735 c = *p;
736 switch( eS )
738 case S_Sign:
739 if( IsNum( c ) )
741 fInt = GetVal( c );
742 nDigCnt--;
743 eS = S_Int;
745 else if( c == '-' )
747 bNegNum = sal_True;
748 eS = S_IntStart;
750 else if( c == '+' )
751 eS = S_IntStart;
752 else if( IsComma( c ) )
753 eS = S_Frac;
754 else
755 return sal_False;
756 break;
757 case S_IntStart:
758 if( IsNum( c ) )
760 fInt = GetVal( c );
761 nDigCnt--;
762 eS = S_Int;
764 else if( IsComma( c ) )
765 eS = S_Frac;
766 else if( IsImagUnit( c ) )
768 rRet = 0.0;
769 return sal_True;
771 else
772 return sal_False;
773 break;
774 case S_Int:
775 if( IsNum( c ) )
777 fInt *= 10.0;
778 fInt += double( GetVal( c ) );
779 nDigCnt--;
780 if( !nDigCnt )
781 eS = S_IgnoreIntDigs;
783 else if( IsComma( c ) )
784 eS = S_Frac;
785 else if( IsExpStart( c ) )
786 eS = S_ExpSign;
787 else
788 eS = S_End;
789 break;
790 case S_IgnoreIntDigs:
791 if( IsNum( c ) )
792 nExp++; // just multiply num with 10... ;-)
793 else if( IsComma( c ) )
794 eS = S_Frac;
795 else if( IsExpStart( c ) )
796 eS = S_ExpSign;
797 else
798 eS = S_End;
799 break;
800 case S_Frac:
801 if( IsNum( c ) )
803 fFrac += double( GetVal( c ) ) * fMult;
804 nDigCnt--;
805 if( nDigCnt )
806 fMult *= 0.1;
807 else
808 eS = S_IgnoreFracDigs;
810 else if( IsExpStart( c ) )
811 eS = S_ExpSign;
812 else
813 eS = S_End;
814 break;
815 case S_IgnoreFracDigs:
816 if( IsExpStart( c ) )
817 eS = S_ExpSign;
818 else if( !IsNum( c ) )
819 eS = S_End;
820 break;
821 case S_ExpSign:
822 if( IsNum( c ) )
824 nExp = GetVal( c );
825 eS = S_Exp;
827 else if( c == '-' )
829 bNegExp = sal_True;
830 eS = S_Exp;
832 else if( c != '+' )
833 eS = S_End;
834 break;
835 case S_Exp:
836 if( IsNum( c ) )
838 nExp *= 10;
839 nExp += GetVal( c );
840 if( nExp > nMaxExp )
841 return sal_False;
843 else
844 eS = S_End;
845 break;
846 case S_End: // to avoid compiler warning
847 break; // loop exits anyway
850 p++;
853 p--; // set pointer back to last
854 rp = p;
856 fInt += fFrac;
857 sal_Int32 nLog10 = sal_Int32( log10( fInt ) );
859 if( bNegExp )
860 nExp = -nExp;
862 if( nLog10 + nExp > nMaxExp )
863 return sal_False;
865 fInt = ::rtl::math::pow10Exp( fInt, nExp );
867 if( bNegNum )
868 fInt = -fInt;
870 rRet = fInt;
872 return sal_True;
876 STRING GetString( double f, sal_Bool bLeadingSign, sal_uInt16 nMaxDig )
878 const int nBuff = 256;
879 sal_Char aBuff[ nBuff + 1 ];
880 const char* pFormStr = bLeadingSign? "%+.*g" : "%.*g";
881 int nLen = snprintf( aBuff, nBuff, pFormStr, int( nMaxDig ), f );
882 // you never know which underlying implementation you get ...
883 aBuff[nBuff] = 0;
884 if ( nLen < 0 || nLen > nBuff )
885 nLen = strlen( aBuff );
887 STRING aRet( aBuff, nLen, RTL_TEXTENCODING_MS_1252 );
889 return aRet;
893 double GetAmordegrc( sal_Int32 nNullDate, double fCost, sal_Int32 nDate, sal_Int32 nFirstPer,
894 double fRestVal, double fPer, double fRate, sal_Int32 nBase ) THROWDEF_RTE_IAE
896 if( nBase == 2 )
897 THROW_IAE;
899 sal_uInt32 nPer = sal_uInt32( fPer );
900 double fUsePer = 1.0 / fRate;
901 double fAmorCoeff;
903 if( fUsePer < 3.0 )
904 fAmorCoeff = 1.0;
905 else if( fUsePer < 5.0 )
906 fAmorCoeff = 1.5;
907 else if( fUsePer <= 6.0 )
908 fAmorCoeff = 2.0;
909 else
910 fAmorCoeff = 2.5;
912 fRate *= fAmorCoeff;
913 double fNRate = ::rtl::math::round( GetYearFrac( nNullDate, nDate, nFirstPer, nBase ) * fRate * fCost, 0 );
914 fCost -= fNRate;
915 double fRest = fCost - fRestVal; // Anschaffungskosten - Restwert - Summe aller Abschreibungen
917 for( sal_uInt32 n = 0 ; n < nPer ; n++ )
919 fNRate = ::rtl::math::round( fRate * fCost, 0 );
920 fRest -= fNRate;
922 if( fRest < 0.0 )
924 switch( nPer - n )
926 case 0:
927 case 1:
928 return ::rtl::math::round( fCost * 0.5, 0 );
929 default:
930 return 0.0;
934 fCost -= fNRate;
937 return fNRate;
941 double GetAmorlinc( sal_Int32 nNullDate, double fCost, sal_Int32 nDate, sal_Int32 nFirstPer,
942 double fRestVal, double fPer, double fRate, sal_Int32 nBase ) THROWDEF_RTE_IAE
944 if( nBase == 2 )
945 THROW_IAE;
947 sal_uInt32 nPer = sal_uInt32( fPer );
948 double fOneRate = fCost * fRate;
949 double fCostDelta = fCost - fRestVal;
950 double f0Rate = GetYearFrac( nNullDate, nDate, nFirstPer, nBase ) * fRate * fCost;
951 sal_uInt32 nNumOfFullPeriods = sal_uInt32( ( fCost - fRestVal - f0Rate) / fOneRate );
953 if( nPer == 0 )
954 return f0Rate;
955 else if( nPer <= nNumOfFullPeriods )
956 return fOneRate;
957 else if( nPer == nNumOfFullPeriods + 1 )
958 return fCostDelta - fOneRate * nNumOfFullPeriods - f0Rate;
959 else
960 return 0.0;
964 double GetDuration( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, double fCoup,
965 double fYield, sal_Int32 nFreq, sal_Int32 nBase ) THROWDEF_RTE_IAE
967 double fYearfrac = GetYearFrac( nNullDate, nSettle, nMat, nBase );
968 double fNumOfCoups = GetCoupnum( nNullDate, nSettle, nMat, nFreq, nBase );
969 double fDur = 0.0;
970 const double f100 = 100.0;
971 fCoup *= f100 / double( nFreq ); // fCoup is used as cash flow
972 fYield /= nFreq;
973 fYield += 1.0;
975 double nDiff = fYearfrac * nFreq - fNumOfCoups;
977 double t;
979 for( t = 1.0 ; t < fNumOfCoups ; t++ )
980 fDur += ( t + nDiff ) * ( fCoup ) / pow( fYield, t + nDiff );
982 fDur += ( fNumOfCoups + nDiff ) * ( fCoup + f100 ) / pow( fYield, fNumOfCoups + nDiff );
984 double p = 0.0;
985 for( t = 1.0 ; t < fNumOfCoups ; t++ )
986 p += fCoup / pow( fYield, t + nDiff );
988 p += ( fCoup + f100 ) / pow( fYield, fNumOfCoups + nDiff );
990 fDur /= p;
991 fDur /= double( nFreq );
993 return fDur;
997 double GetYieldmat( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nIssue,
998 double fRate, double fPrice, sal_Int32 nBase ) THROWDEF_RTE_IAE
1000 double fIssMat = GetYearFrac( nNullDate, nIssue, nMat, nBase );
1001 double fIssSet = GetYearFrac( nNullDate, nIssue, nSettle, nBase );
1002 double fSetMat = GetYearFrac( nNullDate, nSettle, nMat, nBase );
1004 double y = 1.0 + fIssMat * fRate;
1005 y /= fPrice / 100.0 + fIssSet * fRate;
1006 y--;
1007 y /= fSetMat;
1009 return y;
1013 double GetOddfprice( sal_Int32 /*nNullDate*/, sal_Int32 /*nSettle*/, sal_Int32 /*nMat*/, sal_Int32 /*nIssue*/,
1014 sal_Int32 /*nFirstCoup*/, double /*fRate*/, double /*fYield*/, double /*fRedemp*/, sal_Int32 /*nFreq*/,
1015 sal_Int32 /*nBase*/ ) THROWDEF_RTE_IAE
1017 THROW_RTE; // #87380#
1019 double fN = GetCoupnum( nNullDate, nSettle, nMat, nFreq, nBase ) - 1.0;
1020 double fNq = GetCoupnum( nNullDate, nSettle, nFirstCoup, nFreq, nBase ) - 1.0;
1021 double fDSC = GetCoupdaysnc( nNullDate, nSettle, nFirstCoup, nFreq, nBase );
1022 double fDSC_E = fDSC / GetCoupdays( nNullDate, nSettle, nMat, nFreq, nBase );
1023 double fNC = GetCoupnum( nNullDate, nIssue, nFirstCoup, nFreq, nBase );
1024 sal_uInt32 nNC = sal_uInt32( fNC );
1025 sal_uInt16 nMonthDelta = 12 / sal_uInt16( nFreq );
1027 sal_uInt32 i;
1028 double f1YieldFreq = 1.0 + fYield / double( nFreq );
1029 double f100RateFreq = 100.0 * fRate / double( nFreq );
1031 double* pDC = new double[ nNC + 1 ];
1032 double* pNL = new double[ nNC + 1 ];
1033 double* pA = new double[ nNC + 1 ];
1035 pDC[ 0 ] = pNL[ 0 ] = pA[ 0 ] = 1.0;
1037 ScaDate aStartDate( nNullDate, nSettle, nBase );
1038 ScaDate aNextCoup( nNullDate, nFirstCoup, nBase );
1039 if( nNC )
1041 pDC[ 1 ] = ScaDate::GetDiff( aStartDate, aNextCoup );
1042 pNL[ 1 ] = GetCoupdays( nNullDate, nSettle, nFirstCoup, nFreq, nBase );
1043 pA[ 1 ] = pDC[ 1 ];
1044 ScaDate aPre;
1045 for( i = 1 ; i <= nNC ; i++ )
1047 aPre = aStartDate;
1048 aStartDate.addMonths( nMonthDelta );
1049 aNextCoup.addMonths( nMonthDelta );
1050 pDC[ i ] = ScaDate::GetDiff( aPre, aStartDate );
1051 pNL[ i ] = GetCoupdays( nNullDate, aStartDate.GetDate( nNullDate ), aNextCoup.GetDate( nNullDate ),
1052 nFreq, nBase );
1053 pA[ i ] = ScaDate::GetDiff( aStartDate, aNextCoup );
1057 double fT1 = fRedemp / pow( f1YieldFreq, fN + fNq + fDSC_E );
1059 double fT2 = 0.0;
1060 for( i = 1 ; i <= nNC ; i++ )
1061 fT2 += pDC[ i ] / pNL[ i ];
1062 fT2 *= f100RateFreq / pow( f1YieldFreq, fNq + fDSC_E );
1064 double fT3 = 0.0;
1065 for( double k = 2.0 ; k <= fN ; k++ )
1066 fT3 += 1.0 / pow( f1YieldFreq, k - fNq + fDSC_E );
1067 fT3 *= f100RateFreq;
1069 double fT4 = 0.0;
1070 for( i = 1 ; i <= nNC ; i++ )
1071 fT4 += pA[ i ] / pNL[ i ];
1072 fT4 *= f100RateFreq;
1074 if( nNC )
1076 delete pDC;
1077 delete pNL;
1078 delete pA;
1081 return fT1 + fT2 + fT3 - fT4;
1086 double getYield_( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, double fCoup, double fPrice,
1087 double fRedemp, sal_Int32 nFreq, sal_Int32 nBase ) THROWDEF_RTE_IAE
1089 double fRate = fCoup;
1090 double fPriceN = 0.0;
1091 double fYield1 = 0.0;
1092 double fYield2 = 1.0;
1093 double fPrice1 = getPrice_( nNullDate, nSettle, nMat, fRate, fYield1, fRedemp, nFreq, nBase );
1094 double fPrice2 = getPrice_( nNullDate, nSettle, nMat, fRate, fYield2, fRedemp, nFreq, nBase );
1095 double fYieldN = ( fYield2 - fYield1 ) * 0.5;
1097 for( sal_uInt32 nIter = 0 ; nIter < 100 && fPriceN != fPrice ; nIter++ )
1099 fPriceN = getPrice_( nNullDate, nSettle, nMat, fRate, fYieldN, fRedemp, nFreq, nBase );
1101 if( fPrice == fPrice1 )
1102 return fYield1;
1103 else if( fPrice == fPrice2 )
1104 return fYield2;
1105 else if( fPrice == fPriceN )
1106 return fYieldN;
1107 else if( fPrice < fPrice2 )
1109 fYield2 *= 2.0;
1110 fPrice2 = getPrice_( nNullDate, nSettle, nMat, fRate, fYield2, fRedemp, nFreq, nBase );
1112 fYieldN = ( fYield2 - fYield1 ) * 0.5;
1114 else
1116 if( fPrice < fPriceN )
1118 fYield1 = fYieldN;
1119 fPrice1 = fPriceN;
1121 else
1123 fYield2 = fYieldN;
1124 fPrice2 = fPriceN;
1127 fYieldN = fYield2 - ( fYield2 - fYield1 ) * ( ( fPrice - fPrice2 ) / ( fPrice1 - fPrice2 ) );
1131 if( fabs( fPrice - fPriceN ) > fPrice / 100.0 )
1132 THROW_IAE; // result not precise enough
1134 return fYieldN;
1138 double getPrice_( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, double fRate, double fYield,
1139 double fRedemp, sal_Int32 nFreq, sal_Int32 nBase ) THROWDEF_RTE_IAE
1141 double fFreq = nFreq;
1143 double fE = GetCoupdays( nNullDate, nSettle, nMat, nFreq, nBase );
1144 double fDSC_E = GetCoupdaysnc( nNullDate, nSettle, nMat, nFreq, nBase ) / fE;
1145 double fN = GetCoupnum( nNullDate, nSettle, nMat, nFreq, nBase );
1146 double fA = GetCoupdaybs( nNullDate, nSettle, nMat, nFreq, nBase );
1148 double fRet = fRedemp / ( pow( 1.0 + fYield / fFreq, fN - 1.0 + fDSC_E ) );
1149 fRet -= 100.0 * fRate / fFreq * fA / fE;
1151 double fT1 = 100.0 * fRate / fFreq;
1152 double fT2 = 1.0 + fYield / fFreq;
1154 for( double fK = 0.0 ; fK < fN ; fK++ )
1155 fRet += fT1 / pow( fT2, fK + fDSC_E );
1157 return fRet;
1161 double GetOddfyield( sal_Int32 /*nNullDate*/, sal_Int32 /*nSettle*/, sal_Int32 /*nMat*/, sal_Int32 /*nIssue*/,
1162 sal_Int32 /*nFirstCoup*/, double /*fRate*/, double /*fPrice*/, double /*fRedemp*/, sal_Int32 /*nFreq*/,
1163 sal_Int32 /*nBase*/ ) THROWDEF_RTE_IAE
1165 THROW_RTE; // #87380#
1167 //GetOddfprice( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nIssue,
1168 //sal_Int32 nFirstCoup, double fRate, double fYield, double fRedemp, sal_Int32 nFreq,
1169 //sal_Int32 nBase )
1170 double fPriceN = 0.0;
1171 double fYield1 = 0.0;
1172 double fYield2 = 1.0;
1173 double fPrice1 = GetOddfprice( nNullDate, nSettle, nMat, nIssue, nFirstCoup, fRate, fYield1, fRedemp, nFreq, nBase );
1174 double fPrice2 = GetOddfprice( nNullDate, nSettle, nMat, nIssue, nFirstCoup, fRate, fYield2, fRedemp, nFreq, nBase );
1175 double fYieldN = ( fYield2 - fYield1 ) * 0.5;
1177 for( sal_uInt32 nIter = 0 ; nIter < 100 && fPriceN != fPrice ; nIter++ )
1179 fPriceN = GetOddfprice( nNullDate, nSettle, nMat, nIssue, nFirstCoup, fRate, fYieldN, fRedemp, nFreq, nBase );
1181 if( fPrice == fPrice1 )
1182 return fYield1;
1183 else if( fPrice == fPrice2 )
1184 return fYield2;
1185 else if( fPrice == fPriceN )
1186 return fYieldN;
1187 else if( fPrice < fPrice2 )
1189 fYield2 *= 2.0;
1190 fPrice2 = GetOddfprice( nNullDate, nSettle, nMat, nIssue, nFirstCoup, fRate, fYield2, fRedemp, nFreq, nBase );
1192 fYieldN = ( fYield2 - fYield1 ) * 0.5;
1194 else
1196 if( fPrice < fPriceN )
1198 fYield1 = fYieldN;
1199 fPrice1 = fPriceN;
1201 else
1203 fYield2 = fYieldN;
1204 fPrice2 = fPriceN;
1207 fYieldN = fYield2 - ( fYield2 - fYield1 ) * ( ( fPrice - fPrice2 ) / ( fPrice1 - fPrice2 ) );
1211 if( fabs( fPrice - fPriceN ) > fPrice / 100.0 )
1212 THROW_IAE; // result not precise enough
1214 return fYieldN;
1219 double GetOddlprice( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nLastCoup,
1220 double fRate, double fYield, double fRedemp, sal_Int32 nFreq, sal_Int32 nBase ) THROWDEF_RTE_IAE
1222 double fFreq = double( nFreq );
1223 double fDCi = GetYearFrac( nNullDate, nLastCoup, nMat, nBase ) * fFreq;
1224 double fDSCi = GetYearFrac( nNullDate, nSettle, nMat, nBase ) * fFreq;
1225 double fAi = GetYearFrac( nNullDate, nLastCoup, nSettle, nBase ) * fFreq;
1227 double p = fRedemp + fDCi * 100.0 * fRate / fFreq;
1228 p /= fDSCi * fYield / fFreq + 1.0;
1229 p -= fAi * 100.0 * fRate / fFreq;
1231 return p;
1235 double GetOddlyield( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nLastCoup,
1236 double fRate, double fPrice, double fRedemp, sal_Int32 nFreq, sal_Int32 nBase ) THROWDEF_RTE_IAE
1238 double fFreq = double( nFreq );
1239 double fDCi = GetYearFrac( nNullDate, nLastCoup, nMat, nBase ) * fFreq;
1240 double fDSCi = GetYearFrac( nNullDate, nSettle, nMat, nBase ) * fFreq;
1241 double fAi = GetYearFrac( nNullDate, nLastCoup, nSettle, nBase ) * fFreq;
1243 double y = fRedemp + fDCi * 100.0 * fRate / fFreq;
1244 y /= fPrice + fAi * 100.0 * fRate / fFreq;
1245 y--;
1246 y *= fFreq / fDSCi;
1248 return y;
1252 double GetRmz( double fZins, double fZzr, double fBw, double fZw, sal_Int32 nF )
1254 double fRmz;
1255 if( fZins == 0.0 )
1256 fRmz = ( fBw + fZw ) / fZzr;
1257 else
1259 double fTerm = pow( 1.0 + fZins, fZzr );
1260 if( nF > 0 )
1261 fRmz = ( fZw * fZins / ( fTerm - 1.0 ) + fBw * fZins / ( 1.0 - 1.0 / fTerm ) ) / ( 1.0 + fZins );
1262 else
1263 fRmz = fZw * fZins / ( fTerm - 1.0 ) + fBw * fZins / ( 1.0 - 1.0 / fTerm );
1266 return -fRmz;
1270 double GetZw( double fZins, double fZzr, double fRmz, double fBw, sal_Int32 nF )
1272 double fZw;
1273 if( fZins == 0.0 )
1274 fZw = fBw + fRmz * fZzr;
1275 else
1277 double fTerm = pow( 1.0 + fZins, fZzr );
1278 if( nF > 0 )
1279 fZw = fBw * fTerm + fRmz * ( 1.0 + fZins ) * ( fTerm - 1.0 ) / fZins;
1280 else
1281 fZw = fBw * fTerm + fRmz * ( fTerm - 1.0 ) / fZins;
1284 return -fZw;
1288 /*double TBillYield( constREFXPS& xOpt, sal_Int32 nSettle, sal_Int32 nMat, double fPrice ) THROWDEF_RTE_IAE
1290 sal_Int32 nDiff = GetDiffDate360( xOpt, nSettle, nMat, sal_True );
1292 if( fPrice <= 0.0 || nSettle >= nMat || nDiff > 360 )
1293 THROW_IAE;
1295 double fRet = 100.0;
1296 fRet /= fPrice;
1297 fRet--;
1298 fRet *= double( nDiff );
1299 fRet /= 360.0;
1301 return fRet;
1305 //-----------------------------------------------------------------------------
1306 // financial functions COUP***
1309 //-------
1310 // COUPPCD: find last coupon date before settlement (can be equal to settlement)
1311 void lcl_GetCouppcd( ScaDate& rDate, const ScaDate& rSettle, const ScaDate& rMat, sal_Int32 nFreq )
1312 throw( lang::IllegalArgumentException )
1314 rDate = rMat;
1315 rDate.setYear( rSettle.getYear() );
1316 if( rDate < rSettle )
1317 rDate.addYears( 1 );
1318 while( rDate > rSettle )
1319 rDate.addMonths( -12 / nFreq );
1322 double GetCouppcd( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nFreq, sal_Int32 nBase )
1323 THROWDEF_RTE_IAE
1325 if( nSettle >= nMat || CHK_Freq )
1326 THROW_IAE;
1328 ScaDate aDate;
1329 lcl_GetCouppcd( aDate, ScaDate( nNullDate, nSettle, nBase ), ScaDate( nNullDate, nMat, nBase ), nFreq );
1330 return aDate.getDate( nNullDate );
1334 //-------
1335 // COUPNCD: find first coupon date after settlement (is never equal to settlement)
1336 void lcl_GetCoupncd( ScaDate& rDate, const ScaDate& rSettle, const ScaDate& rMat, sal_Int32 nFreq )
1337 throw( lang::IllegalArgumentException )
1339 rDate = rMat;
1340 rDate.setYear( rSettle.getYear() );
1341 if( rDate > rSettle )
1342 rDate.addYears( -1 );
1343 while( rDate <= rSettle )
1344 rDate.addMonths( 12 / nFreq );
1347 double GetCoupncd( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nFreq, sal_Int32 nBase )
1348 THROWDEF_RTE_IAE
1350 if( nSettle >= nMat || CHK_Freq )
1351 THROW_IAE;
1353 ScaDate aDate;
1354 lcl_GetCoupncd( aDate, ScaDate( nNullDate, nSettle, nBase ), ScaDate( nNullDate, nMat, nBase ), nFreq );
1355 return aDate.getDate( nNullDate );
1359 //-------
1360 // COUPDAYBS: get day count: coupon date before settlement <-> settlement
1361 double GetCoupdaybs( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nFreq, sal_Int32 nBase )
1362 THROWDEF_RTE_IAE
1364 if( nSettle >= nMat || CHK_Freq )
1365 THROW_IAE;
1367 ScaDate aSettle( nNullDate, nSettle, nBase );
1368 ScaDate aDate;
1369 lcl_GetCouppcd( aDate, aSettle, ScaDate( nNullDate, nMat, nBase ), nFreq );
1370 return ScaDate::getDiff( aDate, aSettle );
1374 //-------
1375 // COUPDAYSNC: get day count: settlement <-> coupon date after settlement
1376 double GetCoupdaysnc( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nFreq, sal_Int32 nBase )
1377 THROWDEF_RTE_IAE
1379 if( nSettle >= nMat || CHK_Freq )
1380 THROW_IAE;
1382 if( (nBase != 0) && (nBase != 4) )
1384 ScaDate aSettle( nNullDate, nSettle, nBase );
1385 ScaDate aDate;
1386 lcl_GetCoupncd( aDate, aSettle, ScaDate( nNullDate, nMat, nBase ), nFreq );
1387 return ScaDate::getDiff( aSettle, aDate );
1389 return GetCoupdays( nNullDate, nSettle, nMat, nFreq, nBase ) - GetCoupdaybs( nNullDate, nSettle, nMat, nFreq, nBase );
1393 //-------
1394 // COUPDAYS: get day count: coupon date before settlement <-> coupon date after settlement
1395 double GetCoupdays( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nFreq, sal_Int32 nBase )
1396 THROWDEF_RTE_IAE
1398 if( nSettle >= nMat || CHK_Freq )
1399 THROW_IAE;
1401 if( nBase == 1 )
1403 ScaDate aDate;
1404 lcl_GetCouppcd( aDate, ScaDate( nNullDate, nSettle, nBase ), ScaDate( nNullDate, nMat, nBase ), nFreq );
1405 ScaDate aNextDate( aDate );
1406 aNextDate.addMonths( 12 / nFreq );
1407 return ScaDate::getDiff( aDate, aNextDate );
1409 return static_cast< double >( GetDaysInYear( 0, 0, nBase ) ) / nFreq;
1413 //-------
1414 // COUPNUM: get count of coupon dates
1415 double GetCoupnum( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nFreq, sal_Int32 nBase )
1416 THROWDEF_RTE_IAE
1418 if( nSettle >= nMat || CHK_Freq )
1419 THROW_IAE;
1421 ScaDate aMat( nNullDate, nMat, nBase );
1422 ScaDate aDate;
1423 lcl_GetCouppcd( aDate, ScaDate( nNullDate, nSettle, nBase ), aMat, nFreq );
1424 sal_uInt16 nMonths = (aMat.getYear() - aDate.getYear()) * 12 + aMat.getMonth() - aDate.getMonth();
1425 return static_cast< double >( nMonths * nFreq / 12 );
1434 const sal_uInt32 MyList::nStartSize = 16;
1435 const sal_uInt32 MyList::nIncrSize = 16;
1438 void MyList::_Grow( void )
1440 nSize += nIncrSize;
1442 void** pNewData = new void*[ nSize ];
1443 memcpy( pNewData, pData, nNew * sizeof( void* ) );
1445 delete[] pData;
1446 pData = pNewData;
1450 MyList::MyList( void )
1452 nSize = nStartSize;
1453 pData = new void*[ nSize ];
1454 nNew = nAct = 0;
1458 MyList::~MyList()
1460 delete[] pData;
1464 void MyList::Insert( void* p, sal_uInt32 n )
1466 if( n >= nNew )
1467 Append( p );
1468 else
1470 Grow();
1472 void** pIns = pData + n;
1473 memmove( pIns + 1, pIns, ( nNew - n ) * sizeof( void* ) );
1475 *pIns = p;
1477 nNew++;
1484 StringList::~StringList()
1486 for( STRING* p = ( STRING* ) First() ; p ; p = ( STRING* ) Next() )
1487 delete p;
1491 class AnalysisRscStrArrLoader : public Resource
1493 private:
1494 ResStringArray aStrArray;
1495 public:
1496 AnalysisRscStrArrLoader( sal_uInt16 nRsc, sal_uInt16 nArrayId, ResMgr& rResMgr ) :
1497 Resource( AnalysisResId( nRsc, rResMgr ) ),
1498 aStrArray( AnalysisResId( nArrayId, rResMgr ) )
1500 FreeResource();
1503 const ResStringArray& GetStringArray() const { return aStrArray; }
1509 FuncData::FuncData( const FuncDataBase& r, ResMgr& rResMgr ) :
1510 aIntName( OUString::createFromAscii( r.pIntName ) ),
1511 nUINameID( r.nUINameID ),
1512 nDescrID( r.nDescrID ),
1513 bDouble( r.bDouble ),
1514 bWithOpt( r.bWithOpt ),
1515 nParam( r.nNumOfParams ),
1516 nCompID( r.nCompListID ),
1517 eCat( r.eCat )
1519 AnalysisRscStrArrLoader aArrLoader( RID_ANALYSIS_DEFFUNCTION_NAMES, nCompID, rResMgr );
1520 // ResStringArray aDefFuncNameArray( AnalysisResId( nCompID, rResMgr ) );
1521 const ResStringArray& rArr = aArrLoader.GetStringArray();
1523 sal_uInt16 nCount = sal::static_int_cast<sal_uInt16>( rArr.Count() );
1524 sal_uInt16 n;
1526 for( n = 0 ; n < nCount ; n++ )
1527 aCompList.Append( rArr.GetString( n ) );
1531 FuncData::~FuncData()
1536 sal_uInt16 FuncData::GetStrIndex( sal_uInt16 nParamNum ) const
1538 if( !bWithOpt )
1539 nParamNum++;
1541 if( nParamNum > nParam )
1542 return nParam * 2;
1543 else
1544 return nParamNum * 2;
1550 FuncDataList::FuncDataList( ResMgr& rResMgr )
1552 const sal_uInt32 nNum = sizeof( pFuncDatas ) / sizeof( FuncDataBase );
1554 for( sal_uInt16 n = 0 ; n < nNum ; n++ )
1555 Append( new FuncData( pFuncDatas[ n ], rResMgr ) );
1559 FuncDataList::~FuncDataList()
1561 for( FuncData* p = ( FuncData* ) First() ; p ; p = ( FuncData* ) Next() )
1562 delete p;
1566 const FuncData* FuncDataList::Get( const OUString& aProgrammaticName ) const
1568 if( aLastName == aProgrammaticName )
1569 return Get( nLast );
1571 ( ( FuncDataList* ) this )->aLastName = aProgrammaticName;
1573 sal_uInt32 nE = Count();
1574 for( sal_uInt32 n = 0 ; n < nE ; n++ )
1576 const FuncData* p = Get( n );
1577 if( p->Is( aProgrammaticName ) )
1579 ( ( FuncDataList* ) this )->nLast = n;
1580 return p;
1584 ( ( FuncDataList* ) this )->nLast = 0xFFFFFFFF;
1585 return NULL;
1589 AnalysisResId::AnalysisResId( sal_uInt16 nId, ResMgr& rResMgr ) : ResId( nId, rResMgr )
1596 SortedIndividualInt32List::SortedIndividualInt32List()
1601 SortedIndividualInt32List::~SortedIndividualInt32List()
1606 void SortedIndividualInt32List::Insert( sal_Int32 nDay )
1608 sal_uInt32 nIndex = Count();
1609 while( nIndex )
1611 nIndex--;
1612 sal_Int32 nRef = Get( nIndex );
1613 if( nDay == nRef )
1614 return;
1615 else if( nDay > nRef )
1617 MyList::Insert( (void*) nDay, nIndex + 1 );
1618 return;
1621 MyList::Insert( (void*) nDay, 0UL );
1625 void SortedIndividualInt32List::Insert( sal_Int32 nDay, sal_Int32 nNullDate, sal_Bool bInsertOnWeekend )
1627 if( !nDay )
1628 return;
1630 nDay += nNullDate;
1631 if( bInsertOnWeekend || (GetDayOfWeek( nDay ) < 5) )
1632 Insert( nDay );
1636 void SortedIndividualInt32List::Insert(
1637 double fDay, sal_Int32 nNullDate, sal_Bool bInsertOnWeekend ) throw( uno::RuntimeException, lang::IllegalArgumentException )
1639 if( (fDay < -2147483648.0) || (fDay > 2147483649.0) )
1640 throw lang::IllegalArgumentException();
1641 Insert( static_cast< sal_Int32 >( fDay ), nNullDate, bInsertOnWeekend );
1645 sal_Bool SortedIndividualInt32List::Find( sal_Int32 nVal ) const
1647 sal_uInt32 nE = Count();
1649 if( !nE || nVal < Get( 0 ) || nVal > Get( nE - 1 ) )
1650 return sal_False;
1652 // linear search
1654 for( sal_uInt32 n = 0 ; n < nE ; n++ )
1656 sal_Int32 nRef = Get( n );
1658 if( nRef == nVal )
1659 return sal_True;
1660 else if( nRef > nVal )
1661 return sal_False;
1663 return sal_False;
1667 void SortedIndividualInt32List::InsertHolidayList(
1668 const ScaAnyConverter& rAnyConv,
1669 const uno::Any& rHolAny,
1670 sal_Int32 nNullDate,
1671 sal_Bool bInsertOnWeekend ) throw( uno::RuntimeException, lang::IllegalArgumentException )
1673 double fDay;
1674 if( rAnyConv.getDouble( fDay, rHolAny ) )
1675 Insert( fDay, nNullDate, bInsertOnWeekend );
1679 void SortedIndividualInt32List::InsertHolidayList(
1680 ScaAnyConverter& rAnyConv,
1681 const uno::Reference< beans::XPropertySet >& xOptions,
1682 const uno::Any& rHolAny,
1683 sal_Int32 nNullDate,
1684 sal_Bool bInsertOnWeekend ) throw( uno::RuntimeException, lang::IllegalArgumentException )
1686 rAnyConv.init( xOptions );
1687 if( rHolAny.getValueTypeClass() == uno::TypeClass_SEQUENCE )
1689 uno::Sequence< uno::Sequence< uno::Any > > aAnySeq;
1690 if( rHolAny >>= aAnySeq )
1692 const uno::Sequence< uno::Any >* pSeqArray = aAnySeq.getConstArray();
1693 for( sal_Int32 nIndex1 = 0; nIndex1 < aAnySeq.getLength(); nIndex1++ )
1695 const uno::Sequence< uno::Any >& rSubSeq = pSeqArray[ nIndex1 ];
1696 const uno::Any* pAnyArray = rSubSeq.getConstArray();
1698 for( sal_Int32 nIndex2 = 0; nIndex2 < rSubSeq.getLength(); nIndex2++ )
1699 InsertHolidayList( rAnyConv, pAnyArray[ nIndex2 ], nNullDate, bInsertOnWeekend );
1702 else
1703 throw lang::IllegalArgumentException();
1705 else
1706 InsertHolidayList( rAnyConv, rHolAny, nNullDate, bInsertOnWeekend );
1711 //-----------------------------------------------------------------------------
1713 ScaDoubleList::~ScaDoubleList()
1715 for( double* pDbl = const_cast< double* >( First() ); pDbl; pDbl = const_cast< double* >( Next() ) )
1716 delete pDbl;
1720 void ScaDoubleList::Append(
1721 const uno::Sequence< uno::Sequence< double > >& rValueSeq ) throw( uno::RuntimeException, lang::IllegalArgumentException )
1723 const uno::Sequence< double >* pSeqArray = rValueSeq.getConstArray();
1724 for( sal_Int32 nIndex1 = 0; nIndex1 < rValueSeq.getLength(); nIndex1++ )
1726 const uno::Sequence< double >& rSubSeq = pSeqArray[ nIndex1 ];
1727 const double* pArray = rSubSeq.getConstArray();
1728 for( sal_Int32 nIndex2 = 0; nIndex2 < rSubSeq.getLength(); nIndex2++ )
1729 Append( pArray[ nIndex2 ] );
1734 void ScaDoubleList::Append(
1735 const uno::Sequence< uno::Sequence< sal_Int32 > >& rValueSeq ) throw( uno::RuntimeException, lang::IllegalArgumentException )
1737 const uno::Sequence< sal_Int32 >* pSeqArray = rValueSeq.getConstArray();
1738 for( sal_Int32 nIndex1 = 0; nIndex1 < rValueSeq.getLength(); nIndex1++ )
1740 const uno::Sequence< sal_Int32 >& rSubSeq = pSeqArray[ nIndex1 ];
1741 const sal_Int32* pArray = rSubSeq.getConstArray();
1742 for( sal_Int32 nIndex2 = 0; nIndex2 < rSubSeq.getLength(); nIndex2++ )
1743 Append( pArray[ nIndex2 ] );
1749 void ScaDoubleList::Append(
1750 const ScaAnyConverter& rAnyConv,
1751 const uno::Any& rAny,
1752 sal_Bool bIgnoreEmpty ) throw( uno::RuntimeException, lang::IllegalArgumentException )
1754 if( rAny.getValueTypeClass() == uno::TypeClass_SEQUENCE )
1755 Append( rAnyConv, *static_cast< const uno::Sequence< uno::Sequence< uno::Any > >* >( rAny.getValue() ), bIgnoreEmpty );
1756 else
1758 double fValue;
1759 if( rAnyConv.getDouble( fValue, rAny ) )
1760 Append( fValue );
1761 else if( !bIgnoreEmpty )
1762 Append( 0.0 );
1767 void ScaDoubleList::Append(
1768 const ScaAnyConverter& rAnyConv,
1769 const uno::Sequence< uno::Any >& rAnySeq,
1770 sal_Bool bIgnoreEmpty ) throw( uno::RuntimeException, lang::IllegalArgumentException )
1772 const uno::Any* pArray = rAnySeq.getConstArray();
1773 for( sal_Int32 nIndex = 0; nIndex < rAnySeq.getLength(); nIndex++ )
1774 Append( rAnyConv, pArray[ nIndex ], bIgnoreEmpty );
1778 void ScaDoubleList::Append(
1779 const ScaAnyConverter& rAnyConv,
1780 const uno::Sequence< uno::Sequence< uno::Any > >& rAnySeq,
1781 sal_Bool bIgnoreEmpty ) throw( uno::RuntimeException, lang::IllegalArgumentException )
1783 const uno::Sequence< uno::Any >* pArray = rAnySeq.getConstArray();
1784 for( sal_Int32 nIndex = 0; nIndex < rAnySeq.getLength(); nIndex++ )
1785 Append( rAnyConv, pArray[ nIndex ], bIgnoreEmpty );
1790 void ScaDoubleList::Append(
1791 ScaAnyConverter& rAnyConv,
1792 const uno::Reference< beans::XPropertySet >& xOpt,
1793 const uno::Sequence< uno::Any >& rAnySeq,
1794 sal_Bool bIgnoreEmpty ) throw( uno::RuntimeException, lang::IllegalArgumentException )
1796 rAnyConv.init( xOpt );
1797 Append( rAnyConv, rAnySeq, bIgnoreEmpty );
1801 sal_Bool ScaDoubleList::CheckInsert( double ) const throw( uno::RuntimeException, lang::IllegalArgumentException )
1803 return sal_True;
1808 //-----------------------------------------------------------------------------
1810 sal_Bool ScaDoubleListGT0::CheckInsert( double fValue ) const throw( uno::RuntimeException, lang::IllegalArgumentException )
1812 if( fValue < 0.0 )
1813 throw lang::IllegalArgumentException();
1814 return fValue > 0.0;
1819 //-----------------------------------------------------------------------------
1821 sal_Bool ScaDoubleListGE0::CheckInsert( double fValue ) const throw( uno::RuntimeException, lang::IllegalArgumentException )
1823 if( fValue < 0.0 )
1824 throw lang::IllegalArgumentException();
1825 return sal_True;
1830 //-----------------------------------------------------------------------------
1832 Complex::Complex( const STRING& rStr ) THROWDEF_RTE_IAE
1834 if( !ParseString( rStr, *this ) )
1835 THROW_IAE;
1839 inline sal_Bool Complex::IsImagUnit( sal_Unicode c )
1841 return c == 'i' || c == 'j';
1844 sal_Bool Complex::ParseString( const STRING& rStr, Complex& rCompl )
1846 rCompl.c = '\0'; // do not force a symbol, if only real part present
1848 const sal_Unicode* pStr = ( const sal_Unicode * ) rStr;
1850 if( IsImagUnit( *pStr ) && rStr.getLength() == 1)
1852 rCompl.r = 0.0;
1853 rCompl.i = 1.0;
1854 rCompl.c = *pStr;
1855 return sal_True;
1858 double f;
1860 if( !ParseDouble( pStr, f ) )
1861 return sal_False;
1863 switch( *pStr )
1865 case '-': // imag part follows
1866 case '+':
1868 double r = f;
1869 if( IsImagUnit( pStr[ 1 ] ) )
1871 rCompl.c = pStr[ 1 ];
1872 if( pStr[ 2 ] == 0 )
1874 rCompl.r = f;
1875 rCompl.i = ( *pStr == '+' )? 1.0 : -1.0;
1876 return sal_True;
1879 else if( ParseDouble( pStr, f ) && IsImagUnit( *pStr ) )
1881 rCompl.c = *pStr;
1882 pStr++;
1883 if( *pStr == 0 )
1885 rCompl.r = r;
1886 rCompl.i = f;
1887 return sal_True;
1891 break;
1892 case 'j':
1893 case 'i':
1894 rCompl.c = *pStr;
1895 pStr++;
1896 if( *pStr == 0 )
1898 rCompl.i = f;
1899 rCompl.r = 0.0;
1900 return sal_True;
1902 break;
1903 case 0: // only real-part
1904 rCompl.r = f;
1905 rCompl.i = 0.0;
1906 return sal_True;
1909 return sal_False;
1913 STRING Complex::GetString() const THROWDEF_RTE_IAE
1915 static const String aI( 'i' );
1916 static const String aJ( 'j' );
1917 static const String aPlus( '+' );
1918 static const String aMinus( '-' );
1920 CHK_FINITE(r);
1921 CHK_FINITE(i);
1922 STRING aRet;
1924 bool bHasImag = i != 0.0;
1925 bool bHasReal = !bHasImag || (r != 0.0);
1927 if( bHasReal )
1928 aRet = ::GetString( r );
1929 if( bHasImag )
1931 if( i == 1.0 )
1933 if( bHasReal )
1934 aRet += aPlus;
1936 else if( i == -1.0 )
1937 aRet += aMinus;
1938 else
1939 aRet += ::GetString( i, bHasReal );
1940 aRet += (c != 'j') ? aI : aJ;
1943 return aRet;
1947 double Complex::Arg( void ) const THROWDEF_RTE_IAE
1949 if( r == 0.0 && i == 0.0 )
1950 THROW_IAE;
1952 double phi = acos( r / Abs() );
1954 if( i < 0.0 )
1955 phi = -phi;
1957 return phi;
1961 void Complex::Power( double fPower ) THROWDEF_RTE_IAE
1963 if( r == 0.0 && i == 0.0 )
1965 if( fPower > 0 )
1967 r = i = 0.0;
1968 return;
1970 else
1971 THROW_IAE;
1974 double p, phi;
1976 p = Abs();
1978 phi = acos( r / p );
1979 if( i < 0.0 )
1980 phi = -phi;
1982 p = pow( p, fPower );
1983 phi *= fPower;
1985 r = cos( phi ) * p;
1986 i = sin( phi ) * p;
1990 void Complex::Sqrt( void )
1992 static const double fMultConst = 0.7071067811865475; // ...2440084436210485 = 1/sqrt(2)
1993 double p = Abs();
1994 double i_ = sqrt( p - r ) * fMultConst;
1996 r = sqrt( p + r ) * fMultConst;
1997 i = ( i < 0.0 )? -i_ : i_;
2001 inline BOOL SinOverflow( double f )
2003 return fabs( f ) >= 134217728;
2007 void Complex::Sin( void ) THROWDEF_RTE_IAE
2009 if( SinOverflow( r ) )
2010 THROW_IAE;
2012 if( i )
2014 double r_;
2016 r_ = sin( r ) * cosh( i );
2017 i = cos( r ) * sinh( i );
2018 r = r_;
2020 else
2021 r = sin( r );
2025 void Complex::Cos( void ) THROWDEF_RTE_IAE
2027 if( SinOverflow( r ) )
2028 THROW_IAE;
2030 if( i )
2032 double r_;
2034 r_ = cos( r ) * cosh( i );
2035 i = -( sin( r ) * sinh( i ) );
2036 r = r_;
2038 else
2039 r = cos( r );
2043 void Complex::Div( const Complex& z ) THROWDEF_RTE_IAE
2045 if( z.r == 0 && z.i == 0 )
2046 THROW_IAE;
2048 double a1 = r;
2049 double a2 = z.r;
2050 double b1 = i;
2051 double b2 = z.i;
2053 double f = 1.0 / ( a2 * a2 + b2 * b2 );
2055 r = ( a1 * a2 + b1 * b2 ) * f;
2056 i = ( a2 * b1 - a1 * b2 ) * f;
2058 if( !c ) c = z.c;
2062 void Complex::Exp( void )
2064 double fE = exp( r );
2065 r = fE * cos( i );
2066 i = fE * sin( i );
2070 void Complex::Ln( void ) THROWDEF_RTE_IAE
2072 if( r == 0.0 && i == 0.0 )
2073 THROW_IAE;
2075 double fAbs = Abs();
2076 sal_Bool bNegi = i < 0.0;
2078 i = acos( r / fAbs );
2080 if( bNegi )
2081 i = -i;
2083 r = log( fAbs );
2087 void Complex::Log10( void ) THROWDEF_RTE_IAE
2089 Ln();
2090 Mult( 0.434294481903251828 ); // * log10( e )
2094 void Complex::Log2( void ) THROWDEF_RTE_IAE
2096 Ln();
2097 Mult( 1.442695040888963407 ); // * log2( e )
2103 ComplexList::~ComplexList()
2105 for( Complex* p = ( Complex* ) First() ; p ; p = ( Complex* ) Next() )
2106 delete p;
2110 void ComplexList::Append( const SEQSEQ( STRING )& r, ComplListAppendHandl eAH ) THROWDEF_RTE_IAE
2112 sal_Int32 n1, n2;
2113 sal_Int32 nE1 = r.getLength();
2114 sal_Int32 nE2;
2115 sal_Bool bEmpty0 = eAH == AH_EmpyAs0;
2116 sal_Bool bErrOnEmpty = eAH == AH_EmptyAsErr;
2118 for( n1 = 0 ; n1 < nE1 ; n1++ )
2120 const SEQ( STRING )& rList = r[ n1 ];
2121 nE2 = rList.getLength();
2123 for( n2 = 0 ; n2 < nE2 ; n2++ )
2125 const STRING& rStr = rList[ n2 ];
2127 if( rStr.getLength() )
2128 Append( new Complex( rStr ) );
2129 else if( bEmpty0 )
2130 Append( new Complex( 0.0 ) );
2131 else if( bErrOnEmpty )
2132 THROW_IAE;
2138 void ComplexList::Append( const SEQ( ANY )& aMultPars, ComplListAppendHandl eAH ) THROWDEF_RTE_IAE
2140 sal_Int32 nEle = aMultPars.getLength();
2141 sal_Bool bEmpty0 = eAH == AH_EmpyAs0;
2142 sal_Bool bErrOnEmpty = eAH == AH_EmptyAsErr;
2144 for( sal_Int32 i = 0 ; i < nEle ; i++ )
2146 const ANY& r = aMultPars[ i ];
2147 switch( r.getValueTypeClass() )
2149 case uno::TypeClass_VOID: break;
2150 case uno::TypeClass_STRING:
2152 const STRING* pStr = ( const STRING* ) r.getValue();
2154 if( pStr->getLength() )
2155 Append( new Complex( *( STRING* ) r.getValue() ) );
2156 else if( bEmpty0 )
2157 Append( new Complex( 0.0 ) );
2158 else if( bErrOnEmpty )
2159 THROW_IAE;
2161 break;
2162 case uno::TypeClass_DOUBLE:
2163 Append( new Complex( *( double* ) r.getValue(), 0.0 ) );
2164 break;
2165 case uno::TypeClass_SEQUENCE:
2167 SEQSEQ( ANY ) aValArr;
2168 if( r >>= aValArr )
2170 sal_Int32 nE = aValArr.getLength();
2171 const SEQ( ANY )* pArr = aValArr.getConstArray();
2172 for( sal_Int32 n = 0 ; n < nE ; n++ )
2173 Append( pArr[ n ], eAH );
2175 else
2176 THROW_IAE;
2178 break;
2179 default:
2180 THROW_IAE;
2188 ConvertData::ConvertData( const sal_Char p[], double fC, ConvertDataClass e, sal_Bool bPrefSupport ) : aName( p, strlen( p ), RTL_TEXTENCODING_MS_1252 )
2190 fConst = fC;
2191 eClass = e;
2192 bPrefixSupport = bPrefSupport;
2195 ConvertData::~ConvertData()
2200 sal_Int16 ConvertData::GetMatchingLevel( const STRING& rRef ) const
2202 STRING aStr = rRef;
2203 sal_Int32 nLen = rRef.getLength();
2204 sal_Int32 nIndex = rRef.lastIndexOf( '^' );
2205 if( nIndex > 0 && nIndex == ( nLen - 2 ) )
2207 const sal_Unicode* p = aStr.getStr();
2208 aStr = STRING( p, nLen - 2 );
2209 aStr += STRING( p[ nLen - 1 ] );
2211 if( aName.equals( aStr ) )
2212 return 0;
2213 else
2215 const sal_Unicode* p = aStr.getStr();
2217 nLen = aStr.getLength();
2218 bool bPref = IsPrefixSupport();
2219 bool bOneChar = (bPref && nLen > 1 && (aName == p + 1));
2220 if (bOneChar || (bPref && nLen > 2 && (aName == p + 2) &&
2221 *p == 'd' && *(p+1) == 'a'))
2223 sal_Int16 n;
2224 switch( *p )
2226 case 'y': n = -24; break; // yocto
2227 case 'z': n = -21; break; // zepto
2228 case 'a': n = -18; break;
2229 case 'f': n = -15; break;
2230 case 'p': n = -12; break;
2231 case 'n': n = -9; break;
2232 case 'u': n = -6; break;
2233 case 'm': n = -3; break;
2234 case 'c': n = -2; break;
2235 case 'd':
2237 if ( bOneChar )
2238 n = -1; // deci
2239 else
2240 n = 1; // deca
2242 break;
2243 case 'e': n = 1; break;
2244 case 'h': n = 2; break;
2245 case 'k': n = 3; break;
2246 case 'M': n = 6; break;
2247 case 'G': n = 9; break;
2248 case 'T': n = 12; break;
2249 case 'P': n = 15; break;
2250 case 'E': n = 18; break;
2251 case 'Z': n = 21; break; // zetta
2252 case 'Y': n = 24; break; // yotta
2253 default:
2254 n = INV_MATCHLEV;
2257 // We could weed some nonsense out, ODFF doesn't say so though.
2258 #if 0
2259 if (n < 0 && Class() == CDC_Information)
2260 n = INV_MATCHLEV; // milli-bits doesn't make sense
2261 #endif
2263 //! <HACK> #100616# "cm3" is not 10^-2 m^3 but 10^-6 m^3 !!! ------------------
2264 if( n != INV_MATCHLEV )
2266 sal_Unicode cLast = p[ aStr.getLength() - 1 ];
2267 if( cLast == '2' )
2268 n *= 2;
2269 else if( cLast == '3' )
2270 n *= 3;
2272 //! </HACK> -------------------------------------------------------------------
2274 return n;
2276 else if ( nLen > 2 && ( aName == p + 2 ) && ( Class() == CDC_Information ) )
2278 const sal_Unicode* pStr = aStr.getStr();
2279 if ( *(pStr + 1) != 'i')
2280 return INV_MATCHLEV;
2281 sal_Int16 n;
2282 switch( *pStr )
2284 case 'k': n = 10; break;
2285 case 'M': n = 20; break;
2286 case 'G': n = 30; break;
2287 case 'T': n = 40; break;
2288 case 'P': n = 50; break;
2289 case 'E': n = 60; break;
2290 case 'Z': n = 70; break;
2291 case 'Y': n = 80; break;
2292 default:
2293 n = INV_MATCHLEV;
2295 return n;
2297 else
2298 return INV_MATCHLEV;
2303 double ConvertData::Convert(
2304 double f, const ConvertData& r, sal_Int16 nLevFrom, sal_Int16 nLevTo ) const THROWDEF_RTE_IAE
2306 if( Class() != r.Class() )
2307 THROW_IAE;
2309 sal_Bool bBinFromLev = ( nLevFrom > 0 && ( nLevFrom % 10 ) == 0 );
2310 sal_Bool bBinToLev = ( nLevTo > 0 && ( nLevTo % 10 ) == 0 );
2312 if ( Class() == CDC_Information && ( bBinFromLev || bBinToLev ) )
2314 if ( bBinFromLev && bBinToLev )
2316 nLevFrom = sal::static_int_cast<sal_Int16>( nLevFrom - nLevTo );
2317 f *= r.fConst / fConst;
2318 if( nLevFrom )
2319 f *= pow( 2.0, nLevFrom );
2321 else if ( bBinFromLev )
2322 f *= ( r.fConst / fConst ) * ( pow( 2.0, nLevFrom ) / pow( 10.0, nLevTo ) );
2323 else
2324 f *= ( r.fConst / fConst ) * ( pow( 10.0, nLevFrom ) / pow( 2.0, nLevTo ) );
2325 return f;
2328 nLevFrom = sal::static_int_cast<sal_Int16>( nLevFrom - nLevTo ); // effective level
2330 f *= r.fConst / fConst;
2332 if( nLevFrom )
2333 f = ::rtl::math::pow10Exp( f, nLevFrom );
2335 return f;
2339 double ConvertData::ConvertToBase( double f, sal_Int16 n ) const
2341 return ::rtl::math::pow10Exp( f / fConst, n );
2345 double ConvertData::ConvertFromBase( double f, sal_Int16 n ) const
2347 return ::rtl::math::pow10Exp( f * fConst, -n );
2352 ConvertDataLinear::~ConvertDataLinear()
2356 double ConvertDataLinear::Convert(
2357 double f, const ConvertData& r, sal_Int16 nLevFrom, sal_Int16 nLevTo ) const THROWDEF_RTE_IAE
2359 if( Class() != r.Class() )
2360 THROW_IAE;
2362 // return ::rtl::math::round( r.ConvertFromBase( ConvertToBase( f, nLevFrom ), nLevTo ), 13 );
2363 return r.ConvertFromBase( ConvertToBase( f, nLevFrom ), nLevTo );
2367 double ConvertDataLinear::ConvertToBase( double f, sal_Int16 n ) const
2369 if( n )
2370 f = ::rtl::math::pow10Exp( f, n );
2372 f /= fConst;
2373 f -= fOffs;
2375 return f;
2379 double ConvertDataLinear::ConvertFromBase( double f, sal_Int16 n ) const
2381 f += fOffs;
2382 f *= fConst;
2384 if( n )
2385 f = ::rtl::math::pow10Exp( f, -n );
2387 return f;
2393 ConvertDataList::ConvertDataList( void )
2395 #define NEWD(str,unit,cl) Append(new ConvertData(str,unit,cl))
2396 #define NEWDP(str,unit,cl) Append(new ConvertData(str,unit,cl,sal_True))
2397 #define NEWL(str,unit,offs,cl) Append(new ConvertDataLinear(str,unit,offs,cl))
2398 #define NEWLP(str,unit,offs,cl) Append(new ConvertDataLinear(str,unit,offs,cl,sal_True))
2400 // *** are extra and not standard Excel Analysis Addin!
2402 // MASS: 1 Gram is...
2403 NEWDP( "g", 1.0000000000000000E00, CDC_Mass ); // Gram
2404 NEWD( "sg", 6.8522050005347800E-05, CDC_Mass ); // Pieces
2405 NEWD( "lbm", 2.2046229146913400E-03, CDC_Mass ); // Pound (commercial weight)
2406 NEWDP( "u", 6.0221370000000000E23, CDC_Mass ); // U (atomic mass)
2407 NEWD( "ozm", 3.5273971800362700E-02, CDC_Mass ); // Ounce (commercial weight)
2408 NEWD( "stone", 1.574730e-04, CDC_Mass ); // *** Stone
2409 NEWD( "ton", 1.102311e-06, CDC_Mass ); // *** Ton
2410 NEWD( "grain", 1.543236E01, CDC_Mass ); // *** Grain
2411 NEWD( "pweight", 7.054792E-01, CDC_Mass ); // *** Pennyweight
2412 NEWD( "hweight", 1.968413E-05, CDC_Mass ); // *** Hundredweight
2413 NEWD( "shweight", 2.204623E-05, CDC_Mass ); // *** Shorthundredweight
2414 NEWD( "brton", 9.842065E-07, CDC_Mass ); // *** Gross Registered Ton
2415 NEWD( "cwt", 2.2046226218487758E-05, CDC_Mass ); // U.S. (short) hundredweight
2416 NEWD( "shweight", 2.2046226218487758E-05, CDC_Mass ); // U.S. (short) hundredweight also
2417 NEWD( "uk_cwt", 1.9684130552221213E-05, CDC_Mass ); // Imperial hundredweight
2418 NEWD( "lcwt", 1.9684130552221213E-05, CDC_Mass ); // Imperial hundredweight also
2419 NEWD( "hweight", 1.9684130552221213E-05, CDC_Mass ); // Imperial hundredweight also
2420 NEWD( "uk_ton", 9.8420652761106063E-07, CDC_Mass ); // Imperial ton
2421 NEWD( "LTON", 9.8420652761106063E-07, CDC_Mass ); // Imperial ton also
2423 // LENGTH: 1 Meter is...
2424 NEWDP( "m", 1.0000000000000000E00, CDC_Length ); // Meter
2425 NEWD( "mi", 6.2137119223733397E-04, CDC_Length ); // Britsh Mile 6,21371192237333969617434184363e-4
2426 NEWD( "Nmi", 5.3995680345572354E-04, CDC_Length ); // Nautical Mile 5,39956803455723542116630669546e-4
2427 NEWD( "in", 3.9370078740157480E01, CDC_Length ); // Inch 39,37007874015748031496062992126
2428 NEWD( "ft", 3.2808398950131234E00, CDC_Length ); // Foot 3,2808398950131233595800524934383
2429 NEWD( "yd", 1.0936132983377078E00, CDC_Length ); // Yard 1,0936132983377077865266841644794
2430 NEWD( "ang", 1.0000000000000000E10, CDC_Length ); // Angstroem
2431 NEWD( "Pica", 2.8346456692913386E03, CDC_Length ); // Pica (1/72 Inch) 2834,6456692913385826771653543307
2432 NEWD( "ell", 8.748906E-01, CDC_Length ); // *** Ell
2433 NEWDP( "parsec", 3.240779E-17, CDC_Length ); // *** Parsec
2434 NEWDP( "pc", 3.240779E-17, CDC_Length ); // *** Parsec also
2435 NEWDP( "lightyear", 1.0570234557732930E-16, CDC_Length ); // *** Light Year
2436 NEWDP( "ly", 1.0570234557732930E-16, CDC_Length ); // *** Light Year also
2437 NEWD( "survey_mi", 6.2136994949494949E-04, CDC_Length ); // U.S. survey mile
2439 // TIME: 1 Second is...
2440 NEWD( "yr", 3.1688087814028950E-08, CDC_Time ); // Year
2441 NEWD( "day", 1.1574074074074074E-05, CDC_Time ); // Day
2442 NEWD( "d", 1.1574074074074074E-05, CDC_Time ); // Day also
2443 NEWD( "hr", 2.7777777777777778E-04, CDC_Time ); // Hour
2444 NEWD( "mn", 1.6666666666666667E-02, CDC_Time ); // Minute
2445 NEWD( "min", 1.6666666666666667E-02, CDC_Time ); // Minute also
2446 NEWDP( "sec", 1.0000000000000000E00, CDC_Time ); // Second
2447 NEWDP( "s", 1.0000000000000000E00, CDC_Time ); // Second also
2449 // PRESSURE: 1 Pascal is...
2450 NEWDP( "Pa", 1.0000000000000000E00, CDC_Pressure ); // Pascal
2451 NEWDP( "atm", 9.8692329999819300E-06, CDC_Pressure ); // Atmosphere
2452 NEWDP( "at", 9.8692329999819300E-06, CDC_Pressure ); // Atmosphere also
2453 NEWDP( "mmHg", 7.5006170799862700E-03, CDC_Pressure ); // mm Hg (Mercury)
2454 NEWD( "Torr", 7.5006380000000000E-03, CDC_Pressure ); // *** Torr
2455 NEWD( "psi", 1.4503770000000000E-04, CDC_Pressure ); // *** Psi
2457 // FORCE: 1 Newton is...
2458 NEWDP( "N", 1.0000000000000000E00, CDC_Force ); // Newton
2459 NEWDP( "dyn", 1.0000000000000000E05, CDC_Force ); // Dyn
2460 NEWDP( "dy", 1.0000000000000000E05, CDC_Force ); // Dyn also
2461 NEWD( "lbf", 2.24808923655339E-01, CDC_Force ); // Pound-Force
2462 NEWDP( "pond", 1.019716E02, CDC_Force ); // *** Pond
2464 // ENERGY: 1 Joule is...
2465 NEWDP( "J", 1.0000000000000000E00, CDC_Energy ); // Joule
2466 NEWDP( "e", 1.0000000000000000E07, CDC_Energy ); // Erg -> http://www.chemie.fu-berlin.de/chemistry/general/si.html
2467 // NEWD( "e", 9.99999519343231E06, CDC_Energy ); // Erg
2468 NEWDP( "c", 2.3900624947346700E-01, CDC_Energy ); // Thermodynamical Calorie
2469 NEWDP( "cal", 2.3884619064201700E-01, CDC_Energy ); // Calorie
2470 NEWDP( "eV", 6.2414570000000000E18, CDC_Energy ); // Electronvolt
2471 NEWDP( "ev", 6.2414570000000000E18, CDC_Energy ); // Electronvolt also
2472 NEWD( "HPh", 3.7250611111111111E-07, CDC_Energy ); // Horsepower Hours
2473 NEWD( "hh", 3.7250611111111111E-07, CDC_Energy ); // Horsepower Hours also
2474 // NEWD( "HPh", 3.72506430801000E-07, CDC_Energy ); // Horsepower Hours
2475 NEWDP( "Wh", 2.7777777777777778E-04, CDC_Energy ); // Watt Hours
2476 NEWDP( "wh", 2.7777777777777778E-04, CDC_Energy ); // Watt Hours also
2477 NEWD( "flb", 2.37304222192651E01, CDC_Energy ); // Foot Pound
2478 NEWD( "BTU", 9.4781506734901500E-04, CDC_Energy ); // British Thermal Unit
2479 NEWD( "btu", 9.4781506734901500E-04, CDC_Energy ); // British Thermal Unit also
2481 // POWER: 1 Watt is...
2482 NEWDP( "W", 1.0000000000000000E00, CDC_Power ); // Watt
2483 NEWDP( "w", 1.0000000000000000E00, CDC_Power ); // Watt also
2484 NEWD( "HP", 1.341022E-03, CDC_Power ); // Horsepower
2485 NEWD( "h", 1.341022E-03, CDC_Power ); // Horsepower also
2486 NEWD( "PS", 1.359622E-03, CDC_Power ); // *** German Pferdestaerke
2487 // NEWD( "HP", 1.4102006031908E-03, CDC_Power ); // Excel seams to be a little bit wrong... either this doesn't fit to J -> HPh
2489 // MAGNETISM: 1 Tesla is...
2490 NEWDP( "T", 1.0000000000000000E00, CDC_Magnetism ); // Tesla
2491 NEWDP( "ga", 1.0000000000000000E04, CDC_Magnetism ); // Gauss
2493 // TEMERATURE: 1 Kelvin is...
2494 NEWL( "C", 1.0000000000000000E00, -2.7315000000000000E02, CDC_Temperature ); // Celsius
2495 NEWL( "cel", 1.0000000000000000E00, -2.7315000000000000E02, CDC_Temperature ); // Celsius also
2496 NEWL( "F", 1.8000000000000000E00, -2.5537222222222222E02, CDC_Temperature ); // Fahrenheit
2497 NEWL( "fah", 1.8000000000000000E00, -2.5537222222222222E02, CDC_Temperature ); // Fahrenheit also
2498 NEWLP( "K", 1.0000000000000000E00, +0.0000000000000000E00, CDC_Temperature ); // Kelvin
2499 NEWLP( "kel", 1.0000000000000000E00, +0.0000000000000000E00, CDC_Temperature ); // Kelvin also
2500 NEWL( "Reau", 8.0000000000000000E-01, -2.7315000000000000E02, CDC_Temperature ); // *** Reaumur
2501 NEWL( "Rank", 1.8000000000000000E00, +0.0000000000000000E00, CDC_Temperature ); // *** Rankine
2503 // VOLUMNE: 1 Liter is...
2504 NEWD( "tsp", 2.0284000000000000E02, CDC_Volume ); // Teaspoon
2505 NEWD( "tbs", 6.7613333333333333E01, CDC_Volume ); // Tablespoon
2506 NEWD( "oz", 3.3806666666666667E01, CDC_Volume ); // Ounce Liquid
2507 NEWD( "cup", 4.2258333333333333E00, CDC_Volume ); // Cup
2508 NEWD( "pt", 2.1129166666666667E00, CDC_Volume ); // US Pint
2509 NEWD( "us_pt", 2.1129166666666667E00, CDC_Volume ); // US Pint also
2510 NEWD( "uk_pt", 1.75975569552166E00, CDC_Volume ); // UK Pint
2511 NEWD( "qt", 1.0564583333333333E00, CDC_Volume ); // Quart
2512 NEWD( "gal", 2.6411458333333333E-01, CDC_Volume ); // Gallone
2513 NEWDP( "l", 1.0000000000000000E00, CDC_Volume ); // Liter
2514 NEWDP( "L", 1.0000000000000000E00, CDC_Volume ); // Liter also
2515 NEWDP( "lt", 1.0000000000000000E00, CDC_Volume ); // Liter also
2516 NEWDP( "m3", 1.0000000000000000E-03, CDC_Volume ); // *** Cubic Meter
2517 NEWD( "mi3", 2.3991275857892772E-13, CDC_Volume ); // *** Cubic Britsh Mile
2518 NEWD( "Nmi3", 1.5742621468581148E-13, CDC_Volume ); // *** Cubic Nautical Mile
2519 NEWD( "in3", 6.1023744094732284E01, CDC_Volume ); // *** Cubic Inch
2520 NEWD( "ft3", 3.5314666721488590E-02, CDC_Volume ); // *** Cubic Foot
2521 NEWD( "yd3", 1.3079506193143922E-03, CDC_Volume ); // *** Cubic Yard
2522 NEWD( "ang3", 1.0000000000000000E27, CDC_Volume ); // *** Cubic Angstroem
2523 NEWD( "Pica3", 2.2776990435870636E07, CDC_Volume ); // *** Cubic Pica
2524 NEWD( "barrel", 6.289811E-03, CDC_Volume ); // *** Barrel (=42gal?)
2525 NEWD( "bushel", 2.837759E-02, CDC_Volume ); // *** Bushel
2526 NEWD( "regton", 3.531467E-04, CDC_Volume ); // *** Register ton
2527 NEWD( "GRT", 3.531467E-04, CDC_Volume ); // *** Register ton also
2528 NEWD( "Schooner", 2.3529411764705882E00, CDC_Volume ); // *** austr. Schooner
2529 NEWD( "Middy", 3.5087719298245614E00, CDC_Volume ); // *** austr. Middy
2530 NEWD( "Glass", 5.0000000000000000E00, CDC_Volume ); // *** austr. Glass
2531 NEWD( "Sixpack", 0.5, CDC_Volume ); // ***
2532 NEWD( "Humpen", 2.0, CDC_Volume ); // ***
2533 NEWD( "ly3", 1.1810108125623799E-51, CDC_Volume ); // *** Cubic light-year
2534 NEWD( "MTON", 1.4125866688595436E00, CDC_Volume ); // *** Measurement ton
2535 NEWD( "tspm", 5.0000000000000000E02, CDC_Volume ); // *** Modern teaspoon
2536 NEWD( "uk_gal", 2.6411458333333333E-01, CDC_Volume ); // U.K. / Imperial gallon ??
2537 NEWD( "uk_qt", 1.0564583333333333E00, CDC_Volume ); // U.K. / Imperial quart ??
2539 // 1 Square Meter is...
2540 NEWDP( "m2", 1.0000000000000000E00, CDC_Area ); // *** Square Meter
2541 NEWD( "mi2", 3.8610215854244585E-07, CDC_Area ); // *** Square Britsh Mile
2542 NEWD( "Nmi2", 2.9155334959812286E-07, CDC_Area ); // *** Square Nautical Mile
2543 NEWD( "in2", 1.5500031000062000E03, CDC_Area ); // *** Square Inch
2544 NEWD( "ft2", 1.0763910416709722E01, CDC_Area ); // *** Square Foot
2545 NEWD( "yd2", 1.1959900463010803E00, CDC_Area ); // *** Square Yard
2546 NEWDP( "ang2", 1.0000000000000000E20, CDC_Area ); // *** Square Angstroem
2547 NEWD( "Pica2", 8.0352160704321409E06, CDC_Area ); // *** Square Pica
2548 NEWD( "Morgen", 4.0000000000000000E-04, CDC_Area ); // *** Morgen
2549 NEWDP( "ar", 1.000000E-02, CDC_Area ); // *** Ar
2550 NEWD( "acre", 2.471053815E-04, CDC_Area ); // *** Acre
2551 NEWD( "uk_acre", 2.4710538146716534E-04, CDC_Area ); // *** International acre
2552 NEWD( "us_acre", 2.4710439304662790E-04, CDC_Area ); // *** U.S. survey/statute acre
2553 NEWD( "ly2", 1.1172985860549147E-32, CDC_Area ); // *** Square Light-year
2554 NEWD( "ha", 1.000000E-04, CDC_Area ); // *** Hectare
2555 NEWD( "Quadratlatschen",5.6689342403628117914,CDC_Area ); // ***
2557 // SPEED: 1 Meter per Second is...
2558 NEWDP( "m/s", 1.0000000000000000E00, CDC_Speed ); // *** Meters per Second
2559 NEWDP( "m/sec", 1.0000000000000000E00, CDC_Speed ); // *** Meters per Second also
2560 NEWD( "m/h", 3.6000000000000000E03, CDC_Speed ); // *** Meters per Hour
2561 NEWD( "m/hr", 3.6000000000000000E03, CDC_Speed ); // *** Meters per Hour also
2562 NEWD( "mph", 2.2369362920544023E00, CDC_Speed ); // *** Britsh Miles per Hour
2563 NEWD( "kn", 1.9438444924406048E00, CDC_Speed ); // *** Knot = Nautical Miles per Hour
2564 NEWD( "admkn", 1.9438446603753486E00, CDC_Speed ); // *** Admiralty Knot
2565 NEWD( "wahnsinnige Geschwindigkeit", 2.0494886343432328E-14, CDC_Speed ); // ***
2566 NEWD( "ludicrous speed", 2.0494886343432328E-14, CDC_Speed ); // ***
2567 NEWD( "laecherliche Geschwindigkeit", 4.0156958471424288E-06, CDC_Speed); // ***
2568 NEWD( "ridiculous speed", 4.0156958471424288E-06, CDC_Speed); // ***
2570 // INFORMATION: 1 Bit is...
2571 NEWDP( "bit", 1.00E00, CDC_Information); // *** Bit
2572 NEWDP( "byte", 1.25E-01, CDC_Information); // *** Byte
2576 ConvertDataList::~ConvertDataList()
2578 for( ConvertData* p = First() ; p ; p = Next() )
2579 delete p;
2583 double ConvertDataList::Convert( double fVal, const STRING& rFrom, const STRING& rTo ) THROWDEF_RTE_IAE
2585 // This will not catch illegal units
2586 // if( rFrom == rTo )
2587 // return fVal;
2589 ConvertData* pFrom = NULL;
2590 ConvertData* pTo = NULL;
2591 sal_Bool bSearchFrom = sal_True;
2592 sal_Bool bSearchTo = sal_True;
2593 sal_Int16 nLevelFrom = 0;
2594 sal_Int16 nLevelTo = 0;
2596 ConvertData* p = First();
2597 while( p && ( bSearchFrom || bSearchTo ) )
2599 if( bSearchFrom )
2601 sal_Int16 n = p->GetMatchingLevel( rFrom );
2602 if( n != INV_MATCHLEV )
2604 if( n )
2605 { // only first match for partial equality rulz a little bit more
2606 pFrom = p;
2607 nLevelFrom = n;
2609 else
2610 { // ... but exact match rulz most
2611 pFrom = p;
2612 bSearchFrom = sal_False;
2613 nLevelFrom = n;
2618 if( bSearchTo )
2620 sal_Int16 n = p->GetMatchingLevel( rTo );
2621 if( n != INV_MATCHLEV )
2623 if( n )
2624 { // only first match for partial equality rulz a little bit more
2625 pTo = p;
2626 nLevelTo = n;
2628 else
2629 { // ... but exact match rulz most
2630 pTo = p;
2631 bSearchTo = sal_False;
2632 nLevelTo = n;
2637 p = Next();
2640 if( pFrom && pTo )
2641 return pFrom->Convert( fVal, *pTo, nLevelFrom, nLevelTo );
2642 else
2643 THROW_IAE;
2648 //-----------------------------------------------------------------------------
2650 ScaDate::ScaDate() :
2651 nOrigDay( 1 ),
2652 nDay( 1 ),
2653 nMonth( 1 ),
2654 nYear( 1900 ),
2655 bLastDayMode( sal_True ),
2656 bLastDay( sal_False ),
2657 b30Days( sal_False ),
2658 bUSMode( sal_False )
2662 ScaDate::ScaDate( sal_Int32 nNullDate, sal_Int32 nDate, sal_Int32 nBase )
2664 DaysToDate( nNullDate + nDate, nOrigDay, nMonth, nYear );
2665 bLastDayMode = (nBase != 5);
2666 bLastDay = (nOrigDay >= ::DaysInMonth( nMonth, nYear ));
2667 b30Days = (nBase == 0) || (nBase == 4);
2668 bUSMode = (nBase == 0);
2669 setDay();
2672 ScaDate::ScaDate( const ScaDate& rCopy ) :
2673 nOrigDay( rCopy.nOrigDay ),
2674 nDay( rCopy.nDay ),
2675 nMonth( rCopy.nMonth ),
2676 nYear( rCopy.nYear ),
2677 bLastDayMode( rCopy.bLastDayMode ),
2678 bLastDay( rCopy.bLastDay ),
2679 b30Days( rCopy.b30Days ),
2680 bUSMode( rCopy.bUSMode )
2684 ScaDate& ScaDate::operator=( const ScaDate& rCopy )
2686 if( this != &rCopy )
2688 nOrigDay = rCopy.nOrigDay;
2689 nDay = rCopy.nDay;
2690 nMonth = rCopy.nMonth;
2691 nYear = rCopy.nYear;
2692 bLastDayMode = rCopy.bLastDayMode;
2693 bLastDay = rCopy.bLastDay;
2694 b30Days = rCopy.b30Days;
2695 bUSMode = rCopy.bUSMode;
2697 return *this;
2700 void ScaDate::setDay()
2702 if( b30Days )
2704 // 30-days-mode: set nDay to 30 if original was last day in month
2705 nDay = Min( nOrigDay, static_cast< sal_uInt16 >( 30 ) );
2706 if( bLastDay || (nDay >= ::DaysInMonth( nMonth, nYear )) )
2707 nDay = 30;
2709 else
2711 // set nDay to last day in this month if original was last day
2712 sal_uInt16 nLastDay = ::DaysInMonth( nMonth, nYear );
2713 nDay = bLastDay ? nLastDay : Min( nOrigDay, nLastDay );
2717 sal_Int32 ScaDate::getDaysInMonthRange( sal_uInt16 nFrom, sal_uInt16 nTo ) const
2719 if( nFrom > nTo )
2720 return 0;
2722 sal_Int32 nRet = 0;
2723 if( b30Days )
2724 nRet = (nTo - nFrom + 1) * 30;
2725 else
2727 for( sal_uInt16 nMonthIx = nFrom; nMonthIx <= nTo; ++nMonthIx )
2728 nRet += getDaysInMonth( nMonthIx );
2730 return nRet;
2733 sal_Int32 ScaDate::getDaysInYearRange( sal_uInt16 nFrom, sal_uInt16 nTo ) const
2735 if( nFrom > nTo )
2736 return 0;
2738 return b30Days ? ((nTo - nFrom + 1) * 360) : ::GetDaysInYears( nFrom, nTo );
2741 void ScaDate::doAddYears( sal_Int32 nYearCount ) throw( lang::IllegalArgumentException )
2743 sal_Int32 nNewYear = nYearCount + nYear;
2744 if( (nNewYear < 0) || (nNewYear > 0x7FFF) )
2745 throw lang::IllegalArgumentException();
2746 nYear = static_cast< sal_uInt16 >( nNewYear );
2749 void ScaDate::addMonths( sal_Int32 nMonthCount ) throw( lang::IllegalArgumentException )
2751 sal_Int32 nNewMonth = nMonthCount + nMonth;
2752 if( nNewMonth > 12 )
2754 --nNewMonth;
2755 doAddYears( nNewMonth / 12 );
2756 nMonth = static_cast< sal_uInt16 >( nNewMonth % 12 ) + 1;
2758 else if( nNewMonth < 1 )
2760 doAddYears( nNewMonth / 12 - 1 );
2761 nMonth = static_cast< sal_uInt16 >( nNewMonth % 12 + 12 );
2763 else
2764 nMonth = static_cast< sal_uInt16 >( nNewMonth );
2765 setDay();
2768 sal_Int32 ScaDate::getDate( sal_Int32 nNullDate ) const
2770 sal_uInt16 nLastDay = ::DaysInMonth( nMonth, nYear );
2771 sal_uInt16 nRealDay = (bLastDayMode && bLastDay) ? nLastDay : Min( nLastDay, nOrigDay );
2772 return ::DateToDays( nRealDay, nMonth, nYear ) - nNullDate;
2775 sal_Int32 ScaDate::getDiff( const ScaDate& rFrom, const ScaDate& rTo ) throw( lang::IllegalArgumentException )
2777 if( rFrom > rTo )
2778 return getDiff( rTo, rFrom );
2780 sal_Int32 nDiff = 0;
2781 ScaDate aFrom( rFrom );
2782 ScaDate aTo( rTo );
2784 if( rTo.b30Days )
2786 // corrections for base 0 (US NASD)
2787 if( rTo.bUSMode )
2789 if( ((rFrom.nMonth == 2) || (rFrom.nDay < 30)) && (aTo.nOrigDay == 31) )
2790 aTo.nDay = 31;
2791 else if( (aTo.nMonth == 2) && aTo.bLastDay )
2792 aTo.nDay = ::DaysInMonth( 2, aTo.nYear );
2794 // corrections for base 4 (Europe)
2795 else
2797 if( (aFrom.nMonth == 2) && (aFrom.nDay == 30) )
2798 aFrom.nDay = ::DaysInMonth( 2, aFrom.nYear );
2799 if( (aTo.nMonth == 2) && (aTo.nDay == 30) )
2800 aTo.nDay = ::DaysInMonth( 2, aTo.nYear );
2804 if( (aFrom.nYear < aTo.nYear) || ((aFrom.nYear == aTo.nYear) && (aFrom.nMonth < aTo.nMonth)) )
2806 // move aFrom to 1st day of next month
2807 nDiff = aFrom.getDaysInMonth() - aFrom.nDay + 1;
2808 aFrom.nOrigDay = aFrom.nDay = 1;
2809 aFrom.bLastDay = sal_False;
2810 aFrom.addMonths( 1 );
2812 if( aFrom.nYear < aTo.nYear )
2814 // move aFrom to 1st day of next year
2815 nDiff += aFrom.getDaysInMonthRange( aFrom.nMonth, 12 );
2816 aFrom.addMonths( 13 - aFrom.nMonth );
2818 // move aFrom to 1st day of this year
2819 nDiff += aFrom.getDaysInYearRange( aFrom.nYear, aTo.nYear - 1 );
2820 aFrom.addYears( aTo.nYear - aFrom.nYear );
2823 // move aFrom to 1st day of this month
2824 nDiff += aFrom.getDaysInMonthRange( aFrom.nMonth, aTo.nMonth - 1 );
2825 aFrom.addMonths( aTo.nMonth - aFrom.nMonth );
2827 // finally add remaining days in this month
2828 nDiff += aTo.nDay - aFrom.nDay;
2829 return nDiff > 0 ? nDiff : 0;
2832 sal_Bool ScaDate::operator<( const ScaDate& rCmp ) const
2834 if( nYear != rCmp.nYear )
2835 return nYear < rCmp.nYear;
2836 if( nMonth != rCmp.nMonth )
2837 return nMonth < rCmp.nMonth;
2838 if( nDay != rCmp.nDay )
2839 return nDay < rCmp.nDay;
2840 if( bLastDay || rCmp.bLastDay )
2841 return !bLastDay && rCmp.bLastDay;
2842 return nOrigDay < rCmp.nOrigDay;
2847 //-----------------------------------------------------------------------------
2849 ScaAnyConverter::ScaAnyConverter( const uno::Reference< lang::XMultiServiceFactory >& xServiceFact ) :
2850 bHasValidFormat( sal_False )
2852 if( xServiceFact.is() )
2854 uno::Reference< uno::XInterface > xInstance = xServiceFact->createInstance(
2855 OUString::createFromAscii( "com.sun.star.util.NumberFormatter" ) );
2856 xFormatter = uno::Reference< util::XNumberFormatter >( xInstance, uno::UNO_QUERY );
2860 ScaAnyConverter::~ScaAnyConverter()
2864 void ScaAnyConverter::init( const uno::Reference< beans::XPropertySet >& xPropSet ) throw( uno::RuntimeException )
2866 // try to get default number format
2867 bHasValidFormat = sal_False;
2868 if( xFormatter.is() )
2870 // get XFormatsSupplier from outer XPropertySet
2871 uno::Reference< util::XNumberFormatsSupplier > xFormatsSupp( xPropSet, uno::UNO_QUERY );
2872 if( xFormatsSupp.is() )
2874 // get XNumberFormatTypes from XNumberFormatsSupplier to get standard index
2875 uno::Reference< util::XNumberFormats > xFormats( xFormatsSupp->getNumberFormats() );
2876 uno::Reference< util::XNumberFormatTypes > xFormatTypes( xFormats, uno::UNO_QUERY );
2877 if( xFormatTypes.is() )
2879 lang::Locale eLocale;
2880 nDefaultFormat = xFormatTypes->getStandardIndex( eLocale );
2881 xFormatter->attachNumberFormatsSupplier( xFormatsSupp );
2882 bHasValidFormat = sal_True;
2888 double ScaAnyConverter::convertToDouble( const OUString& rString ) const throw( lang::IllegalArgumentException )
2890 double fValue = 0.0;
2891 if( bHasValidFormat )
2895 fValue = xFormatter->convertStringToNumber( nDefaultFormat, rString );
2897 catch( uno::Exception& )
2899 throw lang::IllegalArgumentException();
2902 else
2904 rtl_math_ConversionStatus eStatus;
2905 sal_Int32 nEnd;
2906 fValue = ::rtl::math::stringToDouble( rString, '.', ',', &eStatus, &nEnd );
2907 if( (eStatus != rtl_math_ConversionStatus_Ok) || (nEnd < rString.getLength()) )
2908 throw lang::IllegalArgumentException();
2910 return fValue;
2913 sal_Bool ScaAnyConverter::getDouble(
2914 double& rfResult,
2915 const uno::Any& rAny ) const throw( lang::IllegalArgumentException )
2917 rfResult = 0.0;
2918 sal_Bool bContainsVal = sal_True;
2919 switch( rAny.getValueTypeClass() )
2921 case uno::TypeClass_VOID:
2922 bContainsVal = sal_False;
2923 break;
2924 case uno::TypeClass_DOUBLE:
2925 rAny >>= rfResult;
2926 break;
2927 case uno::TypeClass_STRING:
2929 const OUString* pString = static_cast< const OUString* >( rAny.getValue() );
2930 if( pString->getLength() )
2931 rfResult = convertToDouble( *pString );
2932 else
2933 bContainsVal = sal_False;
2935 break;
2936 default:
2937 throw lang::IllegalArgumentException();
2939 return bContainsVal;
2942 sal_Bool ScaAnyConverter::getDouble(
2943 double& rfResult,
2944 const uno::Reference< beans::XPropertySet >& xPropSet,
2945 const uno::Any& rAny ) throw( uno::RuntimeException, lang::IllegalArgumentException )
2947 init( xPropSet );
2948 return getDouble( rfResult, rAny );
2951 double ScaAnyConverter::getDouble(
2952 const uno::Reference< beans::XPropertySet >& xPropSet,
2953 const uno::Any& rAny,
2954 double fDefault ) throw( uno::RuntimeException, lang::IllegalArgumentException )
2956 double fResult;
2957 if( !getDouble( fResult, xPropSet, rAny ) )
2958 fResult = fDefault;
2959 return fResult;
2962 sal_Bool ScaAnyConverter::getInt32(
2963 sal_Int32& rnResult,
2964 const uno::Reference< beans::XPropertySet >& xPropSet,
2965 const uno::Any& rAny ) throw( uno::RuntimeException, lang::IllegalArgumentException )
2967 double fResult;
2968 sal_Bool bContainsVal = getDouble( fResult, xPropSet, rAny );
2969 if( (fResult <= -2147483649.0) || (fResult >= 2147483648.0) )
2970 throw lang::IllegalArgumentException();
2972 rnResult = static_cast< sal_Int32 >( fResult );
2973 return bContainsVal;
2976 sal_Int32 ScaAnyConverter::getInt32(
2977 const uno::Reference< beans::XPropertySet >& xPropSet,
2978 const uno::Any& rAny,
2979 sal_Int32 nDefault ) throw( uno::RuntimeException, lang::IllegalArgumentException )
2981 sal_Int32 nResult;
2982 if( !getInt32( nResult, xPropSet, rAny ) )
2983 nResult = nDefault;
2984 return nResult;
2989 //-----------------------------------------------------------------------------