1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <com/sun/star/util/Date.hpp>
21 #include <com/sun/star/util/XNumberFormatTypes.hpp>
22 #include <com/sun/star/util/NumberFormatter.hpp>
26 #include <o3tl/any.hxx>
27 #include <rtl/math.hxx>
30 #include "analysisdefs.hxx"
31 #include "analysishelper.hxx"
32 #include <analysis.hrc>
33 #include <strings.hrc>
34 #include "deffuncname.hxx"
36 using namespace ::com::sun::star
;
37 using namespace sca::analysis
;
39 #define UNIQUE false // function name does not exist in Calc
40 #define DOUBLE true // function name exists in Calc
42 #define STDPAR false // all parameters are described
43 #define INTPAR true // first parameter is internal
45 #define FUNCDATA( FUNCNAME, DBL, OPT, NUMOFPAR, CAT ) \
46 { "get" #FUNCNAME, ANALYSIS_FUNCNAME_##FUNCNAME, ANALYSIS_##FUNCNAME, DBL, OPT, ANALYSIS_DEFFUNCNAME_##FUNCNAME, NUMOFPAR, CAT, nullptr }
48 #define FUNCDATAS( FUNCNAME, DBL, OPT, NUMOFPAR, CAT, SUFFIX ) \
49 { "get" #FUNCNAME, ANALYSIS_FUNCNAME_##FUNCNAME, ANALYSIS_##FUNCNAME, DBL, OPT, ANALYSIS_DEFFUNCNAME_##FUNCNAME, NUMOFPAR, CAT, SUFFIX }
51 const FuncDataBase pFuncDatas
[] =
53 // UNIQUE or INTPAR or
54 // function name DOUBLE STDPAR # of param category
55 FUNCDATA( Workday
, UNIQUE
, INTPAR
, 3, FDCategory::DateTime
),
56 FUNCDATA( Yearfrac
, UNIQUE
, INTPAR
, 3, FDCategory::DateTime
),
57 FUNCDATA( Edate
, UNIQUE
, INTPAR
, 2, FDCategory::DateTime
),
58 FUNCDATAS( Weeknum
, DOUBLE
, INTPAR
, 2, FDCategory::DateTime
, "_EXCEL2003" ),
59 FUNCDATA( Eomonth
, UNIQUE
, INTPAR
, 2, FDCategory::DateTime
),
60 FUNCDATAS( Networkdays
, DOUBLE
, INTPAR
, 3, FDCategory::DateTime
, "_EXCEL2003" ),
61 FUNCDATA( Iseven
, DOUBLE
, STDPAR
, 1, FDCategory::Inf
),
62 FUNCDATA( Isodd
, DOUBLE
, STDPAR
, 1, FDCategory::Inf
),
63 FUNCDATA( Multinomial
, UNIQUE
, STDPAR
, 1, FDCategory::Math
),
64 FUNCDATA( Seriessum
, UNIQUE
, STDPAR
, 4, FDCategory::Math
),
65 FUNCDATA( Quotient
, UNIQUE
, STDPAR
, 2, FDCategory::Math
),
66 FUNCDATA( Mround
, UNIQUE
, STDPAR
, 2, FDCategory::Math
),
67 FUNCDATA( Sqrtpi
, UNIQUE
, STDPAR
, 1, FDCategory::Math
),
68 FUNCDATA( Randbetween
, UNIQUE
, STDPAR
, 2, FDCategory::Math
),
69 FUNCDATAS( Gcd
, DOUBLE
, INTPAR
, 1, FDCategory::Math
, "_EXCEL2003" ),
70 FUNCDATAS( Lcm
, DOUBLE
, INTPAR
, 1, FDCategory::Math
, "_EXCEL2003" ),
71 FUNCDATA( Besseli
, UNIQUE
, STDPAR
, 2, FDCategory::Tech
),
72 FUNCDATA( Besselj
, UNIQUE
, STDPAR
, 2, FDCategory::Tech
),
73 FUNCDATA( Besselk
, UNIQUE
, STDPAR
, 2, FDCategory::Tech
),
74 FUNCDATA( Bessely
, UNIQUE
, STDPAR
, 2, FDCategory::Tech
),
75 FUNCDATA( Bin2Oct
, UNIQUE
, INTPAR
, 2, FDCategory::Tech
),
76 FUNCDATA( Bin2Dec
, UNIQUE
, STDPAR
, 1, FDCategory::Tech
),
77 FUNCDATA( Bin2Hex
, UNIQUE
, INTPAR
, 2, FDCategory::Tech
),
78 FUNCDATA( Oct2Bin
, UNIQUE
, INTPAR
, 2, FDCategory::Tech
),
79 FUNCDATA( Oct2Dec
, UNIQUE
, STDPAR
, 1, FDCategory::Tech
),
80 FUNCDATA( Oct2Hex
, UNIQUE
, INTPAR
, 2, FDCategory::Tech
),
81 FUNCDATA( Dec2Bin
, UNIQUE
, INTPAR
, 2, FDCategory::Tech
),
82 FUNCDATA( Dec2Hex
, UNIQUE
, INTPAR
, 2, FDCategory::Tech
),
83 FUNCDATA( Dec2Oct
, UNIQUE
, INTPAR
, 2, FDCategory::Tech
),
84 FUNCDATA( Hex2Bin
, UNIQUE
, INTPAR
, 2, FDCategory::Tech
),
85 FUNCDATA( Hex2Dec
, UNIQUE
, STDPAR
, 1, FDCategory::Tech
),
86 FUNCDATA( Hex2Oct
, UNIQUE
, INTPAR
, 2, FDCategory::Tech
),
87 FUNCDATA( Delta
, UNIQUE
, INTPAR
, 2, FDCategory::Tech
),
88 FUNCDATA( Erf
, UNIQUE
, INTPAR
, 2, FDCategory::Tech
),
89 FUNCDATA( Erfc
, UNIQUE
, STDPAR
, 1, FDCategory::Tech
),
90 FUNCDATA( Gestep
, UNIQUE
, INTPAR
, 2, FDCategory::Tech
),
91 FUNCDATA( Factdouble
, UNIQUE
, STDPAR
, 1, FDCategory::Tech
),
92 FUNCDATA( Imabs
, UNIQUE
, STDPAR
, 1, FDCategory::Tech
),
93 FUNCDATA( Imaginary
, UNIQUE
, STDPAR
, 1, FDCategory::Tech
),
94 FUNCDATA( Impower
, UNIQUE
, STDPAR
, 2, FDCategory::Tech
),
95 FUNCDATA( Imargument
, UNIQUE
, STDPAR
, 1, FDCategory::Tech
),
96 FUNCDATA( Imcos
, UNIQUE
, STDPAR
, 1, FDCategory::Tech
),
97 FUNCDATA( Imdiv
, UNIQUE
, STDPAR
, 2, FDCategory::Tech
),
98 FUNCDATA( Imexp
, UNIQUE
, STDPAR
, 1, FDCategory::Tech
),
99 FUNCDATA( Imconjugate
, UNIQUE
, STDPAR
, 1, FDCategory::Tech
),
100 FUNCDATA( Imln
, UNIQUE
, STDPAR
, 1, FDCategory::Tech
),
101 FUNCDATA( Imlog10
, UNIQUE
, STDPAR
, 1, FDCategory::Tech
),
102 FUNCDATA( Imlog2
, UNIQUE
, STDPAR
, 1, FDCategory::Tech
),
103 FUNCDATA( Improduct
, UNIQUE
, INTPAR
, 2, FDCategory::Tech
),
104 FUNCDATA( Imreal
, UNIQUE
, STDPAR
, 1, FDCategory::Tech
),
105 FUNCDATA( Imsin
, UNIQUE
, STDPAR
, 1, FDCategory::Tech
),
106 FUNCDATA( Imsub
, UNIQUE
, STDPAR
, 2, FDCategory::Tech
),
107 FUNCDATA( Imsqrt
, UNIQUE
, STDPAR
, 1, FDCategory::Tech
),
108 FUNCDATA( Imsum
, UNIQUE
, INTPAR
, 1, FDCategory::Tech
),
109 FUNCDATA( Imtan
, UNIQUE
, STDPAR
, 1, FDCategory::Tech
),
110 FUNCDATA( Imsec
, UNIQUE
, STDPAR
, 1, FDCategory::Tech
),
111 FUNCDATA( Imcsc
, UNIQUE
, STDPAR
, 1, FDCategory::Tech
),
112 FUNCDATA( Imcot
, UNIQUE
, STDPAR
, 1, FDCategory::Tech
),
113 FUNCDATA( Imsinh
, UNIQUE
, STDPAR
, 1, FDCategory::Tech
),
114 FUNCDATA( Imcosh
, UNIQUE
, STDPAR
, 1, FDCategory::Tech
),
115 FUNCDATA( Imsech
, UNIQUE
, STDPAR
, 1, FDCategory::Tech
),
116 FUNCDATA( Imcsch
, UNIQUE
, STDPAR
, 1, FDCategory::Tech
),
117 FUNCDATA( Complex
, UNIQUE
, STDPAR
, 3, FDCategory::Tech
),
118 FUNCDATA( Convert
, UNIQUE
, STDPAR
, 3, FDCategory::Tech
),
119 FUNCDATA( Amordegrc
, UNIQUE
, INTPAR
, 7, FDCategory::Finance
),
120 FUNCDATA( Amorlinc
, UNIQUE
, INTPAR
, 7, FDCategory::Finance
),
121 FUNCDATA( Accrint
, UNIQUE
, INTPAR
, 7, FDCategory::Finance
),
122 FUNCDATA( Accrintm
, UNIQUE
, INTPAR
, 5, FDCategory::Finance
),
123 FUNCDATA( Received
, UNIQUE
, INTPAR
, 5, FDCategory::Finance
),
124 FUNCDATA( Disc
, UNIQUE
, INTPAR
, 5, FDCategory::Finance
),
125 FUNCDATA( Duration
, UNIQUE
, INTPAR
, 6, FDCategory::Finance
),
126 FUNCDATA( Effect
, DOUBLE
, STDPAR
, 2, FDCategory::Finance
),
127 FUNCDATA( Cumprinc
, DOUBLE
, STDPAR
, 6, FDCategory::Finance
),
128 FUNCDATA( Cumipmt
, DOUBLE
, STDPAR
, 6, FDCategory::Finance
),
129 FUNCDATA( Price
, UNIQUE
, INTPAR
, 7, FDCategory::Finance
),
130 FUNCDATA( Pricedisc
, UNIQUE
, INTPAR
, 5, FDCategory::Finance
),
131 FUNCDATA( Pricemat
, UNIQUE
, INTPAR
, 6, FDCategory::Finance
),
132 FUNCDATA( Mduration
, UNIQUE
, INTPAR
, 6, FDCategory::Finance
),
133 FUNCDATA( Nominal
, DOUBLE
, STDPAR
, 2, FDCategory::Finance
),
134 FUNCDATA( Dollarfr
, UNIQUE
, STDPAR
, 2, FDCategory::Finance
),
135 FUNCDATA( Dollarde
, UNIQUE
, STDPAR
, 2, FDCategory::Finance
),
136 FUNCDATA( Yield
, UNIQUE
, INTPAR
, 7, FDCategory::Finance
),
137 FUNCDATA( Yielddisc
, UNIQUE
, INTPAR
, 5, FDCategory::Finance
),
138 FUNCDATA( Yieldmat
, UNIQUE
, INTPAR
, 6, FDCategory::Finance
),
139 FUNCDATA( Tbilleq
, UNIQUE
, INTPAR
, 3, FDCategory::Finance
),
140 FUNCDATA( Tbillprice
, UNIQUE
, INTPAR
, 3, FDCategory::Finance
),
141 FUNCDATA( Tbillyield
, UNIQUE
, INTPAR
, 3, FDCategory::Finance
),
142 FUNCDATA( Oddfprice
, UNIQUE
, INTPAR
, 9, FDCategory::Finance
),
143 FUNCDATA( Oddfyield
, UNIQUE
, INTPAR
, 9, FDCategory::Finance
),
144 FUNCDATA( Oddlprice
, UNIQUE
, INTPAR
, 8, FDCategory::Finance
),
145 FUNCDATA( Oddlyield
, UNIQUE
, INTPAR
, 8, FDCategory::Finance
),
146 FUNCDATA( Xirr
, UNIQUE
, INTPAR
, 3, FDCategory::Finance
),
147 FUNCDATA( Xnpv
, UNIQUE
, STDPAR
, 3, FDCategory::Finance
),
148 FUNCDATA( Intrate
, UNIQUE
, INTPAR
, 5, FDCategory::Finance
),
149 FUNCDATA( Coupncd
, UNIQUE
, INTPAR
, 4, FDCategory::Finance
),
150 FUNCDATA( Coupdays
, UNIQUE
, INTPAR
, 4, FDCategory::Finance
),
151 FUNCDATA( Coupdaysnc
, UNIQUE
, INTPAR
, 4, FDCategory::Finance
),
152 FUNCDATA( Coupdaybs
, UNIQUE
, INTPAR
, 4, FDCategory::Finance
),
153 FUNCDATA( Couppcd
, UNIQUE
, INTPAR
, 4, FDCategory::Finance
),
154 FUNCDATA( Coupnum
, UNIQUE
, INTPAR
, 4, FDCategory::Finance
),
155 FUNCDATA( Fvschedule
, UNIQUE
, STDPAR
, 2, FDCategory::Finance
)
159 namespace sca
{ namespace analysis
{
161 sal_uInt16
DaysInMonth( sal_uInt16 nMonth
, sal_uInt16 nYear
)
163 if( (nMonth
== 2) && IsLeapYear( nYear
) )
165 static const sal_uInt16 aDaysInMonth
[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
166 return aDaysInMonth
[ nMonth
];
171 * Convert a date to a count of days starting from 01/01/0001
173 * The internal representation of a Date used in this Addin
174 * is the number of days between 01/01/0001 and the date
175 * this function converts a Day , Month, Year representation
176 * to this internal Date value.
180 sal_Int32
DateToDays( sal_uInt16 nDay
, sal_uInt16 nMonth
, sal_uInt16 nYear
)
182 sal_Int32 nDays
= (static_cast<sal_Int32
>(nYear
)-1) * 365;
183 nDays
+= ((nYear
-1) / 4) - ((nYear
-1) / 100) + ((nYear
-1) / 400);
185 for( sal_uInt16 i
= 1; i
< nMonth
; i
++ )
186 nDays
+= DaysInMonth(i
,nYear
);
194 * Convert a count of days starting from 01/01/0001 to a date
196 * The internal representation of a Date used in this Addin
197 * is the number of days between 01/01/0001 and the date
198 * this function converts this internal Date value
199 * to a Day , Month, Year representation of a Date.
203 void DaysToDate( sal_Int32 nDays
, sal_uInt16
& rDay
, sal_uInt16
& rMonth
, sal_uInt16
& rYear
)
206 throw lang::IllegalArgumentException();
215 rYear
= static_cast<sal_uInt16
>((nTempDays
/ 365) - i
);
216 nTempDays
-= (static_cast<sal_Int32
>(rYear
) -1) * 365;
217 nTempDays
-= (( rYear
-1) / 4) - (( rYear
-1) / 100) + ((rYear
-1) / 400);
226 if ( nTempDays
> 365 )
228 if ( (nTempDays
!= 366) || !IsLeapYear( rYear
) )
239 while ( nTempDays
> DaysInMonth( rMonth
, rYear
) )
241 nTempDays
-= DaysInMonth( rMonth
, rYear
);
244 rDay
= static_cast<sal_uInt16
>(nTempDays
);
249 * Get the null date used by the spreadsheet document
251 * The internal representation of a Date used in this Addin
252 * is the number of days between 01/01/0001 and the date
253 * this function returns this internal Date value for the document null date
257 sal_Int32
GetNullDate( const uno::Reference
< beans::XPropertySet
>& xOpt
)
263 uno::Any aAny
= xOpt
->getPropertyValue( "NullDate" );
266 return DateToDays( aDate
.Day
, aDate
.Month
, aDate
.Year
);
268 catch( uno::Exception
& )
273 // no null date available -> no calculations possible
274 throw uno::RuntimeException();
278 sal_Int32
GetDiffDate360(
279 sal_uInt16 nDay1
, sal_uInt16 nMonth1
, sal_uInt16 nYear1
, bool bLeapYear1
,
280 sal_uInt16 nDay2
, sal_uInt16 nMonth2
, sal_uInt16 nYear2
,
285 else if( bUSAMethod
&& ( nMonth1
== 2 && ( nDay1
== 29 || ( nDay1
== 28 && !bLeapYear1
) ) ) )
290 if( bUSAMethod
&& nDay1
!= 30 )
305 return nDay2
+ nMonth2
* 30 + nYear2
* 360 - nDay1
- nMonth1
* 30 - nYear1
* 360;
309 sal_Int32
GetDiffDate360( sal_Int32 nNullDate
, sal_Int32 nDate1
, sal_Int32 nDate2
, bool bUSAMethod
)
314 sal_uInt16 nDay1
, nMonth1
, nYear1
, nDay2
, nMonth2
, nYear2
;
316 DaysToDate( nDate1
, nDay1
, nMonth1
, nYear1
);
317 DaysToDate( nDate2
, nDay2
, nMonth2
, nYear2
);
319 return GetDiffDate360( nDay1
, nMonth1
, nYear1
, IsLeapYear( nYear1
), nDay2
, nMonth2
, nYear2
, bUSAMethod
);
323 sal_Int32
GetDaysInYears( sal_uInt16 nYear1
, sal_uInt16 nYear2
)
325 sal_uInt16 nLeaps
= 0;
326 for( sal_uInt16 n
= nYear1
; n
<= nYear2
; n
++ )
328 if( IsLeapYear( n
) )
342 sal_Int32
GetDiffDate( sal_Int32 nNullDate
, sal_Int32 nStartDate
, sal_Int32 nEndDate
, sal_Int32 nMode
,
343 sal_Int32
* pOptDaysIn1stYear
)
345 bool bNeg
= nStartDate
> nEndDate
;
349 sal_Int32 n
= nEndDate
;
350 nEndDate
= nStartDate
;
358 case 0: // 0=USA (NASD) 30/360
359 case 4: // 4=Europe 30/360
361 sal_uInt16 nD1
, nM1
, nY1
, nD2
, nM2
, nY2
;
363 nStartDate
+= nNullDate
;
364 nEndDate
+= nNullDate
;
366 DaysToDate( nStartDate
, nD1
, nM1
, nY1
);
367 DaysToDate( nEndDate
, nD2
, nM2
, nY2
);
369 bool bLeap
= IsLeapYear( nY1
);
370 sal_Int32 nDays
, nMonths
;
375 nMonths
+= ( nY2
- nY1
) * 12;
377 nRet
= nMonths
* 30 + nDays
;
378 if( nMode
== 0 && nM1
== 2 && nM2
!= 2 && nY1
== nY2
)
379 nRet
-= bLeap
? 1 : 2;
381 if( pOptDaysIn1stYear
)
382 *pOptDaysIn1stYear
= 360;
385 case 1: // 1=exact/exact
386 if( pOptDaysIn1stYear
)
388 sal_uInt16 nD
, nM
, nY
;
390 DaysToDate( nStartDate
+ nNullDate
, nD
, nM
, nY
);
392 *pOptDaysIn1stYear
= IsLeapYear( nY
)? 366 : 365;
394 nRet
= nEndDate
- nStartDate
;
396 case 2: // 2=exact/360
397 nRet
= nEndDate
- nStartDate
;
398 if( pOptDaysIn1stYear
)
399 *pOptDaysIn1stYear
= 360;
401 case 3: //3=exact/365
402 nRet
= nEndDate
- nStartDate
;
403 if( pOptDaysIn1stYear
)
404 *pOptDaysIn1stYear
= 365;
407 throw lang::IllegalArgumentException();
410 return bNeg
? -nRet
: nRet
;
414 double GetYearDiff( sal_Int32 nNullDate
, sal_Int32 nStartDate
, sal_Int32 nEndDate
, sal_Int32 nMode
)
416 sal_Int32 nDays1stYear
;
417 sal_Int32 nTotalDays
= GetDiffDate( nNullDate
, nStartDate
, nEndDate
, nMode
, &nDays1stYear
);
419 return double( nTotalDays
) / double( nDays1stYear
);
423 sal_Int32
GetDaysInYear( sal_Int32 nNullDate
, sal_Int32 nDate
, sal_Int32 nMode
)
427 case 0: // 0=USA (NASD) 30/360
428 case 2: // 2=exact/360
429 case 4: // 4=Europe 30/360
431 case 1: // 1=exact/exact
433 sal_uInt16 nD
, nM
, nY
;
435 DaysToDate( nDate
, nD
, nM
, nY
);
436 return IsLeapYear( nY
)? 366 : 365;
438 case 3: //3=exact/365
441 throw lang::IllegalArgumentException();
446 // tdf69569 making code compliant with change request for ODFF1.2 par 4.11.7.7
448 * Function GetYearFrac implements YEARFRAC as defined in:
449 * Open Document Format for Office Applications version 1.2 Part 2, par. 6.10.24
450 * The calculations are defined in:
451 * Open Document Format for Office Applications version 1.2 Part 2, par. 4.11.7
453 double GetYearFrac( sal_Int32 nNullDate
, sal_Int32 nStartDate
, sal_Int32 nEndDate
, sal_Int32 nMode
)
455 if( nStartDate
== nEndDate
)
456 return 0.0; // nothing to do...
458 if( nStartDate
> nEndDate
)
460 sal_Int32 n
= nEndDate
;
461 nEndDate
= nStartDate
;
465 sal_Int32 nDate1
= nStartDate
+ nNullDate
;
466 sal_Int32 nDate2
= nEndDate
+ nNullDate
;
468 sal_uInt16 nDay1
, nDay2
;
469 sal_uInt16 nMonth1
, nMonth2
;
470 sal_uInt16 nYear1
, nYear2
;
472 DaysToDate( nDate1
, nDay1
, nMonth1
, nYear1
);
473 DaysToDate( nDate2
, nDay2
, nMonth2
, nYear2
);
475 // calculate days between nDate1 and nDate2
479 case 0: // 0=USA (NASD) 30/360
484 if ( nDay1
== 30 && nDay2
== 31 )
490 if ( nMonth1
== 2 && nDay1
== ( IsLeapYear( nYear1
) ? 29 : 28 ) )
493 if ( nMonth2
== 2 && nDay2
== ( IsLeapYear( nYear2
) ? 29 : 28 ) )
499 nDayDiff
= ( nYear2
- nYear1
) * 360 + ( nMonth2
- nMonth1
) * 30 + ( nDay2
- nDay1
);
501 case 1: // 1=exact/exact
502 case 2: // 2=exact/360
503 case 3: // 3=exact/365
504 nDayDiff
= nDate2
- nDate1
;
506 case 4: // 4=Europe 30/360
515 nDayDiff
= ( nYear2
- nYear1
) * 360 + ( nMonth2
- nMonth1
) * 30 + ( nDay2
- nDay1
);
518 throw lang::IllegalArgumentException();
521 //calculate days in year
525 case 0: // 0=USA (NASD) 30/360
526 case 2: // 2=exact/360
527 case 4: // 4=Europe 30/360
530 case 1: // 1=exact/exact
532 const bool isYearDifferent
= ( nYear1
!= nYear2
);
533 // ODFv1.2 part 2 section 4.11.7.7.7
534 if ( isYearDifferent
&&
535 ( ( nYear2
!= nYear1
+ 1 ) ||
536 ( nMonth1
< nMonth2
) ||
537 ( nMonth1
== nMonth2
&& nDay1
< nDay2
) ) )
539 // return average of days in year between nDate1 and nDate2, inclusive
540 sal_Int32 nDayCount
= 0;
541 for ( sal_uInt16 i
= nYear1
; i
<= nYear2
; i
++ )
542 nDayCount
+= ( IsLeapYear( i
) ? 366 : 365 );
544 nDaysInYear
= static_cast<double>(nDayCount
) / static_cast<double>( nYear2
- nYear1
+ 1 );
548 // as a consequence, !isYearDifferent or
549 // nYear2 == nYear + 1 and (nMonth1 > nMonth2 or
550 // (nMonth1 == nMonth2 and nDay1 >= nDay2))
551 assert( ( !isYearDifferent
||
552 ( nYear1
+ 1 == nYear2
&&
553 ( nMonth1
> nMonth2
||
554 ( nMonth1
== nMonth2
|| nDay1
>= nDay2
) ) ) ) );
556 // ODFv1.2 part 2 section 4.11.7.7.8 (CHANGE REQUEST PENDING, see tdf6959)
557 if ( !isYearDifferent
&& IsLeapYear( nYear1
) )
563 // ODFv1.2 part 2 section 4.11.7.7.9/10 (CHANGE REQUEST PENDING, see tdf69569)
564 // we need to determine whether there is a 29 February
565 // between nDate1 (inclusive) and nDate2 (inclusive)
566 // the case of nYear1 == nYear2 is adequately tested in previous test
567 if( isYearDifferent
&&
568 ( ( IsLeapYear( nYear1
) &&
569 ( ( nMonth1
< 2 ) || ( ( nMonth1
== 2 ) && ( nDay1
<= 29 ) ) ) ) ||
570 ( IsLeapYear( nYear2
) &&
571 ( nMonth2
> 2 || ( ( nMonth2
== 2 ) && ( nDay2
== 29 ) ) ) ) ) )
583 case 3: // 3=exact/365
586 // coverity[dead_error_begin] - following conditions exist to avoid compiler warning
588 throw lang::IllegalArgumentException();
591 return double( nDayDiff
) / nDaysInYear
;
594 double BinomialCoefficient( double n
, double k
)
596 // This method is a copy of BinomKoeff()
597 // found in sc/source/core/tool/interpr3.cxx
600 k
= ::rtl::math::approxFloor(k
);
620 double GetGcd( double f1
, double f2
)
622 double f
= fmod( f1
, f2
);
634 double ConvertToDec( const OUString
& aStr
, sal_uInt16 nBase
, sal_uInt16 nCharLim
)
636 if ( nBase
< 2 || nBase
> 36 )
637 throw lang::IllegalArgumentException();
639 sal_uInt32 nStrLen
= aStr
.getLength();
640 if( nStrLen
> nCharLim
)
641 throw lang::IllegalArgumentException();
647 const sal_Unicode
* p
= aStr
.getStr();
649 sal_uInt16 nFirstDig
= 0;
650 bool bFirstDig
= true;
651 double fBase
= nBase
;
657 if( '0' <= *p
&& *p
<= '9' )
659 else if( 'A' <= *p
&& *p
<= 'Z' )
660 n
= 10 + ( *p
- 'A' );
661 else if ( 'a' <= *p
&& *p
<= 'z' )
662 n
= 10 + ( *p
- 'a' );
667 throw lang::IllegalArgumentException(); // illegal char!
674 fVal
= fVal
* fBase
+ double( n
);
680 if( nStrLen
== nCharLim
&& !bFirstDig
&& (nFirstDig
>= nBase
/ 2) )
681 { // handling negative values
682 fVal
= ( pow( double( nBase
), double( nCharLim
) ) - fVal
); // complement
690 static sal_Char
GetMaxChar( sal_uInt16 nBase
)
692 const sal_Char
* const c
= "--123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
697 OUString
ConvertFromDec( double fNum
, double fMin
, double fMax
, sal_uInt16 nBase
,
698 sal_Int32 nPlaces
, sal_Int32 nMaxPlaces
, bool bUsePlaces
)
700 fNum
= ::rtl::math::approxFloor( fNum
);
701 fMin
= ::rtl::math::approxFloor( fMin
);
702 fMax
= ::rtl::math::approxFloor( fMax
);
704 if( fNum
< fMin
|| fNum
> fMax
|| ( bUsePlaces
&& ( nPlaces
<= 0 || nPlaces
> nMaxPlaces
) ) )
705 throw lang::IllegalArgumentException();
707 sal_Int64 nNum
= static_cast< sal_Int64
>( fNum
);
708 bool bNeg
= nNum
< 0;
710 nNum
= sal_Int64( pow( double( nBase
), double( nMaxPlaces
) ) ) + nNum
;
712 OUString
aRet( OUString::number( nNum
, nBase
).toAsciiUpperCase() );
717 sal_Int32 nLen
= aRet
.getLength();
718 if( !bNeg
&& nLen
> nPlaces
)
720 throw lang::IllegalArgumentException();
722 else if( ( bNeg
&& nLen
< nMaxPlaces
) || ( !bNeg
&& nLen
< nPlaces
) )
724 sal_Int32 nLeft
= nPlaces
- nLen
;
725 std::unique_ptr
<sal_Char
[]> p( new sal_Char
[ nLeft
+ 1 ] );
726 memset( p
.get(), bNeg
? GetMaxChar( nBase
) : '0', nLeft
);
728 OUString
aTmp( p
.get(), nLeft
, RTL_TEXTENCODING_MS_1252
);
737 // implementation moved to module sal, see #i97091#
738 double Erf( double x
)
740 return ::rtl::math::erf(x
);
743 // implementation moved to module sal, see #i97091#
744 double Erfc( double x
)
746 return ::rtl::math::erfc(x
);
749 static bool IsNum( sal_Unicode c
)
751 return c
>= '0' && c
<= '9';
755 static bool IsComma( sal_Unicode c
)
757 return c
== '.' || c
== ',';
761 static bool IsExpStart( sal_Unicode c
)
763 return c
== 'e' || c
== 'E';
767 static bool IsImagUnit( sal_Unicode c
)
769 return c
== 'i' || c
== 'j';
773 static sal_uInt16
GetVal( sal_Unicode c
)
775 return sal_uInt16( c
- '0' );
779 bool ParseDouble( const sal_Unicode
*& rp
, double& rRet
)
783 double fMult
= 0.1; // multiplier to multiply digits with, when adding fractional ones
785 sal_Int32 nMaxExp
= 307;
786 sal_uInt16 nDigCnt
= 18; // max. number of digits to read in, rest doesn't matter
788 enum State
{ S_End
= 0, S_Sign
, S_IntStart
, S_Int
, S_IgnoreIntDigs
, S_Frac
, S_IgnoreFracDigs
, S_ExpSign
, S_Exp
};
792 bool bNegNum
= false;
793 bool bNegExp
= false;
795 const sal_Unicode
* p
= rp
;
817 else if( IsComma( c
) )
829 else if( IsComma( c
) )
831 else if( IsImagUnit( c
) )
843 fInt
+= double( GetVal( c
) );
846 eS
= S_IgnoreIntDigs
;
848 else if( IsComma( c
) )
850 else if( IsExpStart( c
) )
855 case S_IgnoreIntDigs
:
857 nExp
++; // just multiply num with 10... ;-)
858 else if( IsComma( c
) )
860 else if( IsExpStart( c
) )
868 fFrac
+= double( GetVal( c
) ) * fMult
;
873 eS
= S_IgnoreFracDigs
;
875 else if( IsExpStart( c
) )
880 case S_IgnoreFracDigs
:
881 if( IsExpStart( c
) )
883 else if( !IsNum( c
) )
911 // coverity[dead_error_begin] - following conditions exist to avoid compiler warning
919 p
--; // set pointer back to last
924 if (fInt
!= 0.0) // exact check; log10(0.0) may entail a pole error
926 sal_Int32 nLog10
= sal_Int32( log10( fInt
) );
931 if( nLog10
+ nExp
> nMaxExp
)
934 fInt
= ::rtl::math::pow10Exp( fInt
, nExp
);
946 OUString
GetString( double f
, bool bLeadingSign
, sal_uInt16 nMaxDig
)
948 const int nBuff
= 256;
949 sal_Char aBuff
[ nBuff
+ 1 ];
950 const char* pFormStr
= bLeadingSign
? "%+.*g" : "%.*g";
951 int nLen
= snprintf( aBuff
, nBuff
, pFormStr
, int( nMaxDig
), f
);
952 // you never know which underlying implementation you get ...
954 if ( nLen
< 0 || nLen
> nBuff
)
955 nLen
= strlen( aBuff
);
957 OUString
aRet( aBuff
, nLen
, RTL_TEXTENCODING_MS_1252
);
963 double GetAmordegrc( sal_Int32 nNullDate
, double fCost
, sal_Int32 nDate
, sal_Int32 nFirstPer
,
964 double fRestVal
, double fPer
, double fRate
, sal_Int32 nBase
)
966 sal_uInt32 nPer
= sal_uInt32( fPer
);
967 double fUsePer
= 1.0 / fRate
;
972 else if( fUsePer
< 5.0 )
974 else if( fUsePer
<= 6.0 )
980 double fNRate
= ::rtl::math::round( GetYearFrac( nNullDate
, nDate
, nFirstPer
, nBase
) * fRate
* fCost
);
982 double fRest
= fCost
- fRestVal
; // aboriginal cost - residual value - sum of all write-downs
984 for( sal_uInt32 n
= 0 ; n
< nPer
; n
++ )
986 fNRate
= ::rtl::math::round( fRate
* fCost
);
995 return ::rtl::math::round( fCost
* 0.5 );
1008 double GetAmorlinc( sal_Int32 nNullDate
, double fCost
, sal_Int32 nDate
, sal_Int32 nFirstPer
,
1009 double fRestVal
, double fPer
, double fRate
, sal_Int32 nBase
)
1011 sal_uInt32 nPer
= sal_uInt32( fPer
);
1012 double fOneRate
= fCost
* fRate
;
1013 double fCostDelta
= fCost
- fRestVal
;
1014 double f0Rate
= GetYearFrac( nNullDate
, nDate
, nFirstPer
, nBase
) * fRate
* fCost
;
1015 sal_uInt32 nNumOfFullPeriods
= sal_uInt32( ( fCost
- fRestVal
- f0Rate
) / fOneRate
);
1017 double fResult
= 0.0;
1020 else if( nPer
<= nNumOfFullPeriods
)
1022 else if( nPer
== nNumOfFullPeriods
+ 1 )
1023 fResult
= fCostDelta
- fOneRate
* nNumOfFullPeriods
- f0Rate
;
1025 if ( fResult
> 0.0 )
1032 double GetDuration( sal_Int32 nNullDate
, sal_Int32 nSettle
, sal_Int32 nMat
, double fCoup
,
1033 double fYield
, sal_Int32 nFreq
, sal_Int32 nBase
)
1035 double fYearfrac
= GetYearFrac( nNullDate
, nSettle
, nMat
, nBase
);
1036 double fNumOfCoups
= GetCoupnum( nNullDate
, nSettle
, nMat
, nFreq
, nBase
);
1038 const double f100
= 100.0;
1039 fCoup
*= f100
/ double( nFreq
); // fCoup is used as cash flow
1043 double nDiff
= fYearfrac
* nFreq
- fNumOfCoups
;
1047 for( t
= 1.0 ; t
< fNumOfCoups
; t
++ )
1048 fDur
+= ( t
+ nDiff
) * fCoup
/ pow( fYield
, t
+ nDiff
);
1050 fDur
+= ( fNumOfCoups
+ nDiff
) * ( fCoup
+ f100
) / pow( fYield
, fNumOfCoups
+ nDiff
);
1053 for( t
= 1.0 ; t
< fNumOfCoups
; t
++ )
1054 p
+= fCoup
/ pow( fYield
, t
+ nDiff
);
1056 p
+= ( fCoup
+ f100
) / pow( fYield
, fNumOfCoups
+ nDiff
);
1059 fDur
/= double( nFreq
);
1065 double GetYieldmat( sal_Int32 nNullDate
, sal_Int32 nSettle
, sal_Int32 nMat
, sal_Int32 nIssue
,
1066 double fRate
, double fPrice
, sal_Int32 nBase
)
1068 double fIssMat
= GetYearFrac( nNullDate
, nIssue
, nMat
, nBase
);
1069 double fIssSet
= GetYearFrac( nNullDate
, nIssue
, nSettle
, nBase
);
1070 double fSetMat
= GetYearFrac( nNullDate
, nSettle
, nMat
, nBase
);
1072 double y
= 1.0 + fIssMat
* fRate
;
1073 y
/= fPrice
/ 100.0 + fIssSet
* fRate
;
1081 double GetOddfprice( sal_Int32
/*nNullDate*/, sal_Int32
/*nSettle*/, sal_Int32
/*nMat*/, sal_Int32
/*nIssue*/,
1082 sal_Int32
/*nFirstCoup*/, double /*fRate*/, double /*fYield*/, double /*fRedemp*/, sal_Int32
/*nFreq*/,
1083 sal_Int32
/*nBase*/ )
1085 // If you change this to not unconditionally throw, the
1086 // SAL_WNOUNREACHABLE_CODE_PUSH/POP around the caller in
1087 // financial.cxx can be removed.
1088 throw uno::RuntimeException();
1092 double getYield_( sal_Int32 nNullDate
, sal_Int32 nSettle
, sal_Int32 nMat
, double fCoup
, double fPrice
,
1093 double fRedemp
, sal_Int32 nFreq
, sal_Int32 nBase
)
1095 double fRate
= fCoup
;
1096 double fPriceN
= 0.0;
1097 double fYield1
= 0.0;
1098 double fYield2
= 1.0;
1099 double fPrice1
= getPrice_( nNullDate
, nSettle
, nMat
, fRate
, fYield1
, fRedemp
, nFreq
, nBase
);
1100 double fPrice2
= getPrice_( nNullDate
, nSettle
, nMat
, fRate
, fYield2
, fRedemp
, nFreq
, nBase
);
1101 double fYieldN
= ( fYield2
- fYield1
) * 0.5;
1103 for( sal_uInt32 nIter
= 0 ; nIter
< 100 && !rtl::math::approxEqual(fPriceN
, fPrice
) ; nIter
++ )
1105 fPriceN
= getPrice_( nNullDate
, nSettle
, nMat
, fRate
, fYieldN
, fRedemp
, nFreq
, nBase
);
1107 if( rtl::math::approxEqual(fPrice
, fPrice1
) )
1109 else if( rtl::math::approxEqual(fPrice
, fPrice2
) )
1111 else if( rtl::math::approxEqual(fPrice
, fPriceN
) )
1113 else if( fPrice
< fPrice2
)
1116 fPrice2
= getPrice_( nNullDate
, nSettle
, nMat
, fRate
, fYield2
, fRedemp
, nFreq
, nBase
);
1118 fYieldN
= ( fYield2
- fYield1
) * 0.5;
1122 if( fPrice
< fPriceN
)
1133 fYieldN
= fYield2
- ( fYield2
- fYield1
) * ( ( fPrice
- fPrice2
) / ( fPrice1
- fPrice2
) );
1137 if( fabs( fPrice
- fPriceN
) > fPrice
/ 100.0 )
1138 throw lang::IllegalArgumentException(); // result not precise enough
1144 double getPrice_( sal_Int32 nNullDate
, sal_Int32 nSettle
, sal_Int32 nMat
, double fRate
, double fYield
,
1145 double fRedemp
, sal_Int32 nFreq
, sal_Int32 nBase
)
1147 double fFreq
= nFreq
;
1149 double fE
= GetCoupdays( nNullDate
, nSettle
, nMat
, nFreq
, nBase
);
1150 double fDSC_E
= GetCoupdaysnc( nNullDate
, nSettle
, nMat
, nFreq
, nBase
) / fE
;
1151 double fN
= GetCoupnum( nNullDate
, nSettle
, nMat
, nFreq
, nBase
);
1152 double fA
= GetCoupdaybs( nNullDate
, nSettle
, nMat
, nFreq
, nBase
);
1154 double fRet
= fRedemp
/ ( pow( 1.0 + fYield
/ fFreq
, fN
- 1.0 + fDSC_E
) );
1155 fRet
-= 100.0 * fRate
/ fFreq
* fA
/ fE
;
1157 double fT1
= 100.0 * fRate
/ fFreq
;
1158 double fT2
= 1.0 + fYield
/ fFreq
;
1160 for( double fK
= 0.0 ; fK
< fN
; fK
++ )
1161 fRet
+= fT1
/ pow( fT2
, fK
+ fDSC_E
);
1167 double GetOddfyield( sal_Int32
/*nNullDate*/, sal_Int32
/*nSettle*/, sal_Int32
/*nMat*/, sal_Int32
/*nIssue*/,
1168 sal_Int32
/*nFirstCoup*/, double /*fRate*/, double /*fPrice*/, double /*fRedemp*/, sal_Int32
/*nFreq*/,
1169 sal_Int32
/*nBase*/ )
1171 // If you change this to not unconditionally throw, the
1172 // SAL_WNOUNREACHABLE_CODE_PUSH/POP around the caller in
1173 // financial.cxx can be removed.
1174 throw uno::RuntimeException();
1178 double GetOddlprice( sal_Int32 nNullDate
, sal_Int32 nSettle
, sal_Int32 nMat
, sal_Int32 nLastCoup
,
1179 double fRate
, double fYield
, double fRedemp
, sal_Int32 nFreq
, sal_Int32 nBase
)
1181 double fFreq
= double( nFreq
);
1182 double fDCi
= GetYearFrac( nNullDate
, nLastCoup
, nMat
, nBase
) * fFreq
;
1183 double fDSCi
= GetYearFrac( nNullDate
, nSettle
, nMat
, nBase
) * fFreq
;
1184 double fAi
= GetYearFrac( nNullDate
, nLastCoup
, nSettle
, nBase
) * fFreq
;
1186 double p
= fRedemp
+ fDCi
* 100.0 * fRate
/ fFreq
;
1187 p
/= fDSCi
* fYield
/ fFreq
+ 1.0;
1188 p
-= fAi
* 100.0 * fRate
/ fFreq
;
1194 double GetOddlyield( sal_Int32 nNullDate
, sal_Int32 nSettle
, sal_Int32 nMat
, sal_Int32 nLastCoup
,
1195 double fRate
, double fPrice
, double fRedemp
, sal_Int32 nFreq
, sal_Int32 nBase
)
1197 double fFreq
= double( nFreq
);
1198 double fDCi
= GetYearFrac( nNullDate
, nLastCoup
, nMat
, nBase
) * fFreq
;
1199 double fDSCi
= GetYearFrac( nNullDate
, nSettle
, nMat
, nBase
) * fFreq
;
1200 double fAi
= GetYearFrac( nNullDate
, nLastCoup
, nSettle
, nBase
) * fFreq
;
1202 double y
= fRedemp
+ fDCi
* 100.0 * fRate
/ fFreq
;
1203 y
/= fPrice
+ fAi
* 100.0 * fRate
/ fFreq
;
1211 double GetPmt( double fRate
, double fNper
, double fPv
, double fFv
, sal_Int32 nPayType
)
1215 fPmt
= ( fPv
+ fFv
) / fNper
;
1218 double fTerm
= pow( 1.0 + fRate
, fNper
);
1220 fPmt
= ( fFv
* fRate
/ ( fTerm
- 1.0 ) + fPv
* fRate
/ ( 1.0 - 1.0 / fTerm
) ) / ( 1.0 + fRate
);
1222 fPmt
= fFv
* fRate
/ ( fTerm
- 1.0 ) + fPv
* fRate
/ ( 1.0 - 1.0 / fTerm
);
1229 double GetFv( double fRate
, double fNper
, double fPmt
, double fPv
, sal_Int32 nPayType
)
1233 fFv
= fPv
+ fPmt
* fNper
;
1236 double fTerm
= pow( 1.0 + fRate
, fNper
);
1238 fFv
= fPv
* fTerm
+ fPmt
* ( 1.0 + fRate
) * ( fTerm
- 1.0 ) / fRate
;
1240 fFv
= fPv
* fTerm
+ fPmt
* ( fTerm
- 1.0 ) / fRate
;
1246 // financial functions COUP***
1248 // COUPPCD: find last coupon date before settlement (can be equal to settlement)
1249 /// @throws css::lang::IllegalArgumentException
1250 static void lcl_GetCouppcd( ScaDate
& rDate
, const ScaDate
& rSettle
, const ScaDate
& rMat
, sal_Int32 nFreq
)
1253 rDate
.setYear( rSettle
.getYear() );
1254 if( rDate
< rSettle
)
1255 rDate
.addYears( 1 );
1256 while( rDate
> rSettle
)
1257 rDate
.addMonths( -12 / nFreq
);
1260 double GetCouppcd( sal_Int32 nNullDate
, sal_Int32 nSettle
, sal_Int32 nMat
, sal_Int32 nFreq
, sal_Int32 nBase
)
1262 if( nSettle
>= nMat
|| CHK_Freq
)
1263 throw lang::IllegalArgumentException();
1266 lcl_GetCouppcd( aDate
, ScaDate( nNullDate
, nSettle
, nBase
), ScaDate( nNullDate
, nMat
, nBase
), nFreq
);
1267 return aDate
.getDate( nNullDate
);
1270 // COUPNCD: find first coupon date after settlement (is never equal to settlement)
1271 /// @throws css::lang::IllegalArgumentException
1272 static void lcl_GetCoupncd( ScaDate
& rDate
, const ScaDate
& rSettle
, const ScaDate
& rMat
, sal_Int32 nFreq
)
1275 rDate
.setYear( rSettle
.getYear() );
1276 if( rDate
> rSettle
)
1277 rDate
.addYears( -1 );
1278 while( rDate
<= rSettle
)
1279 rDate
.addMonths( 12 / nFreq
);
1282 double GetCoupncd( sal_Int32 nNullDate
, sal_Int32 nSettle
, sal_Int32 nMat
, sal_Int32 nFreq
, sal_Int32 nBase
)
1284 if( nSettle
>= nMat
|| CHK_Freq
)
1285 throw lang::IllegalArgumentException();
1288 lcl_GetCoupncd( aDate
, ScaDate( nNullDate
, nSettle
, nBase
), ScaDate( nNullDate
, nMat
, nBase
), nFreq
);
1289 return aDate
.getDate( nNullDate
);
1292 // COUPDAYBS: get day count: coupon date before settlement <-> settlement
1293 double GetCoupdaybs( sal_Int32 nNullDate
, sal_Int32 nSettle
, sal_Int32 nMat
, sal_Int32 nFreq
, sal_Int32 nBase
)
1295 if( nSettle
>= nMat
|| CHK_Freq
)
1296 throw lang::IllegalArgumentException();
1298 ScaDate
aSettle( nNullDate
, nSettle
, nBase
);
1300 lcl_GetCouppcd( aDate
, aSettle
, ScaDate( nNullDate
, nMat
, nBase
), nFreq
);
1301 return ScaDate::getDiff( aDate
, aSettle
);
1304 // COUPDAYSNC: get day count: settlement <-> coupon date after settlement
1305 double GetCoupdaysnc( sal_Int32 nNullDate
, sal_Int32 nSettle
, sal_Int32 nMat
, sal_Int32 nFreq
, sal_Int32 nBase
)
1307 if( nSettle
>= nMat
|| CHK_Freq
)
1308 throw lang::IllegalArgumentException();
1310 if( (nBase
!= 0) && (nBase
!= 4) )
1312 ScaDate
aSettle( nNullDate
, nSettle
, nBase
);
1314 lcl_GetCoupncd( aDate
, aSettle
, ScaDate( nNullDate
, nMat
, nBase
), nFreq
);
1315 return ScaDate::getDiff( aSettle
, aDate
);
1317 return GetCoupdays( nNullDate
, nSettle
, nMat
, nFreq
, nBase
) - GetCoupdaybs( nNullDate
, nSettle
, nMat
, nFreq
, nBase
);
1320 // COUPDAYS: get day count: coupon date before settlement <-> coupon date after settlement
1321 double GetCoupdays( sal_Int32 nNullDate
, sal_Int32 nSettle
, sal_Int32 nMat
, sal_Int32 nFreq
, sal_Int32 nBase
)
1323 if( nSettle
>= nMat
|| CHK_Freq
)
1324 throw lang::IllegalArgumentException();
1329 lcl_GetCouppcd( aDate
, ScaDate( nNullDate
, nSettle
, nBase
), ScaDate( nNullDate
, nMat
, nBase
), nFreq
);
1330 ScaDate
aNextDate( aDate
);
1331 aNextDate
.addMonths( 12 / nFreq
);
1332 return ScaDate::getDiff( aDate
, aNextDate
);
1334 return static_cast< double >( GetDaysInYear( 0, 0, nBase
) ) / nFreq
;
1337 // COUPNUM: get count of coupon dates
1338 double GetCoupnum( sal_Int32 nNullDate
, sal_Int32 nSettle
, sal_Int32 nMat
, sal_Int32 nFreq
, sal_Int32 nBase
)
1340 if( nSettle
>= nMat
|| CHK_Freq
)
1341 throw lang::IllegalArgumentException();
1343 ScaDate
aMat( nNullDate
, nMat
, nBase
);
1345 lcl_GetCouppcd( aDate
, ScaDate( nNullDate
, nSettle
, nBase
), aMat
, nFreq
);
1346 sal_uInt16 nMonths
= (aMat
.getYear() - aDate
.getYear()) * 12 + aMat
.getMonth() - aDate
.getMonth();
1347 return static_cast< double >( nMonths
* nFreq
/ 12 );
1350 FuncData::FuncData(const FuncDataBase
& r
) :
1351 aIntName( OUString::createFromAscii( r
.pIntName
) ),
1352 pUINameID( r
.pUINameID
),
1353 pDescrID( r
.pDescrID
),
1354 bDouble( r
.bDouble
),
1355 bWithOpt( r
.bWithOpt
),
1356 nParam( r
.nNumOfParams
),
1360 aSuffix
= OUString::createFromAscii(r
.pSuffix
);
1362 aCompList
.resize(2);
1363 aCompList
[0] = OUString(r
.pCompListID
[0], strlen(r
.pCompListID
[0]), RTL_TEXTENCODING_UTF8
);
1364 aCompList
[1] = OUString(r
.pCompListID
[1], strlen(r
.pCompListID
[1]), RTL_TEXTENCODING_UTF8
);
1367 FuncData::~FuncData()
1371 sal_uInt16
FuncData::GetStrIndex( sal_uInt16 nParamNum
) const
1376 if( nParamNum
> nParam
)
1379 return nParamNum
* 2;
1382 void InitFuncDataList(FuncDataList
& rList
)
1384 for(const auto & rFuncData
: pFuncDatas
)
1385 rList
.push_back(FuncData(rFuncData
));
1388 SortedIndividualInt32List::SortedIndividualInt32List()
1393 SortedIndividualInt32List::~SortedIndividualInt32List()
1398 void SortedIndividualInt32List::Insert( sal_Int32 nDay
)
1400 sal_uInt32 nIndex
= Count();
1404 sal_Int32 nRef
= Get( nIndex
);
1407 else if( nDay
> nRef
)
1409 maVector
.insert( maVector
.begin() + nIndex
+ 1, nDay
);
1413 maVector
.insert( maVector
.begin(), nDay
);
1417 void SortedIndividualInt32List::Insert( sal_Int32 nDay
, sal_Int32 nNullDate
, bool bInsertOnWeekend
)
1423 if( bInsertOnWeekend
|| (GetDayOfWeek( nDay
) < 5) )
1428 void SortedIndividualInt32List::Insert(
1429 double fDay
, sal_Int32 nNullDate
, bool bInsertOnWeekend
)
1431 if( (fDay
< -2147483648.0) || (fDay
> 2147483649.0) )
1432 throw lang::IllegalArgumentException();
1433 Insert( static_cast< sal_Int32
>( fDay
), nNullDate
, bInsertOnWeekend
);
1437 bool SortedIndividualInt32List::Find( sal_Int32 nVal
) const
1439 sal_uInt32 nE
= Count();
1441 if( !nE
|| nVal
< Get( 0 ) || nVal
> Get( nE
- 1 ) )
1446 for( sal_uInt32 n
= 0 ; n
< nE
; n
++ )
1448 sal_Int32 nRef
= Get( n
);
1452 else if( nRef
> nVal
)
1459 void SortedIndividualInt32List::InsertHolidayList(
1460 const ScaAnyConverter
& rAnyConv
,
1461 const uno::Any
& rHolAny
,
1462 sal_Int32 nNullDate
,
1463 bool bInsertOnWeekend
)
1466 if( rAnyConv
.getDouble( fDay
, rHolAny
) )
1467 Insert( fDay
, nNullDate
, bInsertOnWeekend
);
1471 void SortedIndividualInt32List::InsertHolidayList(
1472 ScaAnyConverter
& rAnyConv
,
1473 const uno::Reference
< beans::XPropertySet
>& xOptions
,
1474 const uno::Any
& rHolAny
,
1475 sal_Int32 nNullDate
)
1477 rAnyConv
.init( xOptions
);
1478 if( rHolAny
.getValueTypeClass() == uno::TypeClass_SEQUENCE
)
1480 uno::Sequence
< uno::Sequence
< uno::Any
> > aAnySeq
;
1481 if( !(rHolAny
>>= aAnySeq
) )
1482 throw lang::IllegalArgumentException();
1484 const uno::Sequence
< uno::Any
>* pSeqArray
= aAnySeq
.getConstArray();
1485 for( sal_Int32 nIndex1
= 0; nIndex1
< aAnySeq
.getLength(); nIndex1
++ )
1487 const uno::Sequence
< uno::Any
>& rSubSeq
= pSeqArray
[ nIndex1
];
1488 const uno::Any
* pAnyArray
= rSubSeq
.getConstArray();
1490 for( sal_Int32 nIndex2
= 0; nIndex2
< rSubSeq
.getLength(); nIndex2
++ )
1491 InsertHolidayList( rAnyConv
, pAnyArray
[ nIndex2
], nNullDate
, false/*bInsertOnWeekend*/ );
1495 InsertHolidayList( rAnyConv
, rHolAny
, nNullDate
, false/*bInsertOnWeekend*/ );
1499 void ScaDoubleList::Append(
1500 const uno::Sequence
< uno::Sequence
< double > >& rValueSeq
)
1502 const uno::Sequence
< double >* pSeqArray
= rValueSeq
.getConstArray();
1503 for( sal_Int32 nIndex1
= 0; nIndex1
< rValueSeq
.getLength(); nIndex1
++ )
1505 const uno::Sequence
< double >& rSubSeq
= pSeqArray
[ nIndex1
];
1506 const double* pArray
= rSubSeq
.getConstArray();
1507 for( sal_Int32 nIndex2
= 0; nIndex2
< rSubSeq
.getLength(); nIndex2
++ )
1508 Append( pArray
[ nIndex2
] );
1513 void ScaDoubleList::Append(
1514 const uno::Sequence
< uno::Sequence
< sal_Int32
> >& rValueSeq
)
1516 const uno::Sequence
< sal_Int32
>* pSeqArray
= rValueSeq
.getConstArray();
1517 for( sal_Int32 nIndex1
= 0; nIndex1
< rValueSeq
.getLength(); nIndex1
++ )
1519 const uno::Sequence
< sal_Int32
>& rSubSeq
= pSeqArray
[ nIndex1
];
1520 const sal_Int32
* pArray
= rSubSeq
.getConstArray();
1521 for( sal_Int32 nIndex2
= 0; nIndex2
< rSubSeq
.getLength(); nIndex2
++ )
1522 Append( pArray
[ nIndex2
] );
1526 void ScaDoubleList::Append(
1527 const ScaAnyConverter
& rAnyConv
,
1528 const uno::Any
& rAny
,
1531 if( auto s
= o3tl::tryAccess
<
1532 css::uno::Sequence
<css::uno::Sequence
<css::uno::Any
>>>(rAny
) )
1533 Append( rAnyConv
, *s
, bIgnoreEmpty
);
1537 if( rAnyConv
.getDouble( fValue
, rAny
) )
1539 else if( !bIgnoreEmpty
)
1545 void ScaDoubleList::Append(
1546 const ScaAnyConverter
& rAnyConv
,
1547 const uno::Sequence
< uno::Any
>& rAnySeq
,
1550 const uno::Any
* pArray
= rAnySeq
.getConstArray();
1551 for( sal_Int32 nIndex
= 0; nIndex
< rAnySeq
.getLength(); nIndex
++ )
1552 Append( rAnyConv
, pArray
[ nIndex
], bIgnoreEmpty
);
1556 void ScaDoubleList::Append(
1557 const ScaAnyConverter
& rAnyConv
,
1558 const uno::Sequence
< uno::Sequence
< uno::Any
> >& rAnySeq
,
1561 const uno::Sequence
< uno::Any
>* pArray
= rAnySeq
.getConstArray();
1562 for( sal_Int32 nIndex
= 0; nIndex
< rAnySeq
.getLength(); nIndex
++ )
1563 Append( rAnyConv
, pArray
[ nIndex
], bIgnoreEmpty
);
1566 void ScaDoubleList::Append(
1567 ScaAnyConverter
& rAnyConv
,
1568 const uno::Reference
< beans::XPropertySet
>& xOpt
,
1569 const uno::Sequence
< uno::Any
>& rAnySeq
)
1571 rAnyConv
.init( xOpt
);
1572 Append( rAnyConv
, rAnySeq
, true/*bIgnoreEmpty*/ );
1576 bool ScaDoubleList::CheckInsert( double ) const
1582 bool ScaDoubleListGT0::CheckInsert( double fValue
) const
1585 throw lang::IllegalArgumentException();
1586 return fValue
> 0.0;
1590 bool ScaDoubleListGE0::CheckInsert( double fValue
) const
1593 throw lang::IllegalArgumentException();
1598 Complex::Complex( const OUString
& rStr
)
1600 if( !ParseString( rStr
, *this ) )
1601 throw lang::IllegalArgumentException();
1605 inline bool Complex::IsImagUnit( sal_Unicode c
)
1607 return c
== 'i' || c
== 'j';
1610 bool Complex::ParseString( const OUString
& rStr
, Complex
& rCompl
)
1612 rCompl
.c
= '\0'; // do not force a symbol, if only real part present
1614 const sal_Unicode
* pStr
= rStr
.getStr();
1616 if( IsImagUnit( *pStr
) && rStr
.getLength() == 1)
1626 if( !ParseDouble( pStr
, f
) )
1631 case '-': // imag part follows
1635 if( IsImagUnit( pStr
[ 1 ] ) )
1637 rCompl
.c
= pStr
[ 1 ];
1638 if( pStr
[ 2 ] == 0 )
1641 rCompl
.i
= ( *pStr
== '+' )? 1.0 : -1.0;
1645 else if( ParseDouble( pStr
, f
) && IsImagUnit( *pStr
) )
1669 case 0: // only real-part
1679 OUString
Complex::GetString() const
1683 OUStringBuffer aRet
;
1685 bool bHasImag
= i
!= 0.0;
1686 bool bHasReal
= !bHasImag
|| (r
!= 0.0);
1689 aRet
.append(::GetString( r
, false ));
1697 else if( i
== -1.0 )
1700 aRet
.append(::GetString( i
, bHasReal
));
1701 aRet
.append((c
!= 'j') ? 'i' : 'j');
1704 return aRet
.makeStringAndClear();
1708 double Complex::Arg() const
1710 if( r
== 0.0 && i
== 0.0 )
1711 throw lang::IllegalArgumentException();
1713 double phi
= acos( r
/ Abs() );
1722 void Complex::Power( double fPower
)
1724 if( r
== 0.0 && i
== 0.0 )
1727 throw lang::IllegalArgumentException();
1736 phi
= acos( r
/ p
);
1740 p
= pow( p
, fPower
);
1748 void Complex::Sqrt()
1750 static const double fMultConst
= 0.7071067811865475; // ...2440084436210485 = 1/sqrt(2)
1752 double i_
= sqrt( p
- r
) * fMultConst
;
1754 r
= sqrt( p
+ r
) * fMultConst
;
1755 i
= ( i
< 0.0 )? -i_
: i_
;
1761 if( !::rtl::math::isValidArcArg( r
) )
1762 throw lang::IllegalArgumentException();
1768 r_
= sin( r
) * cosh( i
);
1769 i
= cos( r
) * sinh( i
);
1779 if( !::rtl::math::isValidArcArg( r
) )
1780 throw lang::IllegalArgumentException();
1786 r_
= cos( r
) * cosh( i
);
1787 i
= -( sin( r
) * sinh( i
) );
1795 void Complex::Div( const Complex
& z
)
1797 if( z
.r
== 0 && z
.i
== 0 )
1798 throw lang::IllegalArgumentException();
1805 double f
= 1.0 / ( a2
* a2
+ b2
* b2
);
1807 r
= ( a1
* a2
+ b1
* b2
) * f
;
1808 i
= ( a2
* b1
- a1
* b2
) * f
;
1816 double fE
= exp( r
);
1824 if( r
== 0.0 && i
== 0.0 )
1825 throw lang::IllegalArgumentException();
1827 double fAbs
= Abs();
1828 bool bNegi
= i
< 0.0;
1830 i
= acos( r
/ fAbs
);
1839 void Complex::Log10()
1842 Mult( 0.434294481903251828 ); // * log10( e )
1846 void Complex::Log2()
1849 Mult( 1.442695040888963407 ); // * log2( e )
1857 if( !::rtl::math::isValidArcArg( 2.0 * r
) )
1858 throw lang::IllegalArgumentException();
1859 double fScale
=1.0 / ( cos( 2.0 * r
) + cosh( 2.0 * i
));
1860 r
= sin( 2.0 * r
) * fScale
;
1861 i
= sinh( 2.0 * i
) * fScale
;
1865 if( !::rtl::math::isValidArcArg( r
) )
1866 throw lang::IllegalArgumentException();
1876 if( !::rtl::math::isValidArcArg( 2 * r
) )
1877 throw lang::IllegalArgumentException();
1878 double fScale
= 1.0 / (cosh( 2.0 * i
) + cos ( 2.0 * r
));
1880 r_
= 2.0 * cos( r
) * cosh( i
) * fScale
;
1881 i
= 2.0 * sin( r
) * sinh( i
) * fScale
;
1886 if( !::rtl::math::isValidArcArg( r
) )
1887 throw lang::IllegalArgumentException();
1897 if( !::rtl::math::isValidArcArg( 2 * r
) )
1898 throw lang::IllegalArgumentException();
1899 double fScale
= 1.0 / (cosh( 2.0 * i
) - cos ( 2.0 * r
));
1901 r_
= 2.0 * sin( r
) * cosh( i
) * fScale
;
1902 i
= -2.0 * cos( r
) * sinh( i
) * fScale
;
1907 if( !::rtl::math::isValidArcArg( r
) )
1908 throw lang::IllegalArgumentException();
1918 if( !::rtl::math::isValidArcArg( 2.0 * r
) )
1919 throw lang::IllegalArgumentException();
1920 double fScale
=1.0 / ( cosh( 2.0 * i
) - cos( 2.0 * r
) );
1921 r
= sin( 2.0 * r
) * fScale
;
1922 i
= - ( sinh( 2.0 * i
) * fScale
);
1926 if( !::rtl::math::isValidArcArg( r
) )
1927 throw lang::IllegalArgumentException();
1933 void Complex::Sinh()
1935 if( !::rtl::math::isValidArcArg( r
) )
1936 throw lang::IllegalArgumentException();
1941 r_
= sinh( r
) * cos( i
);
1942 i
= cosh( r
) * sin( i
);
1950 void Complex::Cosh()
1952 if( !::rtl::math::isValidArcArg( r
) )
1953 throw lang::IllegalArgumentException();
1958 r_
= cosh( r
) * cos( i
);
1959 i
= sinh( r
) * sin( i
);
1967 void Complex::Sech()
1971 if( !::rtl::math::isValidArcArg( 2.0 * r
) )
1972 throw lang::IllegalArgumentException();
1973 double fScale
=1.0 / ( cosh( 2.0 * r
) + cos( 2.0 * i
));
1975 r_
= 2.0 * cosh( r
) * cos( i
) * fScale
;
1976 i
= - (2.0 * sinh( r
) * sin( i
) * fScale
);
1981 if( !::rtl::math::isValidArcArg( r
) )
1982 throw lang::IllegalArgumentException();
1983 r
= 1.0 / cosh( r
);
1988 void Complex::Csch()
1992 if( !::rtl::math::isValidArcArg( 2.0 * r
) )
1993 throw lang::IllegalArgumentException();
1994 double fScale
=1.0 / ( cosh( 2.0 * r
) - cos( 2.0 * i
));
1996 r_
= 2.0 * sinh( r
) * cos( i
) * fScale
;
1997 i
= - ( 2.0 * cosh( r
) * sin( i
) * fScale
);
2002 if( !::rtl::math::isValidArcArg( r
) )
2003 throw lang::IllegalArgumentException();
2004 r
= 1.0 / sinh( r
);
2009 ComplexList::~ComplexList()
2014 void ComplexList::Append( const uno::Sequence
< uno::Sequence
< OUString
> >& r
)
2017 sal_Int32 nE1
= r
.getLength();
2020 for( n1
= 0 ; n1
< nE1
; n1
++ )
2022 const uno::Sequence
< OUString
>& rList
= r
[ n1
];
2023 nE2
= rList
.getLength();
2025 for( n2
= 0 ; n2
< nE2
; n2
++ )
2027 const OUString
& rStr
= rList
[ n2
];
2029 if( !rStr
.isEmpty() )
2030 Append( Complex( rStr
) );
2036 void ComplexList::Append( const uno::Sequence
< uno::Any
>& aMultPars
)
2038 sal_Int32 nEle
= aMultPars
.getLength();
2040 for( sal_Int32 i
= 0 ; i
< nEle
; i
++ )
2042 const uno::Any
& r
= aMultPars
[ i
];
2043 switch( r
.getValueTypeClass() )
2045 case uno::TypeClass_VOID
: break;
2046 case uno::TypeClass_STRING
:
2048 auto pStr
= o3tl::forceAccess
<OUString
>(r
);
2050 if( !pStr
->isEmpty() )
2051 Append( Complex( *pStr
) );
2054 case uno::TypeClass_DOUBLE
:
2055 Append( Complex( *o3tl::forceAccess
<double>(r
), 0.0 ) );
2057 case uno::TypeClass_SEQUENCE
:
2059 uno::Sequence
< uno::Sequence
< uno::Any
> > aValArr
;
2060 if( !(r
>>= aValArr
) )
2061 throw lang::IllegalArgumentException();
2063 sal_Int32 nE
= aValArr
.getLength();
2064 const uno::Sequence
< uno::Any
>* pArr
= aValArr
.getConstArray();
2065 for( sal_Int32 n
= 0 ; n
< nE
; n
++ )
2066 Append( pArr
[ n
] );
2070 throw lang::IllegalArgumentException();
2075 ConvertData::ConvertData(const sal_Char p
[], double fC
, ConvertDataClass e
, bool bPrefSupport
)
2077 , aName(p
, strlen(p
), RTL_TEXTENCODING_MS_1252
)
2079 , bPrefixSupport(bPrefSupport
)
2083 ConvertData::~ConvertData()
2087 sal_Int16
ConvertData::GetMatchingLevel( const OUString
& rRef
) const
2089 OUString aStr
= rRef
;
2090 sal_Int32 nLen
= rRef
.getLength();
2091 sal_Int32 nIndex
= rRef
.lastIndexOf( '^' );
2092 if( nIndex
> 0 && nIndex
== ( nLen
- 2 ) )
2093 aStr
= aStr
.copy( 0, nLen
- 2 ) + OUStringLiteral1( aStr
[ nLen
- 1 ] );
2098 const sal_Unicode
* p
= aStr
.getStr();
2100 nLen
= aStr
.getLength();
2101 bool bPref
= bPrefixSupport
;
2102 bool bOneChar
= (bPref
&& nLen
> 1 && (aName
== p
+ 1));
2103 if (bOneChar
|| (bPref
&& nLen
> 2 && (aName
== p
+ 2) &&
2104 *p
== 'd' && *(p
+1) == 'a'))
2109 case 'y': n
= -24; break; // yocto
2110 case 'z': n
= -21; break; // zepto
2111 case 'a': n
= -18; break;
2112 case 'f': n
= -15; break;
2113 case 'p': n
= -12; break;
2114 case 'n': n
= -9; break;
2115 case 'u': n
= -6; break;
2116 case 'm': n
= -3; break;
2117 case 'c': n
= -2; break;
2126 case 'e': n
= 1; break;
2127 case 'h': n
= 2; break;
2128 case 'k': n
= 3; break;
2129 case 'M': n
= 6; break;
2130 case 'G': n
= 9; break;
2131 case 'T': n
= 12; break;
2132 case 'P': n
= 15; break;
2133 case 'E': n
= 18; break;
2134 case 'Z': n
= 21; break; // zetta
2135 case 'Y': n
= 24; break; // yotta
2140 // We could weed some nonsense out, ODFF doesn't say so though.
2142 if (n
< 0 && Class() == CDC_Information
)
2143 n
= INV_MATCHLEV
; // milli-bits doesn't make sense
2146 //! <HACK> "cm3" is not 10^-2 m^3 but 10^-6 m^3 !!! ------------------
2147 if( n
!= INV_MATCHLEV
)
2149 sal_Unicode cLast
= p
[ aStr
.getLength() - 1 ];
2152 else if( cLast
== '3' )
2155 //! </HACK> -------------------------------------------------------------------
2159 else if ( nLen
> 2 && ( aName
== p
+ 2 ) && ( Class() == CDC_Information
) )
2161 const sal_Unicode
* pStr
= aStr
.getStr();
2162 if ( *(pStr
+ 1) != 'i')
2163 return INV_MATCHLEV
;
2167 case 'k': n
= 10; break;
2168 case 'M': n
= 20; break;
2169 case 'G': n
= 30; break;
2170 case 'T': n
= 40; break;
2171 case 'P': n
= 50; break;
2172 case 'E': n
= 60; break;
2173 case 'Z': n
= 70; break;
2174 case 'Y': n
= 80; break;
2181 return INV_MATCHLEV
;
2186 double ConvertData::Convert(
2187 double f
, const ConvertData
& r
, sal_Int16 nLevFrom
, sal_Int16 nLevTo
) const
2189 if( Class() != r
.Class() )
2190 throw lang::IllegalArgumentException();
2192 bool bBinFromLev
= ( nLevFrom
> 0 && ( nLevFrom
% 10 ) == 0 );
2193 bool bBinToLev
= ( nLevTo
> 0 && ( nLevTo
% 10 ) == 0 );
2195 if ( Class() == CDC_Information
&& ( bBinFromLev
|| bBinToLev
) )
2197 if ( bBinFromLev
&& bBinToLev
)
2199 nLevFrom
= sal::static_int_cast
<sal_Int16
>( nLevFrom
- nLevTo
);
2200 f
*= r
.fConst
/ fConst
;
2202 f
*= pow( 2.0, nLevFrom
);
2204 else if ( bBinFromLev
)
2205 f
*= ( r
.fConst
/ fConst
) * ( pow( 2.0, nLevFrom
) / pow( 10.0, nLevTo
) );
2207 f
*= ( r
.fConst
/ fConst
) * ( pow( 10.0, nLevFrom
) / pow( 2.0, nLevTo
) );
2211 nLevFrom
= sal::static_int_cast
<sal_Int16
>( nLevFrom
- nLevTo
); // effective level
2213 f
*= r
.fConst
/ fConst
;
2216 f
= ::rtl::math::pow10Exp( f
, nLevFrom
);
2222 double ConvertData::ConvertFromBase( double f
, sal_Int16 n
) const
2224 return ::rtl::math::pow10Exp( f
* fConst
, -n
);
2227 ConvertDataLinear::~ConvertDataLinear()
2231 double ConvertDataLinear::Convert(
2232 double f
, const ConvertData
& r
, sal_Int16 nLevFrom
, sal_Int16 nLevTo
) const
2234 if( Class() != r
.Class() )
2235 throw lang::IllegalArgumentException();
2236 return r
.ConvertFromBase( ConvertToBase( f
, nLevFrom
), nLevTo
);
2240 double ConvertDataLinear::ConvertToBase( double f
, sal_Int16 n
) const
2243 f
= ::rtl::math::pow10Exp( f
, n
);
2252 double ConvertDataLinear::ConvertFromBase( double f
, sal_Int16 n
) const
2258 f
= ::rtl::math::pow10Exp( f
, -n
);
2264 ConvertDataList::ConvertDataList()
2266 #define NEWD(str,unit,cl) maVector.emplace_back(new ConvertData(str,unit,cl))
2267 #define NEWDP(str,unit,cl) maVector.emplace_back(new ConvertData(str,unit,cl,true))
2268 #define NEWL(str,unit,offs,cl) maVector.emplace_back(new ConvertDataLinear(str,unit,offs,cl))
2269 #define NEWLP(str,unit,offs,cl) maVector.emplace_back(new ConvertDataLinear(str,unit,offs,cl,true))
2271 // *** are extra and not standard Excel Analysis Addin!
2273 // MASS: 1 Gram is...
2274 NEWDP( "g", 1.0000000000000000E00
, CDC_Mass
); // Gram
2275 NEWD( "sg", 6.8522050005347800E-05, CDC_Mass
); // Pieces
2276 NEWD( "lbm", 2.2046229146913400E-03, CDC_Mass
); // Pound (commercial weight)
2277 NEWDP( "u", 6.0221370000000000E23
, CDC_Mass
); // U (atomic mass)
2278 NEWD( "ozm", 3.5273971800362700E-02, CDC_Mass
); // Ounce (commercial weight)
2279 NEWD( "stone", 1.574730e-04, CDC_Mass
); // *** Stone
2280 NEWD( "ton", 1.102311e-06, CDC_Mass
); // *** Ton
2281 NEWD( "grain", 1.543236E01
, CDC_Mass
); // *** Grain
2282 NEWD( "pweight", 7.054792E-01, CDC_Mass
); // *** Pennyweight
2283 NEWD( "hweight", 1.968413E-05, CDC_Mass
); // *** Hundredweight
2284 NEWD( "shweight", 2.204623E-05, CDC_Mass
); // *** Shorthundredweight
2285 NEWD( "brton", 9.842065E-07, CDC_Mass
); // *** Gross Registered Ton
2286 NEWD( "cwt", 2.2046226218487758E-05, CDC_Mass
); // U.S. (short) hundredweight
2287 NEWD( "shweight", 2.2046226218487758E-05, CDC_Mass
); // U.S. (short) hundredweight also
2288 NEWD( "uk_cwt", 1.9684130552221213E-05, CDC_Mass
); // Imperial hundredweight
2289 NEWD( "lcwt", 1.9684130552221213E-05, CDC_Mass
); // Imperial hundredweight also
2290 NEWD( "hweight", 1.9684130552221213E-05, CDC_Mass
); // Imperial hundredweight also
2291 NEWD( "uk_ton", 9.8420652761106063E-07, CDC_Mass
); // Imperial ton
2292 NEWD( "LTON", 9.8420652761106063E-07, CDC_Mass
); // Imperial ton also
2294 // LENGTH: 1 Meter is...
2295 NEWDP( "m", 1.0000000000000000E00
, CDC_Length
); // Meter
2296 NEWD( "mi", 6.2137119223733397E-04, CDC_Length
); // Britsh Mile 6,21371192237333969617434184363e-4
2297 NEWD( "Nmi", 5.3995680345572354E-04, CDC_Length
); // Nautical Mile 5,39956803455723542116630669546e-4
2298 NEWD( "in", 3.9370078740157480E01
, CDC_Length
); // Inch 39,37007874015748031496062992126
2299 NEWD( "ft", 3.2808398950131234E00
, CDC_Length
); // Foot 3,2808398950131233595800524934383
2300 NEWD( "yd", 1.0936132983377078E00
, CDC_Length
); // Yard 1,0936132983377077865266841644794
2301 NEWDP( "ang", 1.0000000000000000E10
, CDC_Length
); // Angstroem
2302 NEWD( "Pica", 2.8346456692913386E03
, CDC_Length
); // Pica Point (1/72 Inch) 2834,6456692913385826771653543307
2303 NEWD( "picapt", 2.8346456692913386E03
, CDC_Length
); // Pica Point (1/72 Inch) 2834,6456692913385826771653543307
2304 NEWD( "pica", 2.36220472441E02
, CDC_Length
); // pica (1/6 Inch)
2305 NEWD( "ell", 8.748906E-01, CDC_Length
); // *** Ell
2306 NEWDP( "parsec", 3.240779E-17, CDC_Length
); // *** Parsec
2307 NEWDP( "pc", 3.240779E-17, CDC_Length
); // *** Parsec also
2308 NEWDP( "lightyear", 1.0570234557732930E-16, CDC_Length
); // *** Light Year
2309 NEWDP( "ly", 1.0570234557732930E-16, CDC_Length
); // *** Light Year also
2310 NEWD( "survey_mi", 6.2136994949494949E-04, CDC_Length
); // U.S. survey mile
2312 // TIME: 1 Second is...
2313 NEWD( "yr", 3.1688087814028950E-08, CDC_Time
); // Year
2314 NEWD( "day", 1.1574074074074074E-05, CDC_Time
); // Day
2315 NEWD( "d", 1.1574074074074074E-05, CDC_Time
); // Day also
2316 NEWD( "hr", 2.7777777777777778E-04, CDC_Time
); // Hour
2317 NEWD( "mn", 1.6666666666666667E-02, CDC_Time
); // Minute
2318 NEWD( "min", 1.6666666666666667E-02, CDC_Time
); // Minute also
2319 NEWDP( "sec", 1.0000000000000000E00
, CDC_Time
); // Second
2320 NEWDP( "s", 1.0000000000000000E00
, CDC_Time
); // Second also
2322 // PRESSURE: 1 Pascal is...
2323 NEWDP( "Pa", 1.0000000000000000E00
, CDC_Pressure
); // Pascal
2324 NEWDP( "atm", 9.8692329999819300E-06, CDC_Pressure
); // Atmosphere
2325 NEWDP( "at", 9.8692329999819300E-06, CDC_Pressure
); // Atmosphere also
2326 NEWDP( "mmHg", 7.5006170799862700E-03, CDC_Pressure
); // mm Hg (Mercury)
2327 NEWD( "Torr", 7.5006380000000000E-03, CDC_Pressure
); // *** Torr
2328 NEWD( "psi", 1.4503770000000000E-04, CDC_Pressure
); // *** Psi
2330 // FORCE: 1 Newton is...
2331 NEWDP( "N", 1.0000000000000000E00
, CDC_Force
); // Newton
2332 NEWDP( "dyn", 1.0000000000000000E05
, CDC_Force
); // Dyn
2333 NEWDP( "dy", 1.0000000000000000E05
, CDC_Force
); // Dyn also
2334 NEWD( "lbf", 2.24808923655339E-01, CDC_Force
); // Pound-Force
2335 NEWDP( "pond", 1.019716E02
, CDC_Force
); // *** Pond
2337 // ENERGY: 1 Joule is...
2338 NEWDP( "J", 1.0000000000000000E00
, CDC_Energy
); // Joule
2339 NEWDP( "e", 1.0000000000000000E07
, CDC_Energy
); // Erg -> https://en.wikipedia.org/wiki/Erg
2340 NEWDP( "c", 2.3900624947346700E-01, CDC_Energy
); // Thermodynamical Calorie
2341 NEWDP( "cal", 2.3884619064201700E-01, CDC_Energy
); // Calorie
2342 NEWDP( "eV", 6.2414570000000000E18
, CDC_Energy
); // Electronvolt
2343 NEWDP( "ev", 6.2414570000000000E18
, CDC_Energy
); // Electronvolt also
2344 NEWD( "HPh", 3.7250611111111111E-07, CDC_Energy
); // Horsepower Hours
2345 NEWD( "hh", 3.7250611111111111E-07, CDC_Energy
); // Horsepower Hours also
2346 NEWDP( "Wh", 2.7777777777777778E-04, CDC_Energy
); // Watt Hours
2347 NEWDP( "wh", 2.7777777777777778E-04, CDC_Energy
); // Watt Hours also
2348 NEWD( "flb", 2.37304222192651E01
, CDC_Energy
); // Foot Pound
2349 NEWD( "BTU", 9.4781506734901500E-04, CDC_Energy
); // British Thermal Unit
2350 NEWD( "btu", 9.4781506734901500E-04, CDC_Energy
); // British Thermal Unit also
2352 // POWER: 1 Watt is...
2353 NEWDP( "W", 1.0000000000000000E00
, CDC_Power
); // Watt
2354 NEWDP( "w", 1.0000000000000000E00
, CDC_Power
); // Watt also
2355 NEWD( "HP", 1.341022E-03, CDC_Power
); // Horsepower
2356 NEWD( "h", 1.341022E-03, CDC_Power
); // Horsepower also
2357 NEWD( "PS", 1.359622E-03, CDC_Power
); // *** German Pferdestaerke
2359 // MAGNETISM: 1 Tesla is...
2360 NEWDP( "T", 1.0000000000000000E00
, CDC_Magnetism
); // Tesla
2361 NEWDP( "ga", 1.0000000000000000E04
, CDC_Magnetism
); // Gauss
2363 // TEMPERATURE: 1 Kelvin is...
2364 NEWL( "C", 1.0000000000000000E00
, -2.7315000000000000E02
, CDC_Temperature
); // Celsius
2365 NEWL( "cel", 1.0000000000000000E00
, -2.7315000000000000E02
, CDC_Temperature
); // Celsius also
2366 NEWL( "F", 1.8000000000000000E00
, -2.5537222222222222E02
, CDC_Temperature
); // Fahrenheit
2367 NEWL( "fah", 1.8000000000000000E00
, -2.5537222222222222E02
, CDC_Temperature
); // Fahrenheit also
2368 NEWLP( "K", 1.0000000000000000E00
, +0.0000000000000000E00
, CDC_Temperature
); // Kelvin
2369 NEWLP( "kel", 1.0000000000000000E00
, +0.0000000000000000E00
, CDC_Temperature
); // Kelvin also
2370 NEWL( "Reau", 8.0000000000000000E-01, -2.7315000000000000E02
, CDC_Temperature
); // *** Reaumur
2371 NEWL( "Rank", 1.8000000000000000E00
, +0.0000000000000000E00
, CDC_Temperature
); // *** Rankine
2373 // VOLUME: 1 Liter is...
2374 NEWD( "tsp", 2.0288413621105798E02
, CDC_Volume
); // US teaspoon 1/768 gallon
2375 NEWD( "tbs", 6.7628045403685994E01
, CDC_Volume
); // US tablespoon 1/256 gallon
2376 NEWD( "oz", 3.3814022701842997E01
, CDC_Volume
); // Ounce Liquid 1/128 gallon
2377 NEWD( "cup", 4.2267528377303746E00
, CDC_Volume
); // Cup 1/16 gallon
2378 NEWD( "pt", 2.1133764188651873E00
, CDC_Volume
); // US Pint 1/8 gallon
2379 NEWD( "us_pt", 2.1133764188651873E00
, CDC_Volume
); // US Pint also
2380 NEWD( "uk_pt", 1.7597539863927023E00
, CDC_Volume
); // UK Pint 1/8 imperial gallon
2381 NEWD( "qt", 1.0566882094325937E00
, CDC_Volume
); // Quart 1/4 gallon
2382 NEWD( "gal", 2.6417205235814842E-01, CDC_Volume
); // Gallon 1/3.785411784
2383 NEWDP( "l", 1.0000000000000000E00
, CDC_Volume
); // Liter
2384 NEWDP( "L", 1.0000000000000000E00
, CDC_Volume
); // Liter also
2385 NEWDP( "lt", 1.0000000000000000E00
, CDC_Volume
); // Liter also
2386 NEWDP( "m3", 1.0000000000000000E-03, CDC_Volume
); // *** Cubic Meter
2387 NEWD( "mi3", 2.3991275857892772E-13, CDC_Volume
); // *** Cubic Britsh Mile
2388 NEWD( "Nmi3", 1.5742621468581148E-13, CDC_Volume
); // *** Cubic Nautical Mile
2389 NEWD( "in3", 6.1023744094732284E01
, CDC_Volume
); // *** Cubic Inch
2390 NEWD( "ft3", 3.5314666721488590E-02, CDC_Volume
); // *** Cubic Foot
2391 NEWD( "yd3", 1.3079506193143922E-03, CDC_Volume
); // *** Cubic Yard
2392 NEWDP( "ang3", 1.0000000000000000E27
, CDC_Volume
); // *** Cubic Angstroem
2393 NEWD( "Pica3", 2.2776990435870636E07
, CDC_Volume
); // *** Cubic Pica Point (1/72 inch)
2394 NEWD( "picapt3", 2.2776990435870636E07
, CDC_Volume
); // *** Cubic Pica Point (1/72 inch)
2395 NEWD( "pica3", 1.31811287245E04
, CDC_Volume
); // *** Cubic Pica (1/6 inch)
2396 NEWD( "barrel", 6.2898107704321051E-03, CDC_Volume
); // *** Barrel (=42gal)
2397 NEWD( "bushel", 2.837759E-02, CDC_Volume
); // *** Bushel
2398 NEWD( "regton", 3.531467E-04, CDC_Volume
); // *** Register ton
2399 NEWD( "GRT", 3.531467E-04, CDC_Volume
); // *** Register ton also
2400 NEWD( "Schooner", 2.3529411764705882E00
, CDC_Volume
); // *** austr. Schooner
2401 NEWD( "Middy", 3.5087719298245614E00
, CDC_Volume
); // *** austr. Middy
2402 NEWD( "Glass", 5.0000000000000000E00
, CDC_Volume
); // *** austr. Glass
2403 NEWD( "Sixpack", 0.5, CDC_Volume
); // ***
2404 NEWD( "Humpen", 2.0, CDC_Volume
); // ***
2405 NEWD( "ly3", 1.1810108125623799E-51, CDC_Volume
); // *** Cubic light-year
2406 NEWD( "MTON", 1.4125866688595436E00
, CDC_Volume
); // *** Measurement ton
2407 NEWD( "tspm", 2.0000000000000000E02
, CDC_Volume
); // *** Modern teaspoon
2408 NEWD( "uk_gal", 2.1996924829908779E-01, CDC_Volume
); // U.K. / Imperial gallon 1/4.54609
2409 NEWD( "uk_qt", 8.7987699319635115E-01, CDC_Volume
); // U.K. / Imperial quart 1/4 imperial gallon
2411 // 1 Square Meter is...
2412 NEWDP( "m2", 1.0000000000000000E00
, CDC_Area
); // *** Square Meter
2413 NEWD( "mi2", 3.8610215854244585E-07, CDC_Area
); // *** Square Britsh Mile
2414 NEWD( "Nmi2", 2.9155334959812286E-07, CDC_Area
); // *** Square Nautical Mile
2415 NEWD( "in2", 1.5500031000062000E03
, CDC_Area
); // *** Square Inch
2416 NEWD( "ft2", 1.0763910416709722E01
, CDC_Area
); // *** Square Foot
2417 NEWD( "yd2", 1.1959900463010803E00
, CDC_Area
); // *** Square Yard
2418 NEWDP( "ang2", 1.0000000000000000E20
, CDC_Area
); // *** Square Angstroem
2419 NEWD( "Pica2", 8.0352160704321409E06
, CDC_Area
); // *** Square Pica Point (1/72 inch)
2420 NEWD( "picapt2", 8.0352160704321409E06
, CDC_Area
); // *** Square Pica Point (1/72 inch)
2421 NEWD( "pica2", 5.58001116002232E04
, CDC_Area
); // *** Square Pica (1/6 inch)
2422 NEWD( "Morgen", 4.0000000000000000E-04, CDC_Area
); // *** Morgen
2423 NEWDP( "ar", 1.000000E-02, CDC_Area
); // *** Ar
2424 NEWD( "acre", 2.471053815E-04, CDC_Area
); // *** Acre
2425 NEWD( "uk_acre", 2.4710538146716534E-04, CDC_Area
); // *** International acre
2426 NEWD( "us_acre", 2.4710439304662790E-04, CDC_Area
); // *** U.S. survey/statute acre
2427 NEWD( "ly2", 1.1172985860549147E-32, CDC_Area
); // *** Square Light-year
2428 NEWD( "ha", 1.000000E-04, CDC_Area
); // *** Hectare
2430 // SPEED: 1 Meter per Second is...
2431 NEWDP( "m/s", 1.0000000000000000E00
, CDC_Speed
); // *** Meters per Second
2432 NEWDP( "m/sec", 1.0000000000000000E00
, CDC_Speed
); // *** Meters per Second also
2433 NEWDP( "m/h", 3.6000000000000000E03
, CDC_Speed
); // *** Meters per Hour
2434 NEWDP( "m/hr", 3.6000000000000000E03
, CDC_Speed
); // *** Meters per Hour also
2435 NEWD( "mph", 2.2369362920544023E00
, CDC_Speed
); // *** Britsh Miles per Hour
2436 NEWD( "kn", 1.9438444924406048E00
, CDC_Speed
); // *** Knot = Nautical Miles per Hour
2437 NEWD( "admkn", 1.9438446603753486E00
, CDC_Speed
); // *** Admiralty Knot
2438 NEWD( "ludicrous speed", 2.0494886343432328E-14, CDC_Speed
); // ***
2439 NEWD( "ridiculous speed", 4.0156958471424288E-06, CDC_Speed
); // ***
2441 // INFORMATION: 1 Bit is...
2442 NEWDP( "bit", 1.00E00
, CDC_Information
); // *** Bit
2443 NEWDP( "byte", 1.25E-01, CDC_Information
); // *** Byte
2447 ConvertDataList::~ConvertDataList()
2452 double ConvertDataList::Convert( double fVal
, const OUString
& rFrom
, const OUString
& rTo
)
2454 ConvertData
* pFrom
= nullptr;
2455 ConvertData
* pTo
= nullptr;
2456 bool bSearchFrom
= true;
2457 bool bSearchTo
= true;
2458 sal_Int16 nLevelFrom
= 0;
2459 sal_Int16 nLevelTo
= 0;
2461 for( const auto& rItem
: maVector
)
2463 ConvertData
* p
= rItem
.get();
2466 sal_Int16 n
= p
->GetMatchingLevel( rFrom
);
2467 if( n
!= INV_MATCHLEV
)
2470 { // only first match for partial equality rulz a little bit more
2475 { // ... but exact match rulz most
2477 bSearchFrom
= false;
2485 sal_Int16 n
= p
->GetMatchingLevel( rTo
);
2486 if( n
!= INV_MATCHLEV
)
2489 { // only first match for partial equality rulz a little bit more
2494 { // ... but exact match rulz most
2502 if( !bSearchFrom
&& !bSearchTo
)
2506 if( !pFrom
|| !pTo
)
2507 throw lang::IllegalArgumentException();
2509 return pFrom
->Convert( fVal
, *pTo
, nLevelFrom
, nLevelTo
);
2513 ScaDate::ScaDate() :
2518 bLastDayMode( true ),
2525 ScaDate::ScaDate( sal_Int32 nNullDate
, sal_Int32 nDate
, sal_Int32 nBase
)
2527 DaysToDate( nNullDate
+ nDate
, nOrigDay
, nMonth
, nYear
);
2528 bLastDayMode
= (nBase
!= 5);
2529 bLastDay
= (nOrigDay
>= ::DaysInMonth( nMonth
, nYear
));
2530 b30Days
= (nBase
== 0) || (nBase
== 4);
2531 bUSMode
= (nBase
== 0);
2535 ScaDate::ScaDate( const ScaDate
& rCopy
) :
2536 nOrigDay( rCopy
.nOrigDay
),
2538 nMonth( rCopy
.nMonth
),
2539 nYear( rCopy
.nYear
),
2540 bLastDayMode( rCopy
.bLastDayMode
),
2541 bLastDay( rCopy
.bLastDay
),
2542 b30Days( rCopy
.b30Days
),
2543 bUSMode( rCopy
.bUSMode
)
2547 ScaDate
& ScaDate::operator=( const ScaDate
& rCopy
)
2549 if( this != &rCopy
)
2551 nOrigDay
= rCopy
.nOrigDay
;
2553 nMonth
= rCopy
.nMonth
;
2554 nYear
= rCopy
.nYear
;
2555 bLastDayMode
= rCopy
.bLastDayMode
;
2556 bLastDay
= rCopy
.bLastDay
;
2557 b30Days
= rCopy
.b30Days
;
2558 bUSMode
= rCopy
.bUSMode
;
2563 void ScaDate::setDay()
2567 // 30-days-mode: set nDay to 30 if original was last day in month
2568 nDay
= std::min( nOrigDay
, static_cast< sal_uInt16
>( 30 ) );
2569 if( bLastDay
|| (nDay
>= ::DaysInMonth( nMonth
, nYear
)) )
2574 // set nDay to last day in this month if original was last day
2575 sal_uInt16 nLastDay
= ::DaysInMonth( nMonth
, nYear
);
2576 nDay
= bLastDay
? nLastDay
: std::min( nOrigDay
, nLastDay
);
2580 sal_Int32
ScaDate::getDaysInMonthRange( sal_uInt16 nFrom
, sal_uInt16 nTo
) const
2587 nRet
= (nTo
- nFrom
+ 1) * 30;
2590 for( sal_uInt16 nMonthIx
= nFrom
; nMonthIx
<= nTo
; ++nMonthIx
)
2591 nRet
+= getDaysInMonth( nMonthIx
);
2596 sal_Int32
ScaDate::getDaysInYearRange( sal_uInt16 nFrom
, sal_uInt16 nTo
) const
2601 return b30Days
? ((nTo
- nFrom
+ 1) * 360) : ::GetDaysInYears( nFrom
, nTo
);
2604 void ScaDate::doAddYears( sal_Int32 nYearCount
)
2606 sal_Int32 nNewYear
= nYearCount
+ nYear
;
2607 if( (nNewYear
< 0) || (nNewYear
> 0x7FFF) )
2608 throw lang::IllegalArgumentException();
2609 nYear
= static_cast< sal_uInt16
>( nNewYear
);
2612 void ScaDate::addMonths( sal_Int32 nMonthCount
)
2614 sal_Int32 nNewMonth
= nMonthCount
+ nMonth
;
2615 if( nNewMonth
> 12 )
2618 doAddYears( nNewMonth
/ 12 );
2619 nMonth
= static_cast< sal_uInt16
>( nNewMonth
% 12 ) + 1;
2621 else if( nNewMonth
< 1 )
2623 doAddYears( nNewMonth
/ 12 - 1 );
2624 nMonth
= static_cast< sal_uInt16
>( nNewMonth
% 12 + 12 );
2627 nMonth
= static_cast< sal_uInt16
>( nNewMonth
);
2631 sal_Int32
ScaDate::getDate( sal_Int32 nNullDate
) const
2633 sal_uInt16 nLastDay
= ::DaysInMonth( nMonth
, nYear
);
2634 sal_uInt16 nRealDay
= (bLastDayMode
&& bLastDay
) ? nLastDay
: std::min( nLastDay
, nOrigDay
);
2635 return ::DateToDays( nRealDay
, nMonth
, nYear
) - nNullDate
;
2638 sal_Int32
ScaDate::getDiff( const ScaDate
& rFrom
, const ScaDate
& rTo
)
2641 return getDiff( rTo
, rFrom
);
2643 sal_Int32 nDiff
= 0;
2644 ScaDate
aFrom( rFrom
);
2649 // corrections for base 0 (US NASD)
2652 if( ((rFrom
.nMonth
== 2) || (rFrom
.nDay
< 30)) && (aTo
.nOrigDay
== 31) )
2654 else if( (aTo
.nMonth
== 2) && aTo
.bLastDay
)
2655 aTo
.nDay
= ::DaysInMonth( 2, aTo
.nYear
);
2657 // corrections for base 4 (Europe)
2660 if( (aFrom
.nMonth
== 2) && (aFrom
.nDay
== 30) )
2661 aFrom
.nDay
= ::DaysInMonth( 2, aFrom
.nYear
);
2662 if( (aTo
.nMonth
== 2) && (aTo
.nDay
== 30) )
2663 aTo
.nDay
= ::DaysInMonth( 2, aTo
.nYear
);
2667 if( (aFrom
.nYear
< aTo
.nYear
) || ((aFrom
.nYear
== aTo
.nYear
) && (aFrom
.nMonth
< aTo
.nMonth
)) )
2669 // move aFrom to 1st day of next month
2670 nDiff
= aFrom
.getDaysInMonth() - aFrom
.nDay
+ 1;
2671 aFrom
.nOrigDay
= aFrom
.nDay
= 1;
2672 aFrom
.bLastDay
= false;
2673 aFrom
.addMonths( 1 );
2675 if( aFrom
.nYear
< aTo
.nYear
)
2677 // move aFrom to 1st day of next year
2678 nDiff
+= aFrom
.getDaysInMonthRange( aFrom
.nMonth
, 12 );
2679 aFrom
.addMonths( 13 - aFrom
.nMonth
);
2681 // move aFrom to 1st day of this year
2682 nDiff
+= aFrom
.getDaysInYearRange( aFrom
.nYear
, aTo
.nYear
- 1 );
2683 aFrom
.addYears( aTo
.nYear
- aFrom
.nYear
);
2686 // move aFrom to 1st day of this month
2687 nDiff
+= aFrom
.getDaysInMonthRange( aFrom
.nMonth
, aTo
.nMonth
- 1 );
2688 aFrom
.addMonths( aTo
.nMonth
- aFrom
.nMonth
);
2690 // finally add remaining days in this month
2691 nDiff
+= aTo
.nDay
- aFrom
.nDay
;
2692 return std::max
<sal_Int32
>(nDiff
, 0);
2695 bool ScaDate::operator<( const ScaDate
& rCmp
) const
2697 if( nYear
!= rCmp
.nYear
)
2698 return nYear
< rCmp
.nYear
;
2699 if( nMonth
!= rCmp
.nMonth
)
2700 return nMonth
< rCmp
.nMonth
;
2701 if( nDay
!= rCmp
.nDay
)
2702 return nDay
< rCmp
.nDay
;
2703 if( bLastDay
|| rCmp
.bLastDay
)
2704 return !bLastDay
&& rCmp
.bLastDay
;
2705 return nOrigDay
< rCmp
.nOrigDay
;
2709 ScaAnyConverter::ScaAnyConverter( const uno::Reference
< uno::XComponentContext
>& xContext
)
2711 , bHasValidFormat(false)
2713 xFormatter
= util::NumberFormatter::create(xContext
);
2716 ScaAnyConverter::~ScaAnyConverter()
2720 void ScaAnyConverter::init( const uno::Reference
< beans::XPropertySet
>& xPropSet
)
2722 // try to get default number format
2723 bHasValidFormat
= false;
2724 if( xFormatter
.is() )
2726 // get XFormatsSupplier from outer XPropertySet
2727 uno::Reference
< util::XNumberFormatsSupplier
> xFormatsSupp( xPropSet
, uno::UNO_QUERY
);
2728 if( xFormatsSupp
.is() )
2730 // get XNumberFormatTypes from XNumberFormatsSupplier to get standard index
2731 uno::Reference
< util::XNumberFormats
> xFormats( xFormatsSupp
->getNumberFormats() );
2732 uno::Reference
< util::XNumberFormatTypes
> xFormatTypes( xFormats
, uno::UNO_QUERY
);
2733 if( xFormatTypes
.is() )
2735 lang::Locale eLocale
;
2736 nDefaultFormat
= xFormatTypes
->getStandardIndex( eLocale
);
2737 xFormatter
->attachNumberFormatsSupplier( xFormatsSupp
);
2738 bHasValidFormat
= true;
2744 double ScaAnyConverter::convertToDouble( const OUString
& rString
) const
2746 double fValue
= 0.0;
2747 if( bHasValidFormat
)
2751 fValue
= xFormatter
->convertStringToNumber( nDefaultFormat
, rString
);
2753 catch( uno::Exception
& )
2755 throw lang::IllegalArgumentException();
2760 rtl_math_ConversionStatus eStatus
;
2762 fValue
= ::rtl::math::stringToDouble( rString
, '.', ',', &eStatus
, &nEnd
);
2763 if( (eStatus
!= rtl_math_ConversionStatus_Ok
) || (nEnd
< rString
.getLength()) )
2764 throw lang::IllegalArgumentException();
2769 bool ScaAnyConverter::getDouble(
2771 const uno::Any
& rAny
) const
2774 bool bContainsVal
= true;
2775 switch( rAny
.getValueTypeClass() )
2777 case uno::TypeClass_VOID
:
2778 bContainsVal
= false;
2780 case uno::TypeClass_DOUBLE
:
2783 case uno::TypeClass_STRING
:
2785 auto pString
= o3tl::forceAccess
< OUString
>( rAny
);
2786 if( !pString
->isEmpty() )
2787 rfResult
= convertToDouble( *pString
);
2789 bContainsVal
= false;
2793 throw lang::IllegalArgumentException();
2795 return bContainsVal
;
2798 bool ScaAnyConverter::getDouble(
2800 const uno::Reference
< beans::XPropertySet
>& xPropSet
,
2801 const uno::Any
& rAny
)
2804 return getDouble( rfResult
, rAny
);
2807 double ScaAnyConverter::getDouble(
2808 const uno::Reference
< beans::XPropertySet
>& xPropSet
,
2809 const uno::Any
& rAny
,
2813 if( !getDouble( fResult
, xPropSet
, rAny
) )
2818 bool ScaAnyConverter::getInt32(
2819 sal_Int32
& rnResult
,
2820 const uno::Reference
< beans::XPropertySet
>& xPropSet
,
2821 const uno::Any
& rAny
)
2824 bool bContainsVal
= getDouble( fResult
, xPropSet
, rAny
);
2825 if( (fResult
<= -2147483649.0) || (fResult
>= 2147483648.0) )
2826 throw lang::IllegalArgumentException();
2828 rnResult
= static_cast< sal_Int32
>( fResult
);
2829 return bContainsVal
;
2832 sal_Int32
ScaAnyConverter::getInt32(
2833 const uno::Reference
< beans::XPropertySet
>& xPropSet
,
2834 const uno::Any
& rAny
,
2835 sal_Int32 nDefault
)
2838 if( !getInt32( nResult
, xPropSet
, rAny
) )
2845 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */