merged tag ooo/DEV300_m102
[LibreOffice.git] / scaddins / source / analysis / analysishelper.cxx
blobd929e1427f4b88ccea2f9f96fdb525526b305da1
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2000, 2010 Oracle and/or its affiliates.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * This file is part of OpenOffice.org.
11 * OpenOffice.org is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License version 3
13 * only, as published by the Free Software Foundation.
15 * OpenOffice.org is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License version 3 for more details
19 * (a copy is included in the LICENSE file that accompanied this code).
21 * You should have received a copy of the GNU Lesser General Public License
22 * version 3 along with OpenOffice.org. If not, see
23 * <http://www.openoffice.org/license.html>
24 * for a copy of the LGPLv3 License.
26 ************************************************************************/
28 #include <com/sun/star/util/XNumberFormatTypes.hpp>
30 #include <string.h>
31 #include <stdio.h>
32 #include <tools/resary.hxx>
33 #include <rtl/math.hxx>
34 #include "analysishelper.hxx"
35 #include "analysis.hrc"
37 using namespace ::rtl;
38 using namespace ::com::sun::star;
42 #define UNIQUE sal_False // function name does not exist in Calc
43 #define DOUBLE sal_True // function name exists in Calc
45 #define STDPAR sal_False // all parameters are described
46 #define INTPAR sal_True // first parameter is internal
48 #define FUNCDATA( FUNCNAME, DBL, OPT, NUMOFPAR, CAT ) \
49 { "get" #FUNCNAME, ANALYSIS_FUNCNAME_##FUNCNAME, ANALYSIS_##FUNCNAME, DBL, OPT, ANALYSIS_DEFFUNCNAME_##FUNCNAME, NUMOFPAR, CAT }
51 const FuncDataBase pFuncDatas[] =
53 // UNIQUE or INTPAR or
54 // function name DOUBLE STDPAR # of param category
55 FUNCDATA( Workday, UNIQUE, INTPAR, 3, FDCat_DateTime ),
56 FUNCDATA( Yearfrac, UNIQUE, INTPAR, 3, FDCat_DateTime ),
57 FUNCDATA( Edate, UNIQUE, INTPAR, 2, FDCat_DateTime ),
58 FUNCDATA( Weeknum, DOUBLE, INTPAR, 2, FDCat_DateTime ),
59 FUNCDATA( Eomonth, UNIQUE, INTPAR, 2, FDCat_DateTime ),
60 FUNCDATA( Networkdays, UNIQUE, INTPAR, 3, FDCat_DateTime ),
61 FUNCDATA( Iseven, DOUBLE, STDPAR, 1, FDCat_Inf ),
62 FUNCDATA( Isodd, DOUBLE, STDPAR, 1, FDCat_Inf ),
63 FUNCDATA( Multinomial, UNIQUE, STDPAR, 1, FDCat_Math ),
64 FUNCDATA( Seriessum, UNIQUE, STDPAR, 4, FDCat_Math ),
65 FUNCDATA( Quotient, UNIQUE, STDPAR, 2, FDCat_Math ),
66 FUNCDATA( Mround, UNIQUE, STDPAR, 2, FDCat_Math ),
67 FUNCDATA( Sqrtpi, UNIQUE, STDPAR, 1, FDCat_Math ),
68 FUNCDATA( Randbetween, UNIQUE, STDPAR, 2, FDCat_Math ),
69 FUNCDATA( Gcd, DOUBLE, INTPAR, 1, FDCat_Math ),
70 FUNCDATA( Lcm, DOUBLE, INTPAR, 1, FDCat_Math ),
71 FUNCDATA( Besseli, UNIQUE, STDPAR, 2, FDCat_Tech ),
72 FUNCDATA( Besselj, UNIQUE, STDPAR, 2, FDCat_Tech ),
73 FUNCDATA( Besselk, UNIQUE, STDPAR, 2, FDCat_Tech ),
74 FUNCDATA( Bessely, UNIQUE, STDPAR, 2, FDCat_Tech ),
75 FUNCDATA( Bin2Oct, UNIQUE, INTPAR, 2, FDCat_Tech ),
76 FUNCDATA( Bin2Dec, UNIQUE, STDPAR, 1, FDCat_Tech ),
77 FUNCDATA( Bin2Hex, UNIQUE, INTPAR, 2, FDCat_Tech ),
78 FUNCDATA( Oct2Bin, UNIQUE, INTPAR, 2, FDCat_Tech ),
79 FUNCDATA( Oct2Dec, UNIQUE, STDPAR, 1, FDCat_Tech ),
80 FUNCDATA( Oct2Hex, UNIQUE, INTPAR, 2, FDCat_Tech ),
81 FUNCDATA( Dec2Bin, UNIQUE, INTPAR, 2, FDCat_Tech ),
82 FUNCDATA( Dec2Hex, UNIQUE, INTPAR, 2, FDCat_Tech ),
83 FUNCDATA( Dec2Oct, UNIQUE, INTPAR, 2, FDCat_Tech ),
84 FUNCDATA( Hex2Bin, UNIQUE, INTPAR, 2, FDCat_Tech ),
85 FUNCDATA( Hex2Dec, UNIQUE, STDPAR, 1, FDCat_Tech ),
86 FUNCDATA( Hex2Oct, UNIQUE, INTPAR, 2, FDCat_Tech ),
87 FUNCDATA( Delta, UNIQUE, INTPAR, 2, FDCat_Tech ),
88 FUNCDATA( Erf, UNIQUE, INTPAR, 2, FDCat_Tech ),
89 FUNCDATA( Erfc, UNIQUE, STDPAR, 1, FDCat_Tech ),
90 FUNCDATA( Gestep, UNIQUE, INTPAR, 2, FDCat_Tech ),
91 FUNCDATA( Factdouble, UNIQUE, STDPAR, 1, FDCat_Tech ),
92 FUNCDATA( Imabs, UNIQUE, STDPAR, 1, FDCat_Tech ),
93 FUNCDATA( Imaginary, UNIQUE, STDPAR, 1, FDCat_Tech ),
94 FUNCDATA( Impower, UNIQUE, STDPAR, 2, FDCat_Tech ),
95 FUNCDATA( Imargument, UNIQUE, STDPAR, 1, FDCat_Tech ),
96 FUNCDATA( Imcos, UNIQUE, STDPAR, 1, FDCat_Tech ),
97 FUNCDATA( Imdiv, UNIQUE, STDPAR, 2, FDCat_Tech ),
98 FUNCDATA( Imexp, UNIQUE, STDPAR, 1, FDCat_Tech ),
99 FUNCDATA( Imconjugate, UNIQUE, STDPAR, 1, FDCat_Tech ),
100 FUNCDATA( Imln, UNIQUE, STDPAR, 1, FDCat_Tech ),
101 FUNCDATA( Imlog10, UNIQUE, STDPAR, 1, FDCat_Tech ),
102 FUNCDATA( Imlog2, UNIQUE, STDPAR, 1, FDCat_Tech ),
103 FUNCDATA( Improduct, UNIQUE, INTPAR, 2, FDCat_Tech ),
104 FUNCDATA( Imreal, UNIQUE, STDPAR, 1, FDCat_Tech ),
105 FUNCDATA( Imsin, UNIQUE, STDPAR, 1, FDCat_Tech ),
106 FUNCDATA( Imsub, UNIQUE, STDPAR, 2, FDCat_Tech ),
107 FUNCDATA( Imsqrt, UNIQUE, STDPAR, 1, FDCat_Tech ),
108 FUNCDATA( Imsum, UNIQUE, INTPAR, 1, FDCat_Tech ),
109 FUNCDATA( Complex, UNIQUE, STDPAR, 3, FDCat_Tech ),
110 FUNCDATA( Convert, DOUBLE, STDPAR, 3, FDCat_Tech ),
111 FUNCDATA( Amordegrc, UNIQUE, INTPAR, 7, FDCat_Finance ),
112 FUNCDATA( Amorlinc, UNIQUE, INTPAR, 7, FDCat_Finance ),
113 FUNCDATA( Accrint, UNIQUE, INTPAR, 7, FDCat_Finance ),
114 FUNCDATA( Accrintm, UNIQUE, INTPAR, 5, FDCat_Finance ),
115 FUNCDATA( Received, UNIQUE, INTPAR, 5, FDCat_Finance ),
116 FUNCDATA( Disc, UNIQUE, INTPAR, 5, FDCat_Finance ),
117 FUNCDATA( Duration, DOUBLE, INTPAR, 6, FDCat_Finance ),
118 FUNCDATA( Effect, DOUBLE, STDPAR, 2, FDCat_Finance ),
119 FUNCDATA( Cumprinc, DOUBLE, STDPAR, 6, FDCat_Finance ),
120 FUNCDATA( Cumipmt, DOUBLE, STDPAR, 6, FDCat_Finance ),
121 FUNCDATA( Price, UNIQUE, INTPAR, 7, FDCat_Finance ),
122 FUNCDATA( Pricedisc, UNIQUE, INTPAR, 5, FDCat_Finance ),
123 FUNCDATA( Pricemat, UNIQUE, INTPAR, 6, FDCat_Finance ),
124 FUNCDATA( Mduration, UNIQUE, INTPAR, 6, FDCat_Finance ),
125 FUNCDATA( Nominal, DOUBLE, STDPAR, 2, FDCat_Finance ),
126 FUNCDATA( Dollarfr, UNIQUE, STDPAR, 2, FDCat_Finance ),
127 FUNCDATA( Dollarde, UNIQUE, STDPAR, 2, FDCat_Finance ),
128 FUNCDATA( Yield, UNIQUE, INTPAR, 7, FDCat_Finance ),
129 FUNCDATA( Yielddisc, UNIQUE, INTPAR, 5, FDCat_Finance ),
130 FUNCDATA( Yieldmat, UNIQUE, INTPAR, 6, FDCat_Finance ),
131 FUNCDATA( Tbilleq, UNIQUE, INTPAR, 3, FDCat_Finance ),
132 FUNCDATA( Tbillprice, UNIQUE, INTPAR, 3, FDCat_Finance ),
133 FUNCDATA( Tbillyield, UNIQUE, INTPAR, 3, FDCat_Finance ),
134 FUNCDATA( Oddfprice, UNIQUE, INTPAR, 9, FDCat_Finance ),
135 FUNCDATA( Oddfyield, UNIQUE, INTPAR, 9, FDCat_Finance ),
136 FUNCDATA( Oddlprice, UNIQUE, INTPAR, 8, FDCat_Finance ),
137 FUNCDATA( Oddlyield, UNIQUE, INTPAR, 8, FDCat_Finance ),
138 FUNCDATA( Xirr, UNIQUE, INTPAR, 3, FDCat_Finance ),
139 FUNCDATA( Xnpv, UNIQUE, STDPAR, 3, FDCat_Finance ),
140 FUNCDATA( Intrate, UNIQUE, INTPAR, 5, FDCat_Finance ),
141 FUNCDATA( Coupncd, UNIQUE, INTPAR, 4, FDCat_Finance ),
142 FUNCDATA( Coupdays, UNIQUE, INTPAR, 4, FDCat_Finance ),
143 FUNCDATA( Coupdaysnc, UNIQUE, INTPAR, 4, FDCat_Finance ),
144 FUNCDATA( Coupdaybs, UNIQUE, INTPAR, 4, FDCat_Finance ),
145 FUNCDATA( Couppcd, UNIQUE, INTPAR, 4, FDCat_Finance ),
146 FUNCDATA( Coupnum, UNIQUE, INTPAR, 4, FDCat_Finance ),
147 FUNCDATA( Fvschedule, UNIQUE, STDPAR, 2, FDCat_Finance )
149 #undef FUNCDATA
152 sal_uInt16 DaysInMonth( sal_uInt16 nMonth, sal_uInt16 nYear )
154 if( (nMonth == 2) && IsLeapYear( nYear ) )
155 return 29;
156 static const sal_uInt16 aDaysInMonth[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
157 return aDaysInMonth[ nMonth ];
162 * Convert a date to a count of days starting from 01/01/0001
164 * The internal representation of a Date used in this Addin
165 * is the number of days between 01/01/0001 and the date
166 * this function converts a Day , Month, Year representation
167 * to this internal Date value.
171 sal_Int32 DateToDays( sal_uInt16 nDay, sal_uInt16 nMonth, sal_uInt16 nYear )
173 sal_Int32 nDays = ((sal_Int32)nYear-1) * 365;
174 nDays += ((nYear-1) / 4) - ((nYear-1) / 100) + ((nYear-1) / 400);
176 for( sal_uInt16 i = 1; i < nMonth; i++ )
177 nDays += DaysInMonth(i,nYear);
178 nDays += nDay;
180 return nDays;
185 * Convert a count of days starting from 01/01/0001 to a date
187 * The internal representation of a Date used in this Addin
188 * is the number of days between 01/01/0001 and the date
189 * this function converts this internal Date value
190 * to a Day , Month, Year representation of a Date.
194 void DaysToDate( sal_Int32 nDays, sal_uInt16& rDay, sal_uInt16& rMonth, sal_uInt16& rYear )
195 throw( lang::IllegalArgumentException )
197 if( nDays < 0 )
198 throw lang::IllegalArgumentException();
200 sal_Int32 nTempDays;
201 sal_Int32 i = 0;
202 sal_Bool bCalc;
206 nTempDays = nDays;
207 rYear = (sal_uInt16)((nTempDays / 365) - i);
208 nTempDays -= ((sal_Int32) rYear -1) * 365;
209 nTempDays -= (( rYear -1) / 4) - (( rYear -1) / 100) + ((rYear -1) / 400);
210 bCalc = sal_False;
211 if ( nTempDays < 1 )
213 i++;
214 bCalc = sal_True;
216 else
218 if ( nTempDays > 365 )
220 if ( (nTempDays != 366) || !IsLeapYear( rYear ) )
222 i--;
223 bCalc = sal_True;
228 while ( bCalc );
230 rMonth = 1;
231 while ( (sal_Int32)nTempDays > DaysInMonth( rMonth, rYear ) )
233 nTempDays -= DaysInMonth( rMonth, rYear );
234 rMonth++;
236 rDay = (sal_uInt16)nTempDays;
241 * Get the null date used by the spreadsheet document
243 * The internal representation of a Date used in this Addin
244 * is the number of days between 01/01/0001 and the date
245 * this function returns this internal Date value for the document null date
249 sal_Int32 GetNullDate( constREFXPS& xOpt ) THROWDEF_RTE
251 if( xOpt.is() )
255 ANY aAny = xOpt->getPropertyValue( STRFROMASCII( "NullDate" ) );
256 util::Date aDate;
257 if( aAny >>= aDate )
258 return DateToDays( aDate.Day, aDate.Month, aDate.Year );
260 catch( uno::Exception& )
265 // no null date available -> no calculations possible
266 throw uno::RuntimeException();
270 sal_Int32 GetDiffDate360(
271 sal_uInt16 nDay1, sal_uInt16 nMonth1, sal_uInt16 nYear1, sal_Bool bLeapYear1,
272 sal_uInt16 nDay2, sal_uInt16 nMonth2, sal_uInt16 nYear2,
273 sal_Bool bUSAMethod )
275 if( nDay1 == 31 )
276 nDay1--;
277 else if( bUSAMethod && ( nMonth1 == 2 && ( nDay1 == 29 || ( nDay1 == 28 && !bLeapYear1 ) ) ) )
278 nDay1 = 30;
280 if( nDay2 == 31 )
282 if( bUSAMethod && nDay1 != 30 )
284 //aDate2 += 1; -> 1.xx.yyyy
285 nDay2 = 1;
286 if( nMonth2 == 12 )
288 nYear2++;
289 nMonth2 = 1;
291 else
292 nMonth2++;
294 else
295 nDay2 = 30;
298 return nDay2 + nMonth2 * 30 + nYear2 * 360 - nDay1 - nMonth1 * 30 - nYear1 * 360;
302 sal_Int32 GetDiffDate360( sal_Int32 nNullDate, sal_Int32 nDate1, sal_Int32 nDate2, sal_Bool bUSAMethod )
304 nDate1 += nNullDate;
305 nDate2 += nNullDate;
307 sal_uInt16 nDay1, nMonth1, nYear1, nDay2, nMonth2, nYear2;
309 DaysToDate( nDate1, nDay1, nMonth1, nYear1 );
310 DaysToDate( nDate2, nDay2, nMonth2, nYear2 );
312 return GetDiffDate360( nDay1, nMonth1, nYear1, IsLeapYear( nYear1 ), nDay2, nMonth2, nYear2, bUSAMethod );
316 sal_Int32 GetDaysInYears( sal_uInt16 nYear1, sal_uInt16 nYear2 )
318 sal_uInt16 nLeaps = 0;
319 for( sal_uInt16 n = nYear1 ; n <= nYear2 ; n++ )
321 if( IsLeapYear( n ) )
322 nLeaps++;
325 sal_uInt32 nSum = 1;
326 nSum += nYear2;
327 nSum -= nYear1;
328 nSum *= 365;
329 nSum += nLeaps;
331 return nSum;
335 void GetDiffParam( sal_Int32 nNullDate, sal_Int32 nStartDate, sal_Int32 nEndDate, sal_Int32 nMode,
336 sal_uInt16& rYears, sal_Int32& rDayDiffPart, sal_Int32& rDaysInYear ) THROWDEF_RTE_IAE
338 if( nStartDate > nEndDate )
340 sal_Int32 n = nEndDate;
341 nEndDate = nStartDate;
342 nStartDate = n;
345 sal_Int32 nDate1 = nStartDate + nNullDate;
346 sal_Int32 nDate2 = nEndDate + nNullDate;
348 sal_uInt16 nDay1, nDay2;
349 sal_uInt16 nMonth1, nMonth2;
350 sal_uInt16 nYear1, nYear2;
352 DaysToDate( nDate1, nDay1, nMonth1, nYear1 );
353 DaysToDate( nDate2, nDay2, nMonth2, nYear2 );
355 sal_uInt16 nYears;
357 sal_Int32 nDayDiff, nDaysInYear;
359 switch( nMode )
361 case 0: // 0=USA (NASD) 30/360
362 case 4: // 4=Europe 30/360
363 nDaysInYear = 360;
364 nYears = nYear2 - nYear1;
365 nDayDiff = GetDiffDate360( nDay1, nMonth1, nYear1, IsLeapYear( nYear1 ),
366 nDay2, nMonth2, nYear2, nMode == 0 ) - nYears * nDaysInYear;
367 break;
368 case 1: // 1=exact/exact
369 nYears = nYear2 - nYear1;
371 nDaysInYear = IsLeapYear( nYear1 )? 366 : 365;
373 if( nYears && ( nMonth1 > nMonth2 || ( nMonth1 == nMonth2 && nDay1 > nDay2 ) ) )
374 nYears--;
376 if( nYears )
377 nDayDiff = nDate2 - DateToDays( nDay1, nMonth1, nYear2 );
378 else
379 nDayDiff = nDate2 - nDate1;
381 if( nDayDiff < 0 )
382 nDayDiff += nDaysInYear;
384 break;
385 case 2: // 2=exact/360
386 nDaysInYear = 360;
387 nYears = sal_uInt16( ( nDate2 - nDate1 ) / nDaysInYear );
388 nDayDiff = nDate2 - nDate1;
389 nDayDiff %= nDaysInYear;
390 break;
391 case 3: //3=exact/365
392 nDaysInYear = 365;
393 nYears = sal_uInt16( ( nDate2 - nDate1 ) / nDaysInYear );
394 nDayDiff = nDate2 - nDate1;
395 nDayDiff %= nDaysInYear;
396 break;
397 default:
398 THROW_IAE;
401 rYears = nYears;
402 rDayDiffPart = nDayDiff;
403 rDaysInYear = nDaysInYear;
407 sal_Int32 GetDiffDate( sal_Int32 nNullDate, sal_Int32 nStartDate, sal_Int32 nEndDate, sal_Int32 nMode,
408 sal_Int32* pOptDaysIn1stYear ) THROWDEF_RTE_IAE
410 sal_Bool bNeg = nStartDate > nEndDate;
412 if( bNeg )
414 sal_Int32 n = nEndDate;
415 nEndDate = nStartDate;
416 nStartDate = n;
419 sal_Int32 nRet;
421 switch( nMode )
423 case 0: // 0=USA (NASD) 30/360
424 case 4: // 4=Europe 30/360
426 sal_uInt16 nD1, nM1, nY1, nD2, nM2, nY2;
428 nStartDate += nNullDate;
429 nEndDate += nNullDate;
431 DaysToDate( nStartDate, nD1, nM1, nY1 );
432 DaysToDate( nEndDate, nD2, nM2, nY2 );
434 sal_Bool bLeap = IsLeapYear( nY1 );
435 sal_Int32 nDays, nMonths/*, nYears*/;
437 nMonths = nM2 - nM1;
438 nDays = nD2 - nD1;
440 nMonths += ( nY2 - nY1 ) * 12;
442 nRet = nMonths * 30 + nDays;
443 if( nMode == 0 && nM1 == 2 && nM2 != 2 && nY1 == nY2 )
444 nRet -= bLeap? 1 : 2;
446 if( pOptDaysIn1stYear )
447 *pOptDaysIn1stYear = 360;
449 break;
450 case 1: // 1=exact/exact
451 if( pOptDaysIn1stYear )
453 sal_uInt16 nD, nM, nY;
455 DaysToDate( nStartDate + nNullDate, nD, nM, nY );
457 *pOptDaysIn1stYear = IsLeapYear( nY )? 366 : 365;
459 nRet = nEndDate - nStartDate;
460 break;
461 case 2: // 2=exact/360
462 nRet = nEndDate - nStartDate;
463 if( pOptDaysIn1stYear )
464 *pOptDaysIn1stYear = 360;
465 break;
466 case 3: //3=exact/365
467 nRet = nEndDate - nStartDate;
468 if( pOptDaysIn1stYear )
469 *pOptDaysIn1stYear = 365;
470 break;
471 default:
472 THROW_IAE;
475 return bNeg? -nRet : nRet;
479 double GetYearDiff( sal_Int32 nNullDate, sal_Int32 nStartDate, sal_Int32 nEndDate, sal_Int32 nMode ) THROWDEF_RTE_IAE
481 sal_Int32 nDays1stYear;
482 sal_Int32 nTotalDays = GetDiffDate( nNullDate, nStartDate, nEndDate, nMode, &nDays1stYear );
484 return double( nTotalDays ) / double( nDays1stYear );
488 sal_Int32 GetDaysInYear( sal_Int32 nNullDate, sal_Int32 nDate, sal_Int32 nMode ) THROWDEF_RTE_IAE
490 switch( nMode )
492 case 0: // 0=USA (NASD) 30/360
493 case 2: // 2=exact/360
494 case 4: // 4=Europe 30/360
495 return 360;
496 case 1: // 1=exact/exact
498 sal_uInt16 nD, nM, nY;
499 nDate += nNullDate;
500 DaysToDate( nDate, nD, nM, nY );
501 return IsLeapYear( nY )? 366 : 365;
503 case 3: //3=exact/365
504 return 365;
505 default:
506 THROW_IAE;
511 double GetYearFrac( sal_Int32 nNullDate, sal_Int32 nStartDate, sal_Int32 nEndDate, sal_Int32 nMode ) THROWDEF_RTE_IAE
513 if( nStartDate == nEndDate )
514 return 0.0; // nothing to do...
516 sal_uInt16 nYears;
517 sal_Int32 nDayDiff, nDaysInYear;
519 GetDiffParam( nNullDate, nStartDate, nEndDate, nMode, nYears, nDayDiff, nDaysInYear );
521 return double( nYears ) + double( nDayDiff ) / double( nDaysInYear );
525 double Fak( sal_Int32 n )
527 if( n > 0 )
529 double fRet = n;
530 double f = n - 1;
532 while( f >= 2.0 )
534 fRet *= f;
535 f--;
538 return fRet;
540 else if( !n )
541 return 1.0;
542 else
543 return 0.0;
547 double GetGcd( double f1, double f2 )
549 double f = fmod( f1, f2 );
550 while( f > 0.0 )
552 f1 = f2;
553 f2 = f;
554 f = fmod( f1, f2 );
557 return f2;
561 double ConvertToDec( const STRING& aStr, sal_uInt16 nBase, sal_uInt16 nCharLim ) THROWDEF_RTE_IAE
563 if ( nBase < 2 || nBase > 36 )
564 THROW_IAE;
566 sal_uInt32 nStrLen = aStr.getLength();
567 if( nStrLen > nCharLim )
568 THROW_IAE;
569 else if( !nStrLen )
570 return 0.0;
572 double fVal = 0.0;
574 register const sal_Unicode* p = aStr.getStr();
576 sal_uInt16 nFirstDig = 0;
577 sal_Bool bFirstDig = sal_True;
578 double fBase = nBase;
580 while ( *p )
582 sal_uInt16 n;
584 if( '0' <= *p && *p <= '9' )
585 n = *p - '0';
586 else if( 'A' <= *p && *p <= 'Z' )
587 n = 10 + ( *p - 'A' );
588 else if ( 'a' <= *p && *p <= 'z' )
589 n = 10 + ( *p - 'a' );
590 else
591 n = nBase;
593 if( n < nBase )
595 if( bFirstDig )
597 bFirstDig = sal_False;
598 nFirstDig = n;
600 fVal = fVal * fBase + double( n );
602 else
603 // illegal char!
604 THROW_IAE;
606 p++;
610 if( nStrLen == nCharLim && !bFirstDig && (nFirstDig >= nBase / 2) )
611 { // handling negativ values
612 fVal = ( pow( double( nBase ), double( nCharLim ) ) - fVal ); // complement
613 fVal *= -1.0;
616 return fVal;
620 static inline sal_Char GetMaxChar( sal_uInt16 nBase )
622 const sal_Char* c = "--123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
623 return c[ nBase ];
627 STRING ConvertFromDec( double fNum, double fMin, double fMax, sal_uInt16 nBase,
628 sal_Int32 nPlaces, sal_Int32 nMaxPlaces, sal_Bool bUsePlaces ) THROWDEF_RTE_IAE
630 fNum = ::rtl::math::approxFloor( fNum );
631 fMin = ::rtl::math::approxFloor( fMin );
632 fMax = ::rtl::math::approxFloor( fMax );
634 if( fNum < fMin || fNum > fMax || ( bUsePlaces && ( nPlaces <= 0 || nPlaces > nMaxPlaces ) ) )
635 THROW_IAE;
637 sal_Int64 nNum = static_cast< sal_Int64 >( fNum );
638 sal_Bool bNeg = nNum < 0;
639 if( bNeg )
640 nNum = sal_Int64( pow( double( nBase ), double( nMaxPlaces ) ) ) + nNum;
642 STRING aRet( STRING::valueOf( nNum, nBase ).toAsciiUpperCase() );
645 if( bUsePlaces )
647 sal_Int32 nLen = aRet.getLength();
648 if( !bNeg && nLen > nPlaces )
650 THROW_IAE;
652 else if( ( bNeg && nLen < nMaxPlaces ) || ( !bNeg && nLen < nPlaces ) )
654 sal_Int32 nLeft = nPlaces - nLen;
655 sal_Char* p = new sal_Char[ nLeft + 1 ];
656 memset( p, bNeg? GetMaxChar( nBase ) : '0', nLeft );
657 p[ nLeft ] = 0x00;
658 STRING aTmp( p, nLeft, RTL_TEXTENCODING_MS_1252 );
659 aTmp += aRet;
660 aRet = aTmp;
662 delete[] p;
666 return aRet;
669 // implementation moved to module sal, see #i97091#
670 double Erf( double x )
672 return ::rtl::math::erf(x);
675 // implementation moved to module sal, see #i97091#
676 double Erfc( double x )
678 return ::rtl::math::erfc(x);
681 inline sal_Bool IsNum( sal_Unicode c )
683 return c >= '0' && c <= '9';
687 inline sal_Bool IsComma( sal_Unicode c )
689 return c == '.' || c == ',';
693 inline sal_Bool IsExpStart( sal_Unicode c )
695 return c == 'e' || c == 'E';
699 inline sal_Bool IsImagUnit( sal_Unicode c )
701 return c == 'i' || c == 'j';
705 inline sal_uInt16 GetVal( sal_Unicode c )
707 return sal_uInt16( c - '0' );
711 sal_Bool ParseDouble( const sal_Unicode*& rp, double& rRet )
713 double fInt = 0.0;
714 double fFrac = 0.0;
715 double fMult = 0.1; // multiplier to multiply digits with, when adding fractional ones
716 sal_Int32 nExp = 0;
717 sal_Int32 nMaxExp = 307;
718 sal_uInt16 nDigCnt = 18; // max. number of digits to read in, rest doesn't matter
720 enum State { S_End = 0, S_Sign, S_IntStart, S_Int, S_IgnoreIntDigs, S_Frac, S_IgnoreFracDigs, S_ExpSign, S_Exp };
722 State eS = S_Sign;
724 sal_Bool bNegNum = sal_False;
725 sal_Bool bNegExp = sal_False;
727 const sal_Unicode* p = rp;
728 sal_Unicode c;
730 while( eS )
732 c = *p;
733 switch( eS )
735 case S_Sign:
736 if( IsNum( c ) )
738 fInt = GetVal( c );
739 nDigCnt--;
740 eS = S_Int;
742 else if( c == '-' )
744 bNegNum = sal_True;
745 eS = S_IntStart;
747 else if( c == '+' )
748 eS = S_IntStart;
749 else if( IsComma( c ) )
750 eS = S_Frac;
751 else
752 return sal_False;
753 break;
754 case S_IntStart:
755 if( IsNum( c ) )
757 fInt = GetVal( c );
758 nDigCnt--;
759 eS = S_Int;
761 else if( IsComma( c ) )
762 eS = S_Frac;
763 else if( IsImagUnit( c ) )
765 rRet = 0.0;
766 return sal_True;
768 else
769 return sal_False;
770 break;
771 case S_Int:
772 if( IsNum( c ) )
774 fInt *= 10.0;
775 fInt += double( GetVal( c ) );
776 nDigCnt--;
777 if( !nDigCnt )
778 eS = S_IgnoreIntDigs;
780 else if( IsComma( c ) )
781 eS = S_Frac;
782 else if( IsExpStart( c ) )
783 eS = S_ExpSign;
784 else
785 eS = S_End;
786 break;
787 case S_IgnoreIntDigs:
788 if( IsNum( c ) )
789 nExp++; // just multiply num with 10... ;-)
790 else if( IsComma( c ) )
791 eS = S_Frac;
792 else if( IsExpStart( c ) )
793 eS = S_ExpSign;
794 else
795 eS = S_End;
796 break;
797 case S_Frac:
798 if( IsNum( c ) )
800 fFrac += double( GetVal( c ) ) * fMult;
801 nDigCnt--;
802 if( nDigCnt )
803 fMult *= 0.1;
804 else
805 eS = S_IgnoreFracDigs;
807 else if( IsExpStart( c ) )
808 eS = S_ExpSign;
809 else
810 eS = S_End;
811 break;
812 case S_IgnoreFracDigs:
813 if( IsExpStart( c ) )
814 eS = S_ExpSign;
815 else if( !IsNum( c ) )
816 eS = S_End;
817 break;
818 case S_ExpSign:
819 if( IsNum( c ) )
821 nExp = GetVal( c );
822 eS = S_Exp;
824 else if( c == '-' )
826 bNegExp = sal_True;
827 eS = S_Exp;
829 else if( c != '+' )
830 eS = S_End;
831 break;
832 case S_Exp:
833 if( IsNum( c ) )
835 nExp *= 10;
836 nExp += GetVal( c );
837 if( nExp > nMaxExp )
838 return sal_False;
840 else
841 eS = S_End;
842 break;
843 case S_End: // to avoid compiler warning
844 break; // loop exits anyway
847 p++;
850 p--; // set pointer back to last
851 rp = p;
853 fInt += fFrac;
854 sal_Int32 nLog10 = sal_Int32( log10( fInt ) );
856 if( bNegExp )
857 nExp = -nExp;
859 if( nLog10 + nExp > nMaxExp )
860 return sal_False;
862 fInt = ::rtl::math::pow10Exp( fInt, nExp );
864 if( bNegNum )
865 fInt = -fInt;
867 rRet = fInt;
869 return sal_True;
873 STRING GetString( double f, sal_Bool bLeadingSign, sal_uInt16 nMaxDig )
875 const int nBuff = 256;
876 sal_Char aBuff[ nBuff + 1 ];
877 const char* pFormStr = bLeadingSign? "%+.*g" : "%.*g";
878 int nLen = snprintf( aBuff, nBuff, pFormStr, int( nMaxDig ), f );
879 // you never know which underlying implementation you get ...
880 aBuff[nBuff] = 0;
881 if ( nLen < 0 || nLen > nBuff )
882 nLen = strlen( aBuff );
884 STRING aRet( aBuff, nLen, RTL_TEXTENCODING_MS_1252 );
886 return aRet;
890 double GetAmordegrc( sal_Int32 nNullDate, double fCost, sal_Int32 nDate, sal_Int32 nFirstPer,
891 double fRestVal, double fPer, double fRate, sal_Int32 nBase ) THROWDEF_RTE_IAE
893 if( nBase == 2 )
894 THROW_IAE;
896 sal_uInt32 nPer = sal_uInt32( fPer );
897 double fUsePer = 1.0 / fRate;
898 double fAmorCoeff;
900 if( fUsePer < 3.0 )
901 fAmorCoeff = 1.0;
902 else if( fUsePer < 5.0 )
903 fAmorCoeff = 1.5;
904 else if( fUsePer <= 6.0 )
905 fAmorCoeff = 2.0;
906 else
907 fAmorCoeff = 2.5;
909 fRate *= fAmorCoeff;
910 double fNRate = ::rtl::math::round( GetYearFrac( nNullDate, nDate, nFirstPer, nBase ) * fRate * fCost, 0 );
911 fCost -= fNRate;
912 double fRest = fCost - fRestVal; // Anschaffungskosten - Restwert - Summe aller Abschreibungen
914 for( sal_uInt32 n = 0 ; n < nPer ; n++ )
916 fNRate = ::rtl::math::round( fRate * fCost, 0 );
917 fRest -= fNRate;
919 if( fRest < 0.0 )
921 switch( nPer - n )
923 case 0:
924 case 1:
925 return ::rtl::math::round( fCost * 0.5, 0 );
926 default:
927 return 0.0;
931 fCost -= fNRate;
934 return fNRate;
938 double GetAmorlinc( sal_Int32 nNullDate, double fCost, sal_Int32 nDate, sal_Int32 nFirstPer,
939 double fRestVal, double fPer, double fRate, sal_Int32 nBase ) THROWDEF_RTE_IAE
941 if( nBase == 2 )
942 THROW_IAE;
944 sal_uInt32 nPer = sal_uInt32( fPer );
945 double fOneRate = fCost * fRate;
946 double fCostDelta = fCost - fRestVal;
947 double f0Rate = GetYearFrac( nNullDate, nDate, nFirstPer, nBase ) * fRate * fCost;
948 sal_uInt32 nNumOfFullPeriods = sal_uInt32( ( fCost - fRestVal - f0Rate) / fOneRate );
950 if( nPer == 0 )
951 return f0Rate;
952 else if( nPer <= nNumOfFullPeriods )
953 return fOneRate;
954 else if( nPer == nNumOfFullPeriods + 1 )
955 return fCostDelta - fOneRate * nNumOfFullPeriods - f0Rate;
956 else
957 return 0.0;
961 double GetDuration( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, double fCoup,
962 double fYield, sal_Int32 nFreq, sal_Int32 nBase ) THROWDEF_RTE_IAE
964 double fYearfrac = GetYearFrac( nNullDate, nSettle, nMat, nBase );
965 double fNumOfCoups = GetCoupnum( nNullDate, nSettle, nMat, nFreq, nBase );
966 double fDur = 0.0;
967 const double f100 = 100.0;
968 fCoup *= f100 / double( nFreq ); // fCoup is used as cash flow
969 fYield /= nFreq;
970 fYield += 1.0;
972 double nDiff = fYearfrac * nFreq - fNumOfCoups;
974 double t;
976 for( t = 1.0 ; t < fNumOfCoups ; t++ )
977 fDur += ( t + nDiff ) * ( fCoup ) / pow( fYield, t + nDiff );
979 fDur += ( fNumOfCoups + nDiff ) * ( fCoup + f100 ) / pow( fYield, fNumOfCoups + nDiff );
981 double p = 0.0;
982 for( t = 1.0 ; t < fNumOfCoups ; t++ )
983 p += fCoup / pow( fYield, t + nDiff );
985 p += ( fCoup + f100 ) / pow( fYield, fNumOfCoups + nDiff );
987 fDur /= p;
988 fDur /= double( nFreq );
990 return fDur;
994 double GetYieldmat( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nIssue,
995 double fRate, double fPrice, sal_Int32 nBase ) THROWDEF_RTE_IAE
997 double fIssMat = GetYearFrac( nNullDate, nIssue, nMat, nBase );
998 double fIssSet = GetYearFrac( nNullDate, nIssue, nSettle, nBase );
999 double fSetMat = GetYearFrac( nNullDate, nSettle, nMat, nBase );
1001 double y = 1.0 + fIssMat * fRate;
1002 y /= fPrice / 100.0 + fIssSet * fRate;
1003 y--;
1004 y /= fSetMat;
1006 return y;
1010 double GetOddfprice( sal_Int32 /*nNullDate*/, sal_Int32 /*nSettle*/, sal_Int32 /*nMat*/, sal_Int32 /*nIssue*/,
1011 sal_Int32 /*nFirstCoup*/, double /*fRate*/, double /*fYield*/, double /*fRedemp*/, sal_Int32 /*nFreq*/,
1012 sal_Int32 /*nBase*/ ) THROWDEF_RTE_IAE
1014 THROW_RTE; // #87380#
1016 double fN = GetCoupnum( nNullDate, nSettle, nMat, nFreq, nBase ) - 1.0;
1017 double fNq = GetCoupnum( nNullDate, nSettle, nFirstCoup, nFreq, nBase ) - 1.0;
1018 double fDSC = GetCoupdaysnc( nNullDate, nSettle, nFirstCoup, nFreq, nBase );
1019 double fDSC_E = fDSC / GetCoupdays( nNullDate, nSettle, nMat, nFreq, nBase );
1020 double fNC = GetCoupnum( nNullDate, nIssue, nFirstCoup, nFreq, nBase );
1021 sal_uInt32 nNC = sal_uInt32( fNC );
1022 sal_uInt16 nMonthDelta = 12 / sal_uInt16( nFreq );
1024 sal_uInt32 i;
1025 double f1YieldFreq = 1.0 + fYield / double( nFreq );
1026 double f100RateFreq = 100.0 * fRate / double( nFreq );
1028 double* pDC = new double[ nNC + 1 ];
1029 double* pNL = new double[ nNC + 1 ];
1030 double* pA = new double[ nNC + 1 ];
1032 pDC[ 0 ] = pNL[ 0 ] = pA[ 0 ] = 1.0;
1034 ScaDate aStartDate( nNullDate, nSettle, nBase );
1035 ScaDate aNextCoup( nNullDate, nFirstCoup, nBase );
1036 if( nNC )
1038 pDC[ 1 ] = ScaDate::GetDiff( aStartDate, aNextCoup );
1039 pNL[ 1 ] = GetCoupdays( nNullDate, nSettle, nFirstCoup, nFreq, nBase );
1040 pA[ 1 ] = pDC[ 1 ];
1041 ScaDate aPre;
1042 for( i = 1 ; i <= nNC ; i++ )
1044 aPre = aStartDate;
1045 aStartDate.addMonths( nMonthDelta );
1046 aNextCoup.addMonths( nMonthDelta );
1047 pDC[ i ] = ScaDate::GetDiff( aPre, aStartDate );
1048 pNL[ i ] = GetCoupdays( nNullDate, aStartDate.GetDate( nNullDate ), aNextCoup.GetDate( nNullDate ),
1049 nFreq, nBase );
1050 pA[ i ] = ScaDate::GetDiff( aStartDate, aNextCoup );
1054 double fT1 = fRedemp / pow( f1YieldFreq, fN + fNq + fDSC_E );
1056 double fT2 = 0.0;
1057 for( i = 1 ; i <= nNC ; i++ )
1058 fT2 += pDC[ i ] / pNL[ i ];
1059 fT2 *= f100RateFreq / pow( f1YieldFreq, fNq + fDSC_E );
1061 double fT3 = 0.0;
1062 for( double k = 2.0 ; k <= fN ; k++ )
1063 fT3 += 1.0 / pow( f1YieldFreq, k - fNq + fDSC_E );
1064 fT3 *= f100RateFreq;
1066 double fT4 = 0.0;
1067 for( i = 1 ; i <= nNC ; i++ )
1068 fT4 += pA[ i ] / pNL[ i ];
1069 fT4 *= f100RateFreq;
1071 if( nNC )
1073 delete pDC;
1074 delete pNL;
1075 delete pA;
1078 return fT1 + fT2 + fT3 - fT4;
1083 double getYield_( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, double fCoup, double fPrice,
1084 double fRedemp, sal_Int32 nFreq, sal_Int32 nBase ) THROWDEF_RTE_IAE
1086 double fRate = fCoup;
1087 double fPriceN = 0.0;
1088 double fYield1 = 0.0;
1089 double fYield2 = 1.0;
1090 double fPrice1 = getPrice_( nNullDate, nSettle, nMat, fRate, fYield1, fRedemp, nFreq, nBase );
1091 double fPrice2 = getPrice_( nNullDate, nSettle, nMat, fRate, fYield2, fRedemp, nFreq, nBase );
1092 double fYieldN = ( fYield2 - fYield1 ) * 0.5;
1094 for( sal_uInt32 nIter = 0 ; nIter < 100 && fPriceN != fPrice ; nIter++ )
1096 fPriceN = getPrice_( nNullDate, nSettle, nMat, fRate, fYieldN, fRedemp, nFreq, nBase );
1098 if( fPrice == fPrice1 )
1099 return fYield1;
1100 else if( fPrice == fPrice2 )
1101 return fYield2;
1102 else if( fPrice == fPriceN )
1103 return fYieldN;
1104 else if( fPrice < fPrice2 )
1106 fYield2 *= 2.0;
1107 fPrice2 = getPrice_( nNullDate, nSettle, nMat, fRate, fYield2, fRedemp, nFreq, nBase );
1109 fYieldN = ( fYield2 - fYield1 ) * 0.5;
1111 else
1113 if( fPrice < fPriceN )
1115 fYield1 = fYieldN;
1116 fPrice1 = fPriceN;
1118 else
1120 fYield2 = fYieldN;
1121 fPrice2 = fPriceN;
1124 fYieldN = fYield2 - ( fYield2 - fYield1 ) * ( ( fPrice - fPrice2 ) / ( fPrice1 - fPrice2 ) );
1128 if( fabs( fPrice - fPriceN ) > fPrice / 100.0 )
1129 THROW_IAE; // result not precise enough
1131 return fYieldN;
1135 double getPrice_( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, double fRate, double fYield,
1136 double fRedemp, sal_Int32 nFreq, sal_Int32 nBase ) THROWDEF_RTE_IAE
1138 double fFreq = nFreq;
1140 double fE = GetCoupdays( nNullDate, nSettle, nMat, nFreq, nBase );
1141 double fDSC_E = GetCoupdaysnc( nNullDate, nSettle, nMat, nFreq, nBase ) / fE;
1142 double fN = GetCoupnum( nNullDate, nSettle, nMat, nFreq, nBase );
1143 double fA = GetCoupdaybs( nNullDate, nSettle, nMat, nFreq, nBase );
1145 double fRet = fRedemp / ( pow( 1.0 + fYield / fFreq, fN - 1.0 + fDSC_E ) );
1146 fRet -= 100.0 * fRate / fFreq * fA / fE;
1148 double fT1 = 100.0 * fRate / fFreq;
1149 double fT2 = 1.0 + fYield / fFreq;
1151 for( double fK = 0.0 ; fK < fN ; fK++ )
1152 fRet += fT1 / pow( fT2, fK + fDSC_E );
1154 return fRet;
1158 double GetOddfyield( sal_Int32 /*nNullDate*/, sal_Int32 /*nSettle*/, sal_Int32 /*nMat*/, sal_Int32 /*nIssue*/,
1159 sal_Int32 /*nFirstCoup*/, double /*fRate*/, double /*fPrice*/, double /*fRedemp*/, sal_Int32 /*nFreq*/,
1160 sal_Int32 /*nBase*/ ) THROWDEF_RTE_IAE
1162 THROW_RTE; // #87380#
1164 //GetOddfprice( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nIssue,
1165 //sal_Int32 nFirstCoup, double fRate, double fYield, double fRedemp, sal_Int32 nFreq,
1166 //sal_Int32 nBase )
1167 double fPriceN = 0.0;
1168 double fYield1 = 0.0;
1169 double fYield2 = 1.0;
1170 double fPrice1 = GetOddfprice( nNullDate, nSettle, nMat, nIssue, nFirstCoup, fRate, fYield1, fRedemp, nFreq, nBase );
1171 double fPrice2 = GetOddfprice( nNullDate, nSettle, nMat, nIssue, nFirstCoup, fRate, fYield2, fRedemp, nFreq, nBase );
1172 double fYieldN = ( fYield2 - fYield1 ) * 0.5;
1174 for( sal_uInt32 nIter = 0 ; nIter < 100 && fPriceN != fPrice ; nIter++ )
1176 fPriceN = GetOddfprice( nNullDate, nSettle, nMat, nIssue, nFirstCoup, fRate, fYieldN, fRedemp, nFreq, nBase );
1178 if( fPrice == fPrice1 )
1179 return fYield1;
1180 else if( fPrice == fPrice2 )
1181 return fYield2;
1182 else if( fPrice == fPriceN )
1183 return fYieldN;
1184 else if( fPrice < fPrice2 )
1186 fYield2 *= 2.0;
1187 fPrice2 = GetOddfprice( nNullDate, nSettle, nMat, nIssue, nFirstCoup, fRate, fYield2, fRedemp, nFreq, nBase );
1189 fYieldN = ( fYield2 - fYield1 ) * 0.5;
1191 else
1193 if( fPrice < fPriceN )
1195 fYield1 = fYieldN;
1196 fPrice1 = fPriceN;
1198 else
1200 fYield2 = fYieldN;
1201 fPrice2 = fPriceN;
1204 fYieldN = fYield2 - ( fYield2 - fYield1 ) * ( ( fPrice - fPrice2 ) / ( fPrice1 - fPrice2 ) );
1208 if( fabs( fPrice - fPriceN ) > fPrice / 100.0 )
1209 THROW_IAE; // result not precise enough
1211 return fYieldN;
1216 double GetOddlprice( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nLastCoup,
1217 double fRate, double fYield, double fRedemp, sal_Int32 nFreq, sal_Int32 nBase ) THROWDEF_RTE_IAE
1219 double fFreq = double( nFreq );
1220 double fDCi = GetYearFrac( nNullDate, nLastCoup, nMat, nBase ) * fFreq;
1221 double fDSCi = GetYearFrac( nNullDate, nSettle, nMat, nBase ) * fFreq;
1222 double fAi = GetYearFrac( nNullDate, nLastCoup, nSettle, nBase ) * fFreq;
1224 double p = fRedemp + fDCi * 100.0 * fRate / fFreq;
1225 p /= fDSCi * fYield / fFreq + 1.0;
1226 p -= fAi * 100.0 * fRate / fFreq;
1228 return p;
1232 double GetOddlyield( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nLastCoup,
1233 double fRate, double fPrice, double fRedemp, sal_Int32 nFreq, sal_Int32 nBase ) THROWDEF_RTE_IAE
1235 double fFreq = double( nFreq );
1236 double fDCi = GetYearFrac( nNullDate, nLastCoup, nMat, nBase ) * fFreq;
1237 double fDSCi = GetYearFrac( nNullDate, nSettle, nMat, nBase ) * fFreq;
1238 double fAi = GetYearFrac( nNullDate, nLastCoup, nSettle, nBase ) * fFreq;
1240 double y = fRedemp + fDCi * 100.0 * fRate / fFreq;
1241 y /= fPrice + fAi * 100.0 * fRate / fFreq;
1242 y--;
1243 y *= fFreq / fDSCi;
1245 return y;
1249 double GetRmz( double fZins, double fZzr, double fBw, double fZw, sal_Int32 nF )
1251 double fRmz;
1252 if( fZins == 0.0 )
1253 fRmz = ( fBw + fZw ) / fZzr;
1254 else
1256 double fTerm = pow( 1.0 + fZins, fZzr );
1257 if( nF > 0 )
1258 fRmz = ( fZw * fZins / ( fTerm - 1.0 ) + fBw * fZins / ( 1.0 - 1.0 / fTerm ) ) / ( 1.0 + fZins );
1259 else
1260 fRmz = fZw * fZins / ( fTerm - 1.0 ) + fBw * fZins / ( 1.0 - 1.0 / fTerm );
1263 return -fRmz;
1267 double GetZw( double fZins, double fZzr, double fRmz, double fBw, sal_Int32 nF )
1269 double fZw;
1270 if( fZins == 0.0 )
1271 fZw = fBw + fRmz * fZzr;
1272 else
1274 double fTerm = pow( 1.0 + fZins, fZzr );
1275 if( nF > 0 )
1276 fZw = fBw * fTerm + fRmz * ( 1.0 + fZins ) * ( fTerm - 1.0 ) / fZins;
1277 else
1278 fZw = fBw * fTerm + fRmz * ( fTerm - 1.0 ) / fZins;
1281 return -fZw;
1285 /*double TBillYield( constREFXPS& xOpt, sal_Int32 nSettle, sal_Int32 nMat, double fPrice ) THROWDEF_RTE_IAE
1287 sal_Int32 nDiff = GetDiffDate360( xOpt, nSettle, nMat, sal_True );
1289 if( fPrice <= 0.0 || nSettle >= nMat || nDiff > 360 )
1290 THROW_IAE;
1292 double fRet = 100.0;
1293 fRet /= fPrice;
1294 fRet--;
1295 fRet *= double( nDiff );
1296 fRet /= 360.0;
1298 return fRet;
1302 //-----------------------------------------------------------------------------
1303 // financial functions COUP***
1306 //-------
1307 // COUPPCD: find last coupon date before settlement (can be equal to settlement)
1308 void lcl_GetCouppcd( ScaDate& rDate, const ScaDate& rSettle, const ScaDate& rMat, sal_Int32 nFreq )
1309 throw( lang::IllegalArgumentException )
1311 rDate = rMat;
1312 rDate.setYear( rSettle.getYear() );
1313 if( rDate < rSettle )
1314 rDate.addYears( 1 );
1315 while( rDate > rSettle )
1316 rDate.addMonths( -12 / nFreq );
1319 double GetCouppcd( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nFreq, sal_Int32 nBase )
1320 THROWDEF_RTE_IAE
1322 if( nSettle >= nMat || CHK_Freq )
1323 THROW_IAE;
1325 ScaDate aDate;
1326 lcl_GetCouppcd( aDate, ScaDate( nNullDate, nSettle, nBase ), ScaDate( nNullDate, nMat, nBase ), nFreq );
1327 return aDate.getDate( nNullDate );
1331 //-------
1332 // COUPNCD: find first coupon date after settlement (is never equal to settlement)
1333 void lcl_GetCoupncd( ScaDate& rDate, const ScaDate& rSettle, const ScaDate& rMat, sal_Int32 nFreq )
1334 throw( lang::IllegalArgumentException )
1336 rDate = rMat;
1337 rDate.setYear( rSettle.getYear() );
1338 if( rDate > rSettle )
1339 rDate.addYears( -1 );
1340 while( rDate <= rSettle )
1341 rDate.addMonths( 12 / nFreq );
1344 double GetCoupncd( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nFreq, sal_Int32 nBase )
1345 THROWDEF_RTE_IAE
1347 if( nSettle >= nMat || CHK_Freq )
1348 THROW_IAE;
1350 ScaDate aDate;
1351 lcl_GetCoupncd( aDate, ScaDate( nNullDate, nSettle, nBase ), ScaDate( nNullDate, nMat, nBase ), nFreq );
1352 return aDate.getDate( nNullDate );
1356 //-------
1357 // COUPDAYBS: get day count: coupon date before settlement <-> settlement
1358 double GetCoupdaybs( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nFreq, sal_Int32 nBase )
1359 THROWDEF_RTE_IAE
1361 if( nSettle >= nMat || CHK_Freq )
1362 THROW_IAE;
1364 ScaDate aSettle( nNullDate, nSettle, nBase );
1365 ScaDate aDate;
1366 lcl_GetCouppcd( aDate, aSettle, ScaDate( nNullDate, nMat, nBase ), nFreq );
1367 return ScaDate::getDiff( aDate, aSettle );
1371 //-------
1372 // COUPDAYSNC: get day count: settlement <-> coupon date after settlement
1373 double GetCoupdaysnc( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nFreq, sal_Int32 nBase )
1374 THROWDEF_RTE_IAE
1376 if( nSettle >= nMat || CHK_Freq )
1377 THROW_IAE;
1379 if( (nBase != 0) && (nBase != 4) )
1381 ScaDate aSettle( nNullDate, nSettle, nBase );
1382 ScaDate aDate;
1383 lcl_GetCoupncd( aDate, aSettle, ScaDate( nNullDate, nMat, nBase ), nFreq );
1384 return ScaDate::getDiff( aSettle, aDate );
1386 return GetCoupdays( nNullDate, nSettle, nMat, nFreq, nBase ) - GetCoupdaybs( nNullDate, nSettle, nMat, nFreq, nBase );
1390 //-------
1391 // COUPDAYS: get day count: coupon date before settlement <-> coupon date after settlement
1392 double GetCoupdays( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nFreq, sal_Int32 nBase )
1393 THROWDEF_RTE_IAE
1395 if( nSettle >= nMat || CHK_Freq )
1396 THROW_IAE;
1398 if( nBase == 1 )
1400 ScaDate aDate;
1401 lcl_GetCouppcd( aDate, ScaDate( nNullDate, nSettle, nBase ), ScaDate( nNullDate, nMat, nBase ), nFreq );
1402 ScaDate aNextDate( aDate );
1403 aNextDate.addMonths( 12 / nFreq );
1404 return ScaDate::getDiff( aDate, aNextDate );
1406 return static_cast< double >( GetDaysInYear( 0, 0, nBase ) ) / nFreq;
1410 //-------
1411 // COUPNUM: get count of coupon dates
1412 double GetCoupnum( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nFreq, sal_Int32 nBase )
1413 THROWDEF_RTE_IAE
1415 if( nSettle >= nMat || CHK_Freq )
1416 THROW_IAE;
1418 ScaDate aMat( nNullDate, nMat, nBase );
1419 ScaDate aDate;
1420 lcl_GetCouppcd( aDate, ScaDate( nNullDate, nSettle, nBase ), aMat, nFreq );
1421 sal_uInt16 nMonths = (aMat.getYear() - aDate.getYear()) * 12 + aMat.getMonth() - aDate.getMonth();
1422 return static_cast< double >( nMonths * nFreq / 12 );
1431 const sal_uInt32 MyList::nStartSize = 16;
1432 const sal_uInt32 MyList::nIncrSize = 16;
1435 void MyList::_Grow( void )
1437 nSize += nIncrSize;
1439 void** pNewData = new void*[ nSize ];
1440 memcpy( pNewData, pData, nNew * sizeof( void* ) );
1442 delete[] pData;
1443 pData = pNewData;
1447 MyList::MyList( void )
1449 nSize = nStartSize;
1450 pData = new void*[ nSize ];
1451 nNew = nAct = 0;
1455 MyList::~MyList()
1457 delete[] pData;
1461 void MyList::Insert( void* p, sal_uInt32 n )
1463 if( n >= nNew )
1464 Append( p );
1465 else
1467 Grow();
1469 void** pIns = pData + n;
1470 memmove( pIns + 1, pIns, ( nNew - n ) * sizeof( void* ) );
1472 *pIns = p;
1474 nNew++;
1481 StringList::~StringList()
1483 for( STRING* p = ( STRING* ) First() ; p ; p = ( STRING* ) Next() )
1484 delete p;
1488 class AnalysisRscStrArrLoader : public Resource
1490 private:
1491 ResStringArray aStrArray;
1492 public:
1493 AnalysisRscStrArrLoader( sal_uInt16 nRsc, sal_uInt16 nArrayId, ResMgr& rResMgr ) :
1494 Resource( AnalysisResId( nRsc, rResMgr ) ),
1495 aStrArray( AnalysisResId( nArrayId, rResMgr ) )
1497 FreeResource();
1500 const ResStringArray& GetStringArray() const { return aStrArray; }
1506 FuncData::FuncData( const FuncDataBase& r, ResMgr& rResMgr ) :
1507 aIntName( OUString::createFromAscii( r.pIntName ) ),
1508 nUINameID( r.nUINameID ),
1509 nDescrID( r.nDescrID ),
1510 bDouble( r.bDouble ),
1511 bWithOpt( r.bWithOpt ),
1512 nParam( r.nNumOfParams ),
1513 nCompID( r.nCompListID ),
1514 eCat( r.eCat )
1516 AnalysisRscStrArrLoader aArrLoader( RID_ANALYSIS_DEFFUNCTION_NAMES, nCompID, rResMgr );
1517 // ResStringArray aDefFuncNameArray( AnalysisResId( nCompID, rResMgr ) );
1518 const ResStringArray& rArr = aArrLoader.GetStringArray();
1520 sal_uInt16 nCount = sal::static_int_cast<sal_uInt16>( rArr.Count() );
1521 sal_uInt16 n;
1523 for( n = 0 ; n < nCount ; n++ )
1524 aCompList.Append( rArr.GetString( n ) );
1528 FuncData::~FuncData()
1533 sal_uInt16 FuncData::GetStrIndex( sal_uInt16 nParamNum ) const
1535 if( !bWithOpt )
1536 nParamNum++;
1538 if( nParamNum > nParam )
1539 return nParam * 2;
1540 else
1541 return nParamNum * 2;
1547 FuncDataList::FuncDataList( ResMgr& rResMgr )
1549 const sal_uInt32 nNum = sizeof( pFuncDatas ) / sizeof( FuncDataBase );
1551 for( sal_uInt16 n = 0 ; n < nNum ; n++ )
1552 Append( new FuncData( pFuncDatas[ n ], rResMgr ) );
1556 FuncDataList::~FuncDataList()
1558 for( FuncData* p = ( FuncData* ) First() ; p ; p = ( FuncData* ) Next() )
1559 delete p;
1563 const FuncData* FuncDataList::Get( const OUString& aProgrammaticName ) const
1565 if( aLastName == aProgrammaticName )
1566 return Get( nLast );
1568 ( ( FuncDataList* ) this )->aLastName = aProgrammaticName;
1570 sal_uInt32 nE = Count();
1571 for( sal_uInt32 n = 0 ; n < nE ; n++ )
1573 const FuncData* p = Get( n );
1574 if( p->Is( aProgrammaticName ) )
1576 ( ( FuncDataList* ) this )->nLast = n;
1577 return p;
1581 ( ( FuncDataList* ) this )->nLast = 0xFFFFFFFF;
1582 return NULL;
1586 AnalysisResId::AnalysisResId( sal_uInt16 nId, ResMgr& rResMgr ) : ResId( nId, rResMgr )
1593 SortedIndividualInt32List::SortedIndividualInt32List()
1598 SortedIndividualInt32List::~SortedIndividualInt32List()
1603 void SortedIndividualInt32List::Insert( sal_Int32 nDay )
1605 sal_uInt32 nIndex = Count();
1606 while( nIndex )
1608 nIndex--;
1609 sal_Int32 nRef = Get( nIndex );
1610 if( nDay == nRef )
1611 return;
1612 else if( nDay > nRef )
1614 MyList::Insert( (void*) nDay, nIndex + 1 );
1615 return;
1618 MyList::Insert( (void*) nDay, 0UL );
1622 void SortedIndividualInt32List::Insert( sal_Int32 nDay, sal_Int32 nNullDate, sal_Bool bInsertOnWeekend )
1624 if( !nDay )
1625 return;
1627 nDay += nNullDate;
1628 if( bInsertOnWeekend || (GetDayOfWeek( nDay ) < 5) )
1629 Insert( nDay );
1633 void SortedIndividualInt32List::Insert(
1634 double fDay, sal_Int32 nNullDate, sal_Bool bInsertOnWeekend ) throw( uno::RuntimeException, lang::IllegalArgumentException )
1636 if( (fDay < -2147483648.0) || (fDay > 2147483649.0) )
1637 throw lang::IllegalArgumentException();
1638 Insert( static_cast< sal_Int32 >( fDay ), nNullDate, bInsertOnWeekend );
1642 sal_Bool SortedIndividualInt32List::Find( sal_Int32 nVal ) const
1644 sal_uInt32 nE = Count();
1646 if( !nE || nVal < Get( 0 ) || nVal > Get( nE - 1 ) )
1647 return sal_False;
1649 // linear search
1651 for( sal_uInt32 n = 0 ; n < nE ; n++ )
1653 sal_Int32 nRef = Get( n );
1655 if( nRef == nVal )
1656 return sal_True;
1657 else if( nRef > nVal )
1658 return sal_False;
1660 return sal_False;
1664 void SortedIndividualInt32List::InsertHolidayList(
1665 const ScaAnyConverter& rAnyConv,
1666 const uno::Any& rHolAny,
1667 sal_Int32 nNullDate,
1668 sal_Bool bInsertOnWeekend ) throw( uno::RuntimeException, lang::IllegalArgumentException )
1670 double fDay;
1671 if( rAnyConv.getDouble( fDay, rHolAny ) )
1672 Insert( fDay, nNullDate, bInsertOnWeekend );
1676 void SortedIndividualInt32List::InsertHolidayList(
1677 ScaAnyConverter& rAnyConv,
1678 const uno::Reference< beans::XPropertySet >& xOptions,
1679 const uno::Any& rHolAny,
1680 sal_Int32 nNullDate,
1681 sal_Bool bInsertOnWeekend ) throw( uno::RuntimeException, lang::IllegalArgumentException )
1683 rAnyConv.init( xOptions );
1684 if( rHolAny.getValueTypeClass() == uno::TypeClass_SEQUENCE )
1686 uno::Sequence< uno::Sequence< uno::Any > > aAnySeq;
1687 if( rHolAny >>= aAnySeq )
1689 const uno::Sequence< uno::Any >* pSeqArray = aAnySeq.getConstArray();
1690 for( sal_Int32 nIndex1 = 0; nIndex1 < aAnySeq.getLength(); nIndex1++ )
1692 const uno::Sequence< uno::Any >& rSubSeq = pSeqArray[ nIndex1 ];
1693 const uno::Any* pAnyArray = rSubSeq.getConstArray();
1695 for( sal_Int32 nIndex2 = 0; nIndex2 < rSubSeq.getLength(); nIndex2++ )
1696 InsertHolidayList( rAnyConv, pAnyArray[ nIndex2 ], nNullDate, bInsertOnWeekend );
1699 else
1700 throw lang::IllegalArgumentException();
1702 else
1703 InsertHolidayList( rAnyConv, rHolAny, nNullDate, bInsertOnWeekend );
1708 //-----------------------------------------------------------------------------
1710 ScaDoubleList::~ScaDoubleList()
1712 for( double* pDbl = const_cast< double* >( First() ); pDbl; pDbl = const_cast< double* >( Next() ) )
1713 delete pDbl;
1717 void ScaDoubleList::Append(
1718 const uno::Sequence< uno::Sequence< double > >& rValueSeq ) throw( uno::RuntimeException, lang::IllegalArgumentException )
1720 const uno::Sequence< double >* pSeqArray = rValueSeq.getConstArray();
1721 for( sal_Int32 nIndex1 = 0; nIndex1 < rValueSeq.getLength(); nIndex1++ )
1723 const uno::Sequence< double >& rSubSeq = pSeqArray[ nIndex1 ];
1724 const double* pArray = rSubSeq.getConstArray();
1725 for( sal_Int32 nIndex2 = 0; nIndex2 < rSubSeq.getLength(); nIndex2++ )
1726 Append( pArray[ nIndex2 ] );
1731 void ScaDoubleList::Append(
1732 const uno::Sequence< uno::Sequence< sal_Int32 > >& rValueSeq ) throw( uno::RuntimeException, lang::IllegalArgumentException )
1734 const uno::Sequence< sal_Int32 >* pSeqArray = rValueSeq.getConstArray();
1735 for( sal_Int32 nIndex1 = 0; nIndex1 < rValueSeq.getLength(); nIndex1++ )
1737 const uno::Sequence< sal_Int32 >& rSubSeq = pSeqArray[ nIndex1 ];
1738 const sal_Int32* pArray = rSubSeq.getConstArray();
1739 for( sal_Int32 nIndex2 = 0; nIndex2 < rSubSeq.getLength(); nIndex2++ )
1740 Append( pArray[ nIndex2 ] );
1746 void ScaDoubleList::Append(
1747 const ScaAnyConverter& rAnyConv,
1748 const uno::Any& rAny,
1749 sal_Bool bIgnoreEmpty ) throw( uno::RuntimeException, lang::IllegalArgumentException )
1751 if( rAny.getValueTypeClass() == uno::TypeClass_SEQUENCE )
1752 Append( rAnyConv, *static_cast< const uno::Sequence< uno::Sequence< uno::Any > >* >( rAny.getValue() ), bIgnoreEmpty );
1753 else
1755 double fValue;
1756 if( rAnyConv.getDouble( fValue, rAny ) )
1757 Append( fValue );
1758 else if( !bIgnoreEmpty )
1759 Append( 0.0 );
1764 void ScaDoubleList::Append(
1765 const ScaAnyConverter& rAnyConv,
1766 const uno::Sequence< uno::Any >& rAnySeq,
1767 sal_Bool bIgnoreEmpty ) throw( uno::RuntimeException, lang::IllegalArgumentException )
1769 const uno::Any* pArray = rAnySeq.getConstArray();
1770 for( sal_Int32 nIndex = 0; nIndex < rAnySeq.getLength(); nIndex++ )
1771 Append( rAnyConv, pArray[ nIndex ], bIgnoreEmpty );
1775 void ScaDoubleList::Append(
1776 const ScaAnyConverter& rAnyConv,
1777 const uno::Sequence< uno::Sequence< uno::Any > >& rAnySeq,
1778 sal_Bool bIgnoreEmpty ) throw( uno::RuntimeException, lang::IllegalArgumentException )
1780 const uno::Sequence< uno::Any >* pArray = rAnySeq.getConstArray();
1781 for( sal_Int32 nIndex = 0; nIndex < rAnySeq.getLength(); nIndex++ )
1782 Append( rAnyConv, pArray[ nIndex ], bIgnoreEmpty );
1787 void ScaDoubleList::Append(
1788 ScaAnyConverter& rAnyConv,
1789 const uno::Reference< beans::XPropertySet >& xOpt,
1790 const uno::Sequence< uno::Any >& rAnySeq,
1791 sal_Bool bIgnoreEmpty ) throw( uno::RuntimeException, lang::IllegalArgumentException )
1793 rAnyConv.init( xOpt );
1794 Append( rAnyConv, rAnySeq, bIgnoreEmpty );
1798 sal_Bool ScaDoubleList::CheckInsert( double ) const throw( uno::RuntimeException, lang::IllegalArgumentException )
1800 return sal_True;
1805 //-----------------------------------------------------------------------------
1807 sal_Bool ScaDoubleListGT0::CheckInsert( double fValue ) const throw( uno::RuntimeException, lang::IllegalArgumentException )
1809 if( fValue < 0.0 )
1810 throw lang::IllegalArgumentException();
1811 return fValue > 0.0;
1816 //-----------------------------------------------------------------------------
1818 sal_Bool ScaDoubleListGE0::CheckInsert( double fValue ) const throw( uno::RuntimeException, lang::IllegalArgumentException )
1820 if( fValue < 0.0 )
1821 throw lang::IllegalArgumentException();
1822 return sal_True;
1827 //-----------------------------------------------------------------------------
1829 Complex::Complex( const STRING& rStr ) THROWDEF_RTE_IAE
1831 if( !ParseString( rStr, *this ) )
1832 THROW_IAE;
1836 inline sal_Bool Complex::IsImagUnit( sal_Unicode c )
1838 return c == 'i' || c == 'j';
1841 sal_Bool Complex::ParseString( const STRING& rStr, Complex& rCompl )
1843 rCompl.c = '\0'; // do not force a symbol, if only real part present
1845 const sal_Unicode* pStr = ( const sal_Unicode * ) rStr;
1847 if( IsImagUnit( *pStr ) && rStr.getLength() == 1)
1849 rCompl.r = 0.0;
1850 rCompl.i = 1.0;
1851 rCompl.c = *pStr;
1852 return sal_True;
1855 double f;
1857 if( !ParseDouble( pStr, f ) )
1858 return sal_False;
1860 switch( *pStr )
1862 case '-': // imag part follows
1863 case '+':
1865 double r = f;
1866 if( IsImagUnit( pStr[ 1 ] ) )
1868 rCompl.c = pStr[ 1 ];
1869 if( pStr[ 2 ] == 0 )
1871 rCompl.r = f;
1872 rCompl.i = ( *pStr == '+' )? 1.0 : -1.0;
1873 return sal_True;
1876 else if( ParseDouble( pStr, f ) && IsImagUnit( *pStr ) )
1878 rCompl.c = *pStr;
1879 pStr++;
1880 if( *pStr == 0 )
1882 rCompl.r = r;
1883 rCompl.i = f;
1884 return sal_True;
1888 break;
1889 case 'j':
1890 case 'i':
1891 rCompl.c = *pStr;
1892 pStr++;
1893 if( *pStr == 0 )
1895 rCompl.i = f;
1896 rCompl.r = 0.0;
1897 return sal_True;
1899 break;
1900 case 0: // only real-part
1901 rCompl.r = f;
1902 rCompl.i = 0.0;
1903 return sal_True;
1906 return sal_False;
1910 STRING Complex::GetString() const THROWDEF_RTE_IAE
1912 static const String aI( 'i' );
1913 static const String aJ( 'j' );
1914 static const String aPlus( '+' );
1915 static const String aMinus( '-' );
1917 CHK_FINITE(r);
1918 CHK_FINITE(i);
1919 STRING aRet;
1921 bool bHasImag = i != 0.0;
1922 bool bHasReal = !bHasImag || (r != 0.0);
1924 if( bHasReal )
1925 aRet = ::GetString( r );
1926 if( bHasImag )
1928 if( i == 1.0 )
1930 if( bHasReal )
1931 aRet += aPlus;
1933 else if( i == -1.0 )
1934 aRet += aMinus;
1935 else
1936 aRet += ::GetString( i, bHasReal );
1937 aRet += (c != 'j') ? aI : aJ;
1940 return aRet;
1944 double Complex::Arg( void ) const THROWDEF_RTE_IAE
1946 if( r == 0.0 && i == 0.0 )
1947 THROW_IAE;
1949 double phi = acos( r / Abs() );
1951 if( i < 0.0 )
1952 phi = -phi;
1954 return phi;
1958 void Complex::Power( double fPower ) THROWDEF_RTE_IAE
1960 if( r == 0.0 && i == 0.0 )
1962 if( fPower > 0 )
1964 r = i = 0.0;
1965 return;
1967 else
1968 THROW_IAE;
1971 double p, phi;
1973 p = Abs();
1975 phi = acos( r / p );
1976 if( i < 0.0 )
1977 phi = -phi;
1979 p = pow( p, fPower );
1980 phi *= fPower;
1982 r = cos( phi ) * p;
1983 i = sin( phi ) * p;
1987 void Complex::Sqrt( void )
1989 static const double fMultConst = 0.7071067811865475; // ...2440084436210485 = 1/sqrt(2)
1990 double p = Abs();
1991 double i_ = sqrt( p - r ) * fMultConst;
1993 r = sqrt( p + r ) * fMultConst;
1994 i = ( i < 0.0 )? -i_ : i_;
1998 inline sal_Bool SinOverflow( double f )
2000 return fabs( f ) >= 134217728;
2004 void Complex::Sin( void ) THROWDEF_RTE_IAE
2006 if( SinOverflow( r ) )
2007 THROW_IAE;
2009 if( i )
2011 double r_;
2013 r_ = sin( r ) * cosh( i );
2014 i = cos( r ) * sinh( i );
2015 r = r_;
2017 else
2018 r = sin( r );
2022 void Complex::Cos( void ) THROWDEF_RTE_IAE
2024 if( SinOverflow( r ) )
2025 THROW_IAE;
2027 if( i )
2029 double r_;
2031 r_ = cos( r ) * cosh( i );
2032 i = -( sin( r ) * sinh( i ) );
2033 r = r_;
2035 else
2036 r = cos( r );
2040 void Complex::Div( const Complex& z ) THROWDEF_RTE_IAE
2042 if( z.r == 0 && z.i == 0 )
2043 THROW_IAE;
2045 double a1 = r;
2046 double a2 = z.r;
2047 double b1 = i;
2048 double b2 = z.i;
2050 double f = 1.0 / ( a2 * a2 + b2 * b2 );
2052 r = ( a1 * a2 + b1 * b2 ) * f;
2053 i = ( a2 * b1 - a1 * b2 ) * f;
2055 if( !c ) c = z.c;
2059 void Complex::Exp( void )
2061 double fE = exp( r );
2062 r = fE * cos( i );
2063 i = fE * sin( i );
2067 void Complex::Ln( void ) THROWDEF_RTE_IAE
2069 if( r == 0.0 && i == 0.0 )
2070 THROW_IAE;
2072 double fAbs = Abs();
2073 sal_Bool bNegi = i < 0.0;
2075 i = acos( r / fAbs );
2077 if( bNegi )
2078 i = -i;
2080 r = log( fAbs );
2084 void Complex::Log10( void ) THROWDEF_RTE_IAE
2086 Ln();
2087 Mult( 0.434294481903251828 ); // * log10( e )
2091 void Complex::Log2( void ) THROWDEF_RTE_IAE
2093 Ln();
2094 Mult( 1.442695040888963407 ); // * log2( e )
2100 ComplexList::~ComplexList()
2102 for( Complex* p = ( Complex* ) First() ; p ; p = ( Complex* ) Next() )
2103 delete p;
2107 void ComplexList::Append( const SEQSEQ( STRING )& r, ComplListAppendHandl eAH ) THROWDEF_RTE_IAE
2109 sal_Int32 n1, n2;
2110 sal_Int32 nE1 = r.getLength();
2111 sal_Int32 nE2;
2112 sal_Bool bEmpty0 = eAH == AH_EmpyAs0;
2113 sal_Bool bErrOnEmpty = eAH == AH_EmptyAsErr;
2115 for( n1 = 0 ; n1 < nE1 ; n1++ )
2117 const SEQ( STRING )& rList = r[ n1 ];
2118 nE2 = rList.getLength();
2120 for( n2 = 0 ; n2 < nE2 ; n2++ )
2122 const STRING& rStr = rList[ n2 ];
2124 if( rStr.getLength() )
2125 Append( new Complex( rStr ) );
2126 else if( bEmpty0 )
2127 Append( new Complex( 0.0 ) );
2128 else if( bErrOnEmpty )
2129 THROW_IAE;
2135 void ComplexList::Append( const SEQ( ANY )& aMultPars, ComplListAppendHandl eAH ) THROWDEF_RTE_IAE
2137 sal_Int32 nEle = aMultPars.getLength();
2138 sal_Bool bEmpty0 = eAH == AH_EmpyAs0;
2139 sal_Bool bErrOnEmpty = eAH == AH_EmptyAsErr;
2141 for( sal_Int32 i = 0 ; i < nEle ; i++ )
2143 const ANY& r = aMultPars[ i ];
2144 switch( r.getValueTypeClass() )
2146 case uno::TypeClass_VOID: break;
2147 case uno::TypeClass_STRING:
2149 const STRING* pStr = ( const STRING* ) r.getValue();
2151 if( pStr->getLength() )
2152 Append( new Complex( *( STRING* ) r.getValue() ) );
2153 else if( bEmpty0 )
2154 Append( new Complex( 0.0 ) );
2155 else if( bErrOnEmpty )
2156 THROW_IAE;
2158 break;
2159 case uno::TypeClass_DOUBLE:
2160 Append( new Complex( *( double* ) r.getValue(), 0.0 ) );
2161 break;
2162 case uno::TypeClass_SEQUENCE:
2164 SEQSEQ( ANY ) aValArr;
2165 if( r >>= aValArr )
2167 sal_Int32 nE = aValArr.getLength();
2168 const SEQ( ANY )* pArr = aValArr.getConstArray();
2169 for( sal_Int32 n = 0 ; n < nE ; n++ )
2170 Append( pArr[ n ], eAH );
2172 else
2173 THROW_IAE;
2175 break;
2176 default:
2177 THROW_IAE;
2185 ConvertData::ConvertData( const sal_Char p[], double fC, ConvertDataClass e, sal_Bool bPrefSupport ) : aName( p, strlen( p ), RTL_TEXTENCODING_MS_1252 )
2187 fConst = fC;
2188 eClass = e;
2189 bPrefixSupport = bPrefSupport;
2192 ConvertData::~ConvertData()
2197 sal_Int16 ConvertData::GetMatchingLevel( const STRING& rRef ) const
2199 STRING aStr = rRef;
2200 sal_Int32 nLen = rRef.getLength();
2201 sal_Int32 nIndex = rRef.lastIndexOf( '^' );
2202 if( nIndex > 0 && nIndex == ( nLen - 2 ) )
2204 const sal_Unicode* p = aStr.getStr();
2205 aStr = STRING( p, nLen - 2 );
2206 aStr += STRING( p[ nLen - 1 ] );
2208 if( aName.equals( aStr ) )
2209 return 0;
2210 else
2212 const sal_Unicode* p = aStr.getStr();
2214 nLen = aStr.getLength();
2215 bool bPref = IsPrefixSupport();
2216 bool bOneChar = (bPref && nLen > 1 && (aName == p + 1));
2217 if (bOneChar || (bPref && nLen > 2 && (aName == p + 2) &&
2218 *p == 'd' && *(p+1) == 'a'))
2220 sal_Int16 n;
2221 switch( *p )
2223 case 'y': n = -24; break; // yocto
2224 case 'z': n = -21; break; // zepto
2225 case 'a': n = -18; break;
2226 case 'f': n = -15; break;
2227 case 'p': n = -12; break;
2228 case 'n': n = -9; break;
2229 case 'u': n = -6; break;
2230 case 'm': n = -3; break;
2231 case 'c': n = -2; break;
2232 case 'd':
2234 if ( bOneChar )
2235 n = -1; // deci
2236 else
2237 n = 1; // deca
2239 break;
2240 case 'e': n = 1; break;
2241 case 'h': n = 2; break;
2242 case 'k': n = 3; break;
2243 case 'M': n = 6; break;
2244 case 'G': n = 9; break;
2245 case 'T': n = 12; break;
2246 case 'P': n = 15; break;
2247 case 'E': n = 18; break;
2248 case 'Z': n = 21; break; // zetta
2249 case 'Y': n = 24; break; // yotta
2250 default:
2251 n = INV_MATCHLEV;
2254 // We could weed some nonsense out, ODFF doesn't say so though.
2255 #if 0
2256 if (n < 0 && Class() == CDC_Information)
2257 n = INV_MATCHLEV; // milli-bits doesn't make sense
2258 #endif
2260 //! <HACK> #100616# "cm3" is not 10^-2 m^3 but 10^-6 m^3 !!! ------------------
2261 if( n != INV_MATCHLEV )
2263 sal_Unicode cLast = p[ aStr.getLength() - 1 ];
2264 if( cLast == '2' )
2265 n *= 2;
2266 else if( cLast == '3' )
2267 n *= 3;
2269 //! </HACK> -------------------------------------------------------------------
2271 return n;
2273 else if ( nLen > 2 && ( aName == p + 2 ) && ( Class() == CDC_Information ) )
2275 const sal_Unicode* pStr = aStr.getStr();
2276 if ( *(pStr + 1) != 'i')
2277 return INV_MATCHLEV;
2278 sal_Int16 n;
2279 switch( *pStr )
2281 case 'k': n = 10; break;
2282 case 'M': n = 20; break;
2283 case 'G': n = 30; break;
2284 case 'T': n = 40; break;
2285 case 'P': n = 50; break;
2286 case 'E': n = 60; break;
2287 case 'Z': n = 70; break;
2288 case 'Y': n = 80; break;
2289 default:
2290 n = INV_MATCHLEV;
2292 return n;
2294 else
2295 return INV_MATCHLEV;
2300 double ConvertData::Convert(
2301 double f, const ConvertData& r, sal_Int16 nLevFrom, sal_Int16 nLevTo ) const THROWDEF_RTE_IAE
2303 if( Class() != r.Class() )
2304 THROW_IAE;
2306 sal_Bool bBinFromLev = ( nLevFrom > 0 && ( nLevFrom % 10 ) == 0 );
2307 sal_Bool bBinToLev = ( nLevTo > 0 && ( nLevTo % 10 ) == 0 );
2309 if ( Class() == CDC_Information && ( bBinFromLev || bBinToLev ) )
2311 if ( bBinFromLev && bBinToLev )
2313 nLevFrom = sal::static_int_cast<sal_Int16>( nLevFrom - nLevTo );
2314 f *= r.fConst / fConst;
2315 if( nLevFrom )
2316 f *= pow( 2.0, nLevFrom );
2318 else if ( bBinFromLev )
2319 f *= ( r.fConst / fConst ) * ( pow( 2.0, nLevFrom ) / pow( 10.0, nLevTo ) );
2320 else
2321 f *= ( r.fConst / fConst ) * ( pow( 10.0, nLevFrom ) / pow( 2.0, nLevTo ) );
2322 return f;
2325 nLevFrom = sal::static_int_cast<sal_Int16>( nLevFrom - nLevTo ); // effective level
2327 f *= r.fConst / fConst;
2329 if( nLevFrom )
2330 f = ::rtl::math::pow10Exp( f, nLevFrom );
2332 return f;
2336 double ConvertData::ConvertToBase( double f, sal_Int16 n ) const
2338 return ::rtl::math::pow10Exp( f / fConst, n );
2342 double ConvertData::ConvertFromBase( double f, sal_Int16 n ) const
2344 return ::rtl::math::pow10Exp( f * fConst, -n );
2349 ConvertDataLinear::~ConvertDataLinear()
2353 double ConvertDataLinear::Convert(
2354 double f, const ConvertData& r, sal_Int16 nLevFrom, sal_Int16 nLevTo ) const THROWDEF_RTE_IAE
2356 if( Class() != r.Class() )
2357 THROW_IAE;
2359 // return ::rtl::math::round( r.ConvertFromBase( ConvertToBase( f, nLevFrom ), nLevTo ), 13 );
2360 return r.ConvertFromBase( ConvertToBase( f, nLevFrom ), nLevTo );
2364 double ConvertDataLinear::ConvertToBase( double f, sal_Int16 n ) const
2366 if( n )
2367 f = ::rtl::math::pow10Exp( f, n );
2369 f /= fConst;
2370 f -= fOffs;
2372 return f;
2376 double ConvertDataLinear::ConvertFromBase( double f, sal_Int16 n ) const
2378 f += fOffs;
2379 f *= fConst;
2381 if( n )
2382 f = ::rtl::math::pow10Exp( f, -n );
2384 return f;
2390 ConvertDataList::ConvertDataList( void )
2392 #define NEWD(str,unit,cl) Append(new ConvertData(str,unit,cl))
2393 #define NEWDP(str,unit,cl) Append(new ConvertData(str,unit,cl,sal_True))
2394 #define NEWL(str,unit,offs,cl) Append(new ConvertDataLinear(str,unit,offs,cl))
2395 #define NEWLP(str,unit,offs,cl) Append(new ConvertDataLinear(str,unit,offs,cl,sal_True))
2397 // *** are extra and not standard Excel Analysis Addin!
2399 // MASS: 1 Gram is...
2400 NEWDP( "g", 1.0000000000000000E00, CDC_Mass ); // Gram
2401 NEWD( "sg", 6.8522050005347800E-05, CDC_Mass ); // Pieces
2402 NEWD( "lbm", 2.2046229146913400E-03, CDC_Mass ); // Pound (commercial weight)
2403 NEWDP( "u", 6.0221370000000000E23, CDC_Mass ); // U (atomic mass)
2404 NEWD( "ozm", 3.5273971800362700E-02, CDC_Mass ); // Ounce (commercial weight)
2405 NEWD( "stone", 1.574730e-04, CDC_Mass ); // *** Stone
2406 NEWD( "ton", 1.102311e-06, CDC_Mass ); // *** Ton
2407 NEWD( "grain", 1.543236E01, CDC_Mass ); // *** Grain
2408 NEWD( "pweight", 7.054792E-01, CDC_Mass ); // *** Pennyweight
2409 NEWD( "hweight", 1.968413E-05, CDC_Mass ); // *** Hundredweight
2410 NEWD( "shweight", 2.204623E-05, CDC_Mass ); // *** Shorthundredweight
2411 NEWD( "brton", 9.842065E-07, CDC_Mass ); // *** Gross Registered Ton
2412 NEWD( "cwt", 2.2046226218487758E-05, CDC_Mass ); // U.S. (short) hundredweight
2413 NEWD( "shweight", 2.2046226218487758E-05, CDC_Mass ); // U.S. (short) hundredweight also
2414 NEWD( "uk_cwt", 1.9684130552221213E-05, CDC_Mass ); // Imperial hundredweight
2415 NEWD( "lcwt", 1.9684130552221213E-05, CDC_Mass ); // Imperial hundredweight also
2416 NEWD( "hweight", 1.9684130552221213E-05, CDC_Mass ); // Imperial hundredweight also
2417 NEWD( "uk_ton", 9.8420652761106063E-07, CDC_Mass ); // Imperial ton
2418 NEWD( "LTON", 9.8420652761106063E-07, CDC_Mass ); // Imperial ton also
2420 // LENGTH: 1 Meter is...
2421 NEWDP( "m", 1.0000000000000000E00, CDC_Length ); // Meter
2422 NEWD( "mi", 6.2137119223733397E-04, CDC_Length ); // Britsh Mile 6,21371192237333969617434184363e-4
2423 NEWD( "Nmi", 5.3995680345572354E-04, CDC_Length ); // Nautical Mile 5,39956803455723542116630669546e-4
2424 NEWD( "in", 3.9370078740157480E01, CDC_Length ); // Inch 39,37007874015748031496062992126
2425 NEWD( "ft", 3.2808398950131234E00, CDC_Length ); // Foot 3,2808398950131233595800524934383
2426 NEWD( "yd", 1.0936132983377078E00, CDC_Length ); // Yard 1,0936132983377077865266841644794
2427 NEWDP( "ang", 1.0000000000000000E10, CDC_Length ); // Angstroem
2428 NEWD( "Pica", 2.8346456692913386E03, CDC_Length ); // Pica (1/72 Inch) 2834,6456692913385826771653543307
2429 NEWD( "ell", 8.748906E-01, CDC_Length ); // *** Ell
2430 NEWDP( "parsec", 3.240779E-17, CDC_Length ); // *** Parsec
2431 NEWDP( "pc", 3.240779E-17, CDC_Length ); // *** Parsec also
2432 NEWDP( "lightyear", 1.0570234557732930E-16, CDC_Length ); // *** Light Year
2433 NEWDP( "ly", 1.0570234557732930E-16, CDC_Length ); // *** Light Year also
2434 NEWD( "survey_mi", 6.2136994949494949E-04, CDC_Length ); // U.S. survey mile
2436 // TIME: 1 Second is...
2437 NEWD( "yr", 3.1688087814028950E-08, CDC_Time ); // Year
2438 NEWD( "day", 1.1574074074074074E-05, CDC_Time ); // Day
2439 NEWD( "d", 1.1574074074074074E-05, CDC_Time ); // Day also
2440 NEWD( "hr", 2.7777777777777778E-04, CDC_Time ); // Hour
2441 NEWD( "mn", 1.6666666666666667E-02, CDC_Time ); // Minute
2442 NEWD( "min", 1.6666666666666667E-02, CDC_Time ); // Minute also
2443 NEWDP( "sec", 1.0000000000000000E00, CDC_Time ); // Second
2444 NEWDP( "s", 1.0000000000000000E00, CDC_Time ); // Second also
2446 // PRESSURE: 1 Pascal is...
2447 NEWDP( "Pa", 1.0000000000000000E00, CDC_Pressure ); // Pascal
2448 NEWDP( "atm", 9.8692329999819300E-06, CDC_Pressure ); // Atmosphere
2449 NEWDP( "at", 9.8692329999819300E-06, CDC_Pressure ); // Atmosphere also
2450 NEWDP( "mmHg", 7.5006170799862700E-03, CDC_Pressure ); // mm Hg (Mercury)
2451 NEWD( "Torr", 7.5006380000000000E-03, CDC_Pressure ); // *** Torr
2452 NEWD( "psi", 1.4503770000000000E-04, CDC_Pressure ); // *** Psi
2454 // FORCE: 1 Newton is...
2455 NEWDP( "N", 1.0000000000000000E00, CDC_Force ); // Newton
2456 NEWDP( "dyn", 1.0000000000000000E05, CDC_Force ); // Dyn
2457 NEWDP( "dy", 1.0000000000000000E05, CDC_Force ); // Dyn also
2458 NEWD( "lbf", 2.24808923655339E-01, CDC_Force ); // Pound-Force
2459 NEWDP( "pond", 1.019716E02, CDC_Force ); // *** Pond
2461 // ENERGY: 1 Joule is...
2462 NEWDP( "J", 1.0000000000000000E00, CDC_Energy ); // Joule
2463 NEWDP( "e", 1.0000000000000000E07, CDC_Energy ); // Erg -> http://www.chemie.fu-berlin.de/chemistry/general/si.html
2464 // NEWD( "e", 9.99999519343231E06, CDC_Energy ); // Erg
2465 NEWDP( "c", 2.3900624947346700E-01, CDC_Energy ); // Thermodynamical Calorie
2466 NEWDP( "cal", 2.3884619064201700E-01, CDC_Energy ); // Calorie
2467 NEWDP( "eV", 6.2414570000000000E18, CDC_Energy ); // Electronvolt
2468 NEWDP( "ev", 6.2414570000000000E18, CDC_Energy ); // Electronvolt also
2469 NEWD( "HPh", 3.7250611111111111E-07, CDC_Energy ); // Horsepower Hours
2470 NEWD( "hh", 3.7250611111111111E-07, CDC_Energy ); // Horsepower Hours also
2471 // NEWD( "HPh", 3.72506430801000E-07, CDC_Energy ); // Horsepower Hours
2472 NEWDP( "Wh", 2.7777777777777778E-04, CDC_Energy ); // Watt Hours
2473 NEWDP( "wh", 2.7777777777777778E-04, CDC_Energy ); // Watt Hours also
2474 NEWD( "flb", 2.37304222192651E01, CDC_Energy ); // Foot Pound
2475 NEWD( "BTU", 9.4781506734901500E-04, CDC_Energy ); // British Thermal Unit
2476 NEWD( "btu", 9.4781506734901500E-04, CDC_Energy ); // British Thermal Unit also
2478 // POWER: 1 Watt is...
2479 NEWDP( "W", 1.0000000000000000E00, CDC_Power ); // Watt
2480 NEWDP( "w", 1.0000000000000000E00, CDC_Power ); // Watt also
2481 NEWD( "HP", 1.341022E-03, CDC_Power ); // Horsepower
2482 NEWD( "h", 1.341022E-03, CDC_Power ); // Horsepower also
2483 NEWD( "PS", 1.359622E-03, CDC_Power ); // *** German Pferdestaerke
2484 // NEWD( "HP", 1.4102006031908E-03, CDC_Power ); // Excel seams to be a little bit wrong... either this doesn't fit to J -> HPh
2486 // MAGNETISM: 1 Tesla is...
2487 NEWDP( "T", 1.0000000000000000E00, CDC_Magnetism ); // Tesla
2488 NEWDP( "ga", 1.0000000000000000E04, CDC_Magnetism ); // Gauss
2490 // TEMERATURE: 1 Kelvin is...
2491 NEWL( "C", 1.0000000000000000E00, -2.7315000000000000E02, CDC_Temperature ); // Celsius
2492 NEWL( "cel", 1.0000000000000000E00, -2.7315000000000000E02, CDC_Temperature ); // Celsius also
2493 NEWL( "F", 1.8000000000000000E00, -2.5537222222222222E02, CDC_Temperature ); // Fahrenheit
2494 NEWL( "fah", 1.8000000000000000E00, -2.5537222222222222E02, CDC_Temperature ); // Fahrenheit also
2495 NEWLP( "K", 1.0000000000000000E00, +0.0000000000000000E00, CDC_Temperature ); // Kelvin
2496 NEWLP( "kel", 1.0000000000000000E00, +0.0000000000000000E00, CDC_Temperature ); // Kelvin also
2497 NEWL( "Reau", 8.0000000000000000E-01, -2.7315000000000000E02, CDC_Temperature ); // *** Reaumur
2498 NEWL( "Rank", 1.8000000000000000E00, +0.0000000000000000E00, CDC_Temperature ); // *** Rankine
2500 // VOLUMNE: 1 Liter is...
2501 NEWD( "tsp", 2.0284000000000000E02, CDC_Volume ); // Teaspoon
2502 NEWD( "tbs", 6.7613333333333333E01, CDC_Volume ); // Tablespoon
2503 NEWD( "oz", 3.3806666666666667E01, CDC_Volume ); // Ounce Liquid
2504 NEWD( "cup", 4.2258333333333333E00, CDC_Volume ); // Cup
2505 NEWD( "pt", 2.1129166666666667E00, CDC_Volume ); // US Pint
2506 NEWD( "us_pt", 2.1129166666666667E00, CDC_Volume ); // US Pint also
2507 NEWD( "uk_pt", 1.75975569552166E00, CDC_Volume ); // UK Pint
2508 NEWD( "qt", 1.0564583333333333E00, CDC_Volume ); // Quart
2509 NEWD( "gal", 2.6411458333333333E-01, CDC_Volume ); // Gallone
2510 NEWDP( "l", 1.0000000000000000E00, CDC_Volume ); // Liter
2511 NEWDP( "L", 1.0000000000000000E00, CDC_Volume ); // Liter also
2512 NEWDP( "lt", 1.0000000000000000E00, CDC_Volume ); // Liter also
2513 NEWDP( "m3", 1.0000000000000000E-03, CDC_Volume ); // *** Cubic Meter
2514 NEWD( "mi3", 2.3991275857892772E-13, CDC_Volume ); // *** Cubic Britsh Mile
2515 NEWD( "Nmi3", 1.5742621468581148E-13, CDC_Volume ); // *** Cubic Nautical Mile
2516 NEWD( "in3", 6.1023744094732284E01, CDC_Volume ); // *** Cubic Inch
2517 NEWD( "ft3", 3.5314666721488590E-02, CDC_Volume ); // *** Cubic Foot
2518 NEWD( "yd3", 1.3079506193143922E-03, CDC_Volume ); // *** Cubic Yard
2519 NEWDP( "ang3", 1.0000000000000000E27, CDC_Volume ); // *** Cubic Angstroem
2520 NEWD( "Pica3", 2.2776990435870636E07, CDC_Volume ); // *** Cubic Pica
2521 NEWD( "barrel", 6.289811E-03, CDC_Volume ); // *** Barrel (=42gal?)
2522 NEWD( "bushel", 2.837759E-02, CDC_Volume ); // *** Bushel
2523 NEWD( "regton", 3.531467E-04, CDC_Volume ); // *** Register ton
2524 NEWD( "GRT", 3.531467E-04, CDC_Volume ); // *** Register ton also
2525 NEWD( "Schooner", 2.3529411764705882E00, CDC_Volume ); // *** austr. Schooner
2526 NEWD( "Middy", 3.5087719298245614E00, CDC_Volume ); // *** austr. Middy
2527 NEWD( "Glass", 5.0000000000000000E00, CDC_Volume ); // *** austr. Glass
2528 NEWD( "Sixpack", 0.5, CDC_Volume ); // ***
2529 NEWD( "Humpen", 2.0, CDC_Volume ); // ***
2530 NEWD( "ly3", 1.1810108125623799E-51, CDC_Volume ); // *** Cubic light-year
2531 NEWD( "MTON", 1.4125866688595436E00, CDC_Volume ); // *** Measurement ton
2532 NEWD( "tspm", 5.0000000000000000E02, CDC_Volume ); // *** Modern teaspoon
2533 NEWD( "uk_gal", 2.199694619402070E-01, CDC_Volume ); // U.K. / Imperial gallon
2534 NEWD( "uk_qt", 8.798778477608300E-01, CDC_Volume ); // U.K. / Imperial quart
2536 // 1 Square Meter is...
2537 NEWDP( "m2", 1.0000000000000000E00, CDC_Area ); // *** Square Meter
2538 NEWD( "mi2", 3.8610215854244585E-07, CDC_Area ); // *** Square Britsh Mile
2539 NEWD( "Nmi2", 2.9155334959812286E-07, CDC_Area ); // *** Square Nautical Mile
2540 NEWD( "in2", 1.5500031000062000E03, CDC_Area ); // *** Square Inch
2541 NEWD( "ft2", 1.0763910416709722E01, CDC_Area ); // *** Square Foot
2542 NEWD( "yd2", 1.1959900463010803E00, CDC_Area ); // *** Square Yard
2543 NEWDP( "ang2", 1.0000000000000000E20, CDC_Area ); // *** Square Angstroem
2544 NEWD( "Pica2", 8.0352160704321409E06, CDC_Area ); // *** Square Pica
2545 NEWD( "Morgen", 4.0000000000000000E-04, CDC_Area ); // *** Morgen
2546 NEWDP( "ar", 1.000000E-02, CDC_Area ); // *** Ar
2547 NEWD( "acre", 2.471053815E-04, CDC_Area ); // *** Acre
2548 NEWD( "uk_acre", 2.4710538146716534E-04, CDC_Area ); // *** International acre
2549 NEWD( "us_acre", 2.4710439304662790E-04, CDC_Area ); // *** U.S. survey/statute acre
2550 NEWD( "ly2", 1.1172985860549147E-32, CDC_Area ); // *** Square Light-year
2551 NEWD( "ha", 1.000000E-04, CDC_Area ); // *** Hectare
2552 NEWD( "Quadratlatschen",5.6689342403628117914,CDC_Area ); // ***
2554 // SPEED: 1 Meter per Second is...
2555 NEWDP( "m/s", 1.0000000000000000E00, CDC_Speed ); // *** Meters per Second
2556 NEWDP( "m/sec", 1.0000000000000000E00, CDC_Speed ); // *** Meters per Second also
2557 NEWDP( "m/h", 3.6000000000000000E03, CDC_Speed ); // *** Meters per Hour
2558 NEWDP( "m/hr", 3.6000000000000000E03, CDC_Speed ); // *** Meters per Hour also
2559 NEWD( "mph", 2.2369362920544023E00, CDC_Speed ); // *** Britsh Miles per Hour
2560 NEWD( "kn", 1.9438444924406048E00, CDC_Speed ); // *** Knot = Nautical Miles per Hour
2561 NEWD( "admkn", 1.9438446603753486E00, CDC_Speed ); // *** Admiralty Knot
2562 NEWD( "wahnsinnige Geschwindigkeit", 2.0494886343432328E-14, CDC_Speed ); // ***
2563 NEWD( "ludicrous speed", 2.0494886343432328E-14, CDC_Speed ); // ***
2564 NEWD( "laecherliche Geschwindigkeit", 4.0156958471424288E-06, CDC_Speed); // ***
2565 NEWD( "ridiculous speed", 4.0156958471424288E-06, CDC_Speed); // ***
2567 // INFORMATION: 1 Bit is...
2568 NEWDP( "bit", 1.00E00, CDC_Information); // *** Bit
2569 NEWDP( "byte", 1.25E-01, CDC_Information); // *** Byte
2573 ConvertDataList::~ConvertDataList()
2575 for( ConvertData* p = First() ; p ; p = Next() )
2576 delete p;
2580 double ConvertDataList::Convert( double fVal, const STRING& rFrom, const STRING& rTo ) THROWDEF_RTE_IAE
2582 // This will not catch illegal units
2583 // if( rFrom == rTo )
2584 // return fVal;
2586 ConvertData* pFrom = NULL;
2587 ConvertData* pTo = NULL;
2588 sal_Bool bSearchFrom = sal_True;
2589 sal_Bool bSearchTo = sal_True;
2590 sal_Int16 nLevelFrom = 0;
2591 sal_Int16 nLevelTo = 0;
2593 ConvertData* p = First();
2594 while( p && ( bSearchFrom || bSearchTo ) )
2596 if( bSearchFrom )
2598 sal_Int16 n = p->GetMatchingLevel( rFrom );
2599 if( n != INV_MATCHLEV )
2601 if( n )
2602 { // only first match for partial equality rulz a little bit more
2603 pFrom = p;
2604 nLevelFrom = n;
2606 else
2607 { // ... but exact match rulz most
2608 pFrom = p;
2609 bSearchFrom = sal_False;
2610 nLevelFrom = n;
2615 if( bSearchTo )
2617 sal_Int16 n = p->GetMatchingLevel( rTo );
2618 if( n != INV_MATCHLEV )
2620 if( n )
2621 { // only first match for partial equality rulz a little bit more
2622 pTo = p;
2623 nLevelTo = n;
2625 else
2626 { // ... but exact match rulz most
2627 pTo = p;
2628 bSearchTo = sal_False;
2629 nLevelTo = n;
2634 p = Next();
2637 if( pFrom && pTo )
2638 return pFrom->Convert( fVal, *pTo, nLevelFrom, nLevelTo );
2639 else
2640 THROW_IAE;
2645 //-----------------------------------------------------------------------------
2647 ScaDate::ScaDate() :
2648 nOrigDay( 1 ),
2649 nDay( 1 ),
2650 nMonth( 1 ),
2651 nYear( 1900 ),
2652 bLastDayMode( sal_True ),
2653 bLastDay( sal_False ),
2654 b30Days( sal_False ),
2655 bUSMode( sal_False )
2659 ScaDate::ScaDate( sal_Int32 nNullDate, sal_Int32 nDate, sal_Int32 nBase )
2661 DaysToDate( nNullDate + nDate, nOrigDay, nMonth, nYear );
2662 bLastDayMode = (nBase != 5);
2663 bLastDay = (nOrigDay >= ::DaysInMonth( nMonth, nYear ));
2664 b30Days = (nBase == 0) || (nBase == 4);
2665 bUSMode = (nBase == 0);
2666 setDay();
2669 ScaDate::ScaDate( const ScaDate& rCopy ) :
2670 nOrigDay( rCopy.nOrigDay ),
2671 nDay( rCopy.nDay ),
2672 nMonth( rCopy.nMonth ),
2673 nYear( rCopy.nYear ),
2674 bLastDayMode( rCopy.bLastDayMode ),
2675 bLastDay( rCopy.bLastDay ),
2676 b30Days( rCopy.b30Days ),
2677 bUSMode( rCopy.bUSMode )
2681 ScaDate& ScaDate::operator=( const ScaDate& rCopy )
2683 if( this != &rCopy )
2685 nOrigDay = rCopy.nOrigDay;
2686 nDay = rCopy.nDay;
2687 nMonth = rCopy.nMonth;
2688 nYear = rCopy.nYear;
2689 bLastDayMode = rCopy.bLastDayMode;
2690 bLastDay = rCopy.bLastDay;
2691 b30Days = rCopy.b30Days;
2692 bUSMode = rCopy.bUSMode;
2694 return *this;
2697 void ScaDate::setDay()
2699 if( b30Days )
2701 // 30-days-mode: set nDay to 30 if original was last day in month
2702 nDay = Min( nOrigDay, static_cast< sal_uInt16 >( 30 ) );
2703 if( bLastDay || (nDay >= ::DaysInMonth( nMonth, nYear )) )
2704 nDay = 30;
2706 else
2708 // set nDay to last day in this month if original was last day
2709 sal_uInt16 nLastDay = ::DaysInMonth( nMonth, nYear );
2710 nDay = bLastDay ? nLastDay : Min( nOrigDay, nLastDay );
2714 sal_Int32 ScaDate::getDaysInMonthRange( sal_uInt16 nFrom, sal_uInt16 nTo ) const
2716 if( nFrom > nTo )
2717 return 0;
2719 sal_Int32 nRet = 0;
2720 if( b30Days )
2721 nRet = (nTo - nFrom + 1) * 30;
2722 else
2724 for( sal_uInt16 nMonthIx = nFrom; nMonthIx <= nTo; ++nMonthIx )
2725 nRet += getDaysInMonth( nMonthIx );
2727 return nRet;
2730 sal_Int32 ScaDate::getDaysInYearRange( sal_uInt16 nFrom, sal_uInt16 nTo ) const
2732 if( nFrom > nTo )
2733 return 0;
2735 return b30Days ? ((nTo - nFrom + 1) * 360) : ::GetDaysInYears( nFrom, nTo );
2738 void ScaDate::doAddYears( sal_Int32 nYearCount ) throw( lang::IllegalArgumentException )
2740 sal_Int32 nNewYear = nYearCount + nYear;
2741 if( (nNewYear < 0) || (nNewYear > 0x7FFF) )
2742 throw lang::IllegalArgumentException();
2743 nYear = static_cast< sal_uInt16 >( nNewYear );
2746 void ScaDate::addMonths( sal_Int32 nMonthCount ) throw( lang::IllegalArgumentException )
2748 sal_Int32 nNewMonth = nMonthCount + nMonth;
2749 if( nNewMonth > 12 )
2751 --nNewMonth;
2752 doAddYears( nNewMonth / 12 );
2753 nMonth = static_cast< sal_uInt16 >( nNewMonth % 12 ) + 1;
2755 else if( nNewMonth < 1 )
2757 doAddYears( nNewMonth / 12 - 1 );
2758 nMonth = static_cast< sal_uInt16 >( nNewMonth % 12 + 12 );
2760 else
2761 nMonth = static_cast< sal_uInt16 >( nNewMonth );
2762 setDay();
2765 sal_Int32 ScaDate::getDate( sal_Int32 nNullDate ) const
2767 sal_uInt16 nLastDay = ::DaysInMonth( nMonth, nYear );
2768 sal_uInt16 nRealDay = (bLastDayMode && bLastDay) ? nLastDay : Min( nLastDay, nOrigDay );
2769 return ::DateToDays( nRealDay, nMonth, nYear ) - nNullDate;
2772 sal_Int32 ScaDate::getDiff( const ScaDate& rFrom, const ScaDate& rTo ) throw( lang::IllegalArgumentException )
2774 if( rFrom > rTo )
2775 return getDiff( rTo, rFrom );
2777 sal_Int32 nDiff = 0;
2778 ScaDate aFrom( rFrom );
2779 ScaDate aTo( rTo );
2781 if( rTo.b30Days )
2783 // corrections for base 0 (US NASD)
2784 if( rTo.bUSMode )
2786 if( ((rFrom.nMonth == 2) || (rFrom.nDay < 30)) && (aTo.nOrigDay == 31) )
2787 aTo.nDay = 31;
2788 else if( (aTo.nMonth == 2) && aTo.bLastDay )
2789 aTo.nDay = ::DaysInMonth( 2, aTo.nYear );
2791 // corrections for base 4 (Europe)
2792 else
2794 if( (aFrom.nMonth == 2) && (aFrom.nDay == 30) )
2795 aFrom.nDay = ::DaysInMonth( 2, aFrom.nYear );
2796 if( (aTo.nMonth == 2) && (aTo.nDay == 30) )
2797 aTo.nDay = ::DaysInMonth( 2, aTo.nYear );
2801 if( (aFrom.nYear < aTo.nYear) || ((aFrom.nYear == aTo.nYear) && (aFrom.nMonth < aTo.nMonth)) )
2803 // move aFrom to 1st day of next month
2804 nDiff = aFrom.getDaysInMonth() - aFrom.nDay + 1;
2805 aFrom.nOrigDay = aFrom.nDay = 1;
2806 aFrom.bLastDay = sal_False;
2807 aFrom.addMonths( 1 );
2809 if( aFrom.nYear < aTo.nYear )
2811 // move aFrom to 1st day of next year
2812 nDiff += aFrom.getDaysInMonthRange( aFrom.nMonth, 12 );
2813 aFrom.addMonths( 13 - aFrom.nMonth );
2815 // move aFrom to 1st day of this year
2816 nDiff += aFrom.getDaysInYearRange( aFrom.nYear, aTo.nYear - 1 );
2817 aFrom.addYears( aTo.nYear - aFrom.nYear );
2820 // move aFrom to 1st day of this month
2821 nDiff += aFrom.getDaysInMonthRange( aFrom.nMonth, aTo.nMonth - 1 );
2822 aFrom.addMonths( aTo.nMonth - aFrom.nMonth );
2824 // finally add remaining days in this month
2825 nDiff += aTo.nDay - aFrom.nDay;
2826 return nDiff > 0 ? nDiff : 0;
2829 sal_Bool ScaDate::operator<( const ScaDate& rCmp ) const
2831 if( nYear != rCmp.nYear )
2832 return nYear < rCmp.nYear;
2833 if( nMonth != rCmp.nMonth )
2834 return nMonth < rCmp.nMonth;
2835 if( nDay != rCmp.nDay )
2836 return nDay < rCmp.nDay;
2837 if( bLastDay || rCmp.bLastDay )
2838 return !bLastDay && rCmp.bLastDay;
2839 return nOrigDay < rCmp.nOrigDay;
2844 //-----------------------------------------------------------------------------
2846 ScaAnyConverter::ScaAnyConverter( const uno::Reference< lang::XMultiServiceFactory >& xServiceFact ) :
2847 bHasValidFormat( sal_False )
2849 if( xServiceFact.is() )
2851 uno::Reference< uno::XInterface > xInstance = xServiceFact->createInstance(
2852 OUString::createFromAscii( "com.sun.star.util.NumberFormatter" ) );
2853 xFormatter = uno::Reference< util::XNumberFormatter >( xInstance, uno::UNO_QUERY );
2857 ScaAnyConverter::~ScaAnyConverter()
2861 void ScaAnyConverter::init( const uno::Reference< beans::XPropertySet >& xPropSet ) throw( uno::RuntimeException )
2863 // try to get default number format
2864 bHasValidFormat = sal_False;
2865 if( xFormatter.is() )
2867 // get XFormatsSupplier from outer XPropertySet
2868 uno::Reference< util::XNumberFormatsSupplier > xFormatsSupp( xPropSet, uno::UNO_QUERY );
2869 if( xFormatsSupp.is() )
2871 // get XNumberFormatTypes from XNumberFormatsSupplier to get standard index
2872 uno::Reference< util::XNumberFormats > xFormats( xFormatsSupp->getNumberFormats() );
2873 uno::Reference< util::XNumberFormatTypes > xFormatTypes( xFormats, uno::UNO_QUERY );
2874 if( xFormatTypes.is() )
2876 lang::Locale eLocale;
2877 nDefaultFormat = xFormatTypes->getStandardIndex( eLocale );
2878 xFormatter->attachNumberFormatsSupplier( xFormatsSupp );
2879 bHasValidFormat = sal_True;
2885 double ScaAnyConverter::convertToDouble( const OUString& rString ) const throw( lang::IllegalArgumentException )
2887 double fValue = 0.0;
2888 if( bHasValidFormat )
2892 fValue = xFormatter->convertStringToNumber( nDefaultFormat, rString );
2894 catch( uno::Exception& )
2896 throw lang::IllegalArgumentException();
2899 else
2901 rtl_math_ConversionStatus eStatus;
2902 sal_Int32 nEnd;
2903 fValue = ::rtl::math::stringToDouble( rString, '.', ',', &eStatus, &nEnd );
2904 if( (eStatus != rtl_math_ConversionStatus_Ok) || (nEnd < rString.getLength()) )
2905 throw lang::IllegalArgumentException();
2907 return fValue;
2910 sal_Bool ScaAnyConverter::getDouble(
2911 double& rfResult,
2912 const uno::Any& rAny ) const throw( lang::IllegalArgumentException )
2914 rfResult = 0.0;
2915 sal_Bool bContainsVal = sal_True;
2916 switch( rAny.getValueTypeClass() )
2918 case uno::TypeClass_VOID:
2919 bContainsVal = sal_False;
2920 break;
2921 case uno::TypeClass_DOUBLE:
2922 rAny >>= rfResult;
2923 break;
2924 case uno::TypeClass_STRING:
2926 const OUString* pString = static_cast< const OUString* >( rAny.getValue() );
2927 if( pString->getLength() )
2928 rfResult = convertToDouble( *pString );
2929 else
2930 bContainsVal = sal_False;
2932 break;
2933 default:
2934 throw lang::IllegalArgumentException();
2936 return bContainsVal;
2939 sal_Bool ScaAnyConverter::getDouble(
2940 double& rfResult,
2941 const uno::Reference< beans::XPropertySet >& xPropSet,
2942 const uno::Any& rAny ) throw( uno::RuntimeException, lang::IllegalArgumentException )
2944 init( xPropSet );
2945 return getDouble( rfResult, rAny );
2948 double ScaAnyConverter::getDouble(
2949 const uno::Reference< beans::XPropertySet >& xPropSet,
2950 const uno::Any& rAny,
2951 double fDefault ) throw( uno::RuntimeException, lang::IllegalArgumentException )
2953 double fResult;
2954 if( !getDouble( fResult, xPropSet, rAny ) )
2955 fResult = fDefault;
2956 return fResult;
2959 sal_Bool ScaAnyConverter::getInt32(
2960 sal_Int32& rnResult,
2961 const uno::Reference< beans::XPropertySet >& xPropSet,
2962 const uno::Any& rAny ) throw( uno::RuntimeException, lang::IllegalArgumentException )
2964 double fResult;
2965 sal_Bool bContainsVal = getDouble( fResult, xPropSet, rAny );
2966 if( (fResult <= -2147483649.0) || (fResult >= 2147483648.0) )
2967 throw lang::IllegalArgumentException();
2969 rnResult = static_cast< sal_Int32 >( fResult );
2970 return bContainsVal;
2973 sal_Int32 ScaAnyConverter::getInt32(
2974 const uno::Reference< beans::XPropertySet >& xPropSet,
2975 const uno::Any& rAny,
2976 sal_Int32 nDefault ) throw( uno::RuntimeException, lang::IllegalArgumentException )
2978 sal_Int32 nResult;
2979 if( !getInt32( nResult, xPropSet, rAny ) )
2980 nResult = nDefault;
2981 return nResult;
2986 //-----------------------------------------------------------------------------