/src/libreoffice/scaddins/source/analysis/analysishelper.cxx
Line | Count | Source |
1 | | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
2 | | /* |
3 | | * This file is part of the LibreOffice project. |
4 | | * |
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/. |
8 | | * |
9 | | * This file incorporates work covered by the following license notice: |
10 | | * |
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 . |
18 | | */ |
19 | | |
20 | | #include <com/sun/star/util/Date.hpp> |
21 | | #include <com/sun/star/util/XNumberFormatTypes.hpp> |
22 | | #include <com/sun/star/util/NumberFormatter.hpp> |
23 | | |
24 | | #include <string.h> |
25 | | #include <stdio.h> |
26 | | #include <o3tl/any.hxx> |
27 | | #include <o3tl/untaint.hxx> |
28 | | #include <rtl/math.hxx> |
29 | | #include <algorithm> |
30 | | #include <cmath> |
31 | | #include <complex> |
32 | | #include <memory> |
33 | | |
34 | | #include "analysisdefs.hxx" |
35 | | #include "analysishelper.hxx" |
36 | | #include <analysis.hrc> |
37 | | #include <strings.hrc> |
38 | | #include "deffuncname.hxx" |
39 | | |
40 | | using namespace ::com::sun::star; |
41 | | using namespace sca::analysis; |
42 | | |
43 | | #define UNIQUE false // function name does not exist in Calc |
44 | | #define DOUBLE true // function name exists in Calc |
45 | | |
46 | | #define STDPAR false // all parameters are described |
47 | | #define INTPAR true // first parameter is internal |
48 | | |
49 | 1.33k | #define INV_MATCHLEV 1764 // guess, what this is... :-) - I doubt this kind of comment looks fun :-( |
50 | | |
51 | | #define FUNCDATA( FUNCNAME, DBL, OPT, NUMOFPAR, CAT ) \ |
52 | | { "get" #FUNCNAME, ANALYSIS_FUNCNAME_##FUNCNAME, ANALYSIS_##FUNCNAME, DBL, OPT, ANALYSIS_DEFFUNCNAME_##FUNCNAME, NUMOFPAR, CAT, nullptr } |
53 | | |
54 | | #define FUNCDATAS( FUNCNAME, DBL, OPT, NUMOFPAR, CAT, SUFFIX ) \ |
55 | | { "get" #FUNCNAME, ANALYSIS_FUNCNAME_##FUNCNAME, ANALYSIS_##FUNCNAME, DBL, OPT, ANALYSIS_DEFFUNCNAME_##FUNCNAME, NUMOFPAR, CAT, SUFFIX } |
56 | | |
57 | | const FuncDataBase pFuncDatas[] = |
58 | | { |
59 | | // UNIQUE or INTPAR or |
60 | | // function name DOUBLE STDPAR # of param category |
61 | | FUNCDATA( Workday, UNIQUE, INTPAR, 3, FDCategory::DateTime ), |
62 | | FUNCDATA( Yearfrac, UNIQUE, INTPAR, 3, FDCategory::DateTime ), |
63 | | FUNCDATA( Edate, UNIQUE, INTPAR, 2, FDCategory::DateTime ), |
64 | | FUNCDATAS( Weeknum, DOUBLE, INTPAR, 2, FDCategory::DateTime, "_EXCEL2003" ), |
65 | | FUNCDATA( Eomonth, UNIQUE, INTPAR, 2, FDCategory::DateTime ), |
66 | | FUNCDATAS( Networkdays, DOUBLE, INTPAR, 3, FDCategory::DateTime, "_EXCEL2003" ), |
67 | | FUNCDATA( Iseven, DOUBLE, STDPAR, 1, FDCategory::Inf ), |
68 | | FUNCDATA( Isodd, DOUBLE, STDPAR, 1, FDCategory::Inf ), |
69 | | FUNCDATA( Multinomial, UNIQUE, STDPAR, 1, FDCategory::Math ), |
70 | | FUNCDATA( Seriessum, UNIQUE, STDPAR, 4, FDCategory::Math ), |
71 | | FUNCDATA( Quotient, UNIQUE, STDPAR, 2, FDCategory::Math ), |
72 | | FUNCDATA( Mround, UNIQUE, STDPAR, 2, FDCategory::Math ), |
73 | | FUNCDATA( Sqrtpi, UNIQUE, STDPAR, 1, FDCategory::Math ), |
74 | | FUNCDATA( Randbetween, UNIQUE, STDPAR, 2, FDCategory::Math ), |
75 | | FUNCDATAS( Gcd, DOUBLE, INTPAR, 1, FDCategory::Math, "_EXCEL2003" ), |
76 | | FUNCDATAS( Lcm, DOUBLE, INTPAR, 1, FDCategory::Math, "_EXCEL2003" ), |
77 | | FUNCDATA( Besseli, UNIQUE, STDPAR, 2, FDCategory::Tech ), |
78 | | FUNCDATA( Besselj, UNIQUE, STDPAR, 2, FDCategory::Tech ), |
79 | | FUNCDATA( Besselk, UNIQUE, STDPAR, 2, FDCategory::Tech ), |
80 | | FUNCDATA( Bessely, UNIQUE, STDPAR, 2, FDCategory::Tech ), |
81 | | FUNCDATA( Bin2Oct, UNIQUE, INTPAR, 2, FDCategory::Tech ), |
82 | | FUNCDATA( Bin2Dec, UNIQUE, STDPAR, 1, FDCategory::Tech ), |
83 | | FUNCDATA( Bin2Hex, UNIQUE, INTPAR, 2, FDCategory::Tech ), |
84 | | FUNCDATA( Oct2Bin, UNIQUE, INTPAR, 2, FDCategory::Tech ), |
85 | | FUNCDATA( Oct2Dec, UNIQUE, STDPAR, 1, FDCategory::Tech ), |
86 | | FUNCDATA( Oct2Hex, UNIQUE, INTPAR, 2, FDCategory::Tech ), |
87 | | FUNCDATA( Dec2Bin, UNIQUE, INTPAR, 2, FDCategory::Tech ), |
88 | | FUNCDATA( Dec2Hex, UNIQUE, INTPAR, 2, FDCategory::Tech ), |
89 | | FUNCDATA( Dec2Oct, UNIQUE, INTPAR, 2, FDCategory::Tech ), |
90 | | FUNCDATA( Hex2Bin, UNIQUE, INTPAR, 2, FDCategory::Tech ), |
91 | | FUNCDATA( Hex2Dec, UNIQUE, STDPAR, 1, FDCategory::Tech ), |
92 | | FUNCDATA( Hex2Oct, UNIQUE, INTPAR, 2, FDCategory::Tech ), |
93 | | FUNCDATA( Delta, UNIQUE, INTPAR, 2, FDCategory::Tech ), |
94 | | FUNCDATA( Erf, UNIQUE, INTPAR, 2, FDCategory::Tech ), |
95 | | FUNCDATA( Erfc, UNIQUE, STDPAR, 1, FDCategory::Tech ), |
96 | | FUNCDATA( Gestep, UNIQUE, INTPAR, 2, FDCategory::Tech ), |
97 | | FUNCDATA( Factdouble, UNIQUE, STDPAR, 1, FDCategory::Tech ), |
98 | | FUNCDATA( Imabs, UNIQUE, STDPAR, 1, FDCategory::Tech ), |
99 | | FUNCDATA( Imaginary, UNIQUE, STDPAR, 1, FDCategory::Tech ), |
100 | | FUNCDATA( Impower, UNIQUE, STDPAR, 2, FDCategory::Tech ), |
101 | | FUNCDATA( Imargument, UNIQUE, STDPAR, 1, FDCategory::Tech ), |
102 | | FUNCDATA( Imcos, UNIQUE, STDPAR, 1, FDCategory::Tech ), |
103 | | FUNCDATA( Imdiv, UNIQUE, STDPAR, 2, FDCategory::Tech ), |
104 | | FUNCDATA( Imexp, UNIQUE, STDPAR, 1, FDCategory::Tech ), |
105 | | FUNCDATA( Imconjugate, UNIQUE, STDPAR, 1, FDCategory::Tech ), |
106 | | FUNCDATA( Imln, UNIQUE, STDPAR, 1, FDCategory::Tech ), |
107 | | FUNCDATA( Imlog10, UNIQUE, STDPAR, 1, FDCategory::Tech ), |
108 | | FUNCDATA( Imlog2, UNIQUE, STDPAR, 1, FDCategory::Tech ), |
109 | | FUNCDATA( Improduct, UNIQUE, INTPAR, 2, FDCategory::Tech ), |
110 | | FUNCDATA( Imreal, UNIQUE, STDPAR, 1, FDCategory::Tech ), |
111 | | FUNCDATA( Imsin, UNIQUE, STDPAR, 1, FDCategory::Tech ), |
112 | | FUNCDATA( Imsub, UNIQUE, STDPAR, 2, FDCategory::Tech ), |
113 | | FUNCDATA( Imsqrt, UNIQUE, STDPAR, 1, FDCategory::Tech ), |
114 | | FUNCDATA( Imsum, UNIQUE, INTPAR, 1, FDCategory::Tech ), |
115 | | FUNCDATA( Imtan, UNIQUE, STDPAR, 1, FDCategory::Tech ), |
116 | | FUNCDATA( Imsec, UNIQUE, STDPAR, 1, FDCategory::Tech ), |
117 | | FUNCDATA( Imcsc, UNIQUE, STDPAR, 1, FDCategory::Tech ), |
118 | | FUNCDATA( Imcot, UNIQUE, STDPAR, 1, FDCategory::Tech ), |
119 | | FUNCDATA( Imsinh, UNIQUE, STDPAR, 1, FDCategory::Tech ), |
120 | | FUNCDATA( Imcosh, UNIQUE, STDPAR, 1, FDCategory::Tech ), |
121 | | FUNCDATA( Imsech, UNIQUE, STDPAR, 1, FDCategory::Tech ), |
122 | | FUNCDATA( Imcsch, UNIQUE, STDPAR, 1, FDCategory::Tech ), |
123 | | FUNCDATA( Complex, UNIQUE, STDPAR, 3, FDCategory::Tech ), |
124 | | FUNCDATA( Convert, UNIQUE, STDPAR, 3, FDCategory::Tech ), |
125 | | FUNCDATA( Amordegrc, UNIQUE, INTPAR, 7, FDCategory::Finance ), |
126 | | FUNCDATA( Amorlinc, UNIQUE, INTPAR, 7, FDCategory::Finance ), |
127 | | FUNCDATA( Accrint, UNIQUE, INTPAR, 7, FDCategory::Finance ), |
128 | | FUNCDATA( Accrintm, UNIQUE, INTPAR, 5, FDCategory::Finance ), |
129 | | FUNCDATA( Received, UNIQUE, INTPAR, 5, FDCategory::Finance ), |
130 | | FUNCDATA( Disc, UNIQUE, INTPAR, 5, FDCategory::Finance ), |
131 | | FUNCDATA( Duration, UNIQUE, INTPAR, 6, FDCategory::Finance ), |
132 | | FUNCDATA( Effect, DOUBLE, STDPAR, 2, FDCategory::Finance ), |
133 | | FUNCDATA( Cumprinc, DOUBLE, STDPAR, 6, FDCategory::Finance ), |
134 | | FUNCDATA( Cumipmt, DOUBLE, STDPAR, 6, FDCategory::Finance ), |
135 | | FUNCDATA( Price, UNIQUE, INTPAR, 7, FDCategory::Finance ), |
136 | | FUNCDATA( Pricedisc, UNIQUE, INTPAR, 5, FDCategory::Finance ), |
137 | | FUNCDATA( Pricemat, UNIQUE, INTPAR, 6, FDCategory::Finance ), |
138 | | FUNCDATA( Mduration, UNIQUE, INTPAR, 6, FDCategory::Finance ), |
139 | | FUNCDATA( Nominal, DOUBLE, STDPAR, 2, FDCategory::Finance ), |
140 | | FUNCDATA( Dollarfr, UNIQUE, STDPAR, 2, FDCategory::Finance ), |
141 | | FUNCDATA( Dollarde, UNIQUE, STDPAR, 2, FDCategory::Finance ), |
142 | | FUNCDATA( Yield, UNIQUE, INTPAR, 7, FDCategory::Finance ), |
143 | | FUNCDATA( Yielddisc, UNIQUE, INTPAR, 5, FDCategory::Finance ), |
144 | | FUNCDATA( Yieldmat, UNIQUE, INTPAR, 6, FDCategory::Finance ), |
145 | | FUNCDATA( Tbilleq, UNIQUE, INTPAR, 3, FDCategory::Finance ), |
146 | | FUNCDATA( Tbillprice, UNIQUE, INTPAR, 3, FDCategory::Finance ), |
147 | | FUNCDATA( Tbillyield, UNIQUE, INTPAR, 3, FDCategory::Finance ), |
148 | | FUNCDATA( Oddfprice, UNIQUE, INTPAR, 9, FDCategory::Finance ), |
149 | | FUNCDATA( Oddfyield, UNIQUE, INTPAR, 9, FDCategory::Finance ), |
150 | | FUNCDATA( Oddlprice, UNIQUE, INTPAR, 8, FDCategory::Finance ), |
151 | | FUNCDATA( Oddlyield, UNIQUE, INTPAR, 8, FDCategory::Finance ), |
152 | | FUNCDATA( Xirr, UNIQUE, INTPAR, 3, FDCategory::Finance ), |
153 | | FUNCDATA( Xnpv, UNIQUE, STDPAR, 3, FDCategory::Finance ), |
154 | | FUNCDATA( Intrate, UNIQUE, INTPAR, 5, FDCategory::Finance ), |
155 | | FUNCDATA( Coupncd, UNIQUE, INTPAR, 4, FDCategory::Finance ), |
156 | | FUNCDATA( Coupdays, UNIQUE, INTPAR, 4, FDCategory::Finance ), |
157 | | FUNCDATA( Coupdaysnc, UNIQUE, INTPAR, 4, FDCategory::Finance ), |
158 | | FUNCDATA( Coupdaybs, UNIQUE, INTPAR, 4, FDCategory::Finance ), |
159 | | FUNCDATA( Couppcd, UNIQUE, INTPAR, 4, FDCategory::Finance ), |
160 | | FUNCDATA( Coupnum, UNIQUE, INTPAR, 4, FDCategory::Finance ), |
161 | | FUNCDATA( Fvschedule, UNIQUE, STDPAR, 2, FDCategory::Finance ) |
162 | | }; |
163 | | #undef FUNCDATA |
164 | | |
165 | | namespace sca::analysis { |
166 | | |
167 | | sal_uInt16 DaysInMonth( sal_uInt16 nMonth, sal_uInt16 nYear ) |
168 | 189 | { |
169 | 189 | if( (nMonth == 2) && IsLeapYear( nYear ) ) |
170 | 0 | return 29; |
171 | 189 | static const sal_uInt16 aDaysInMonth[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; |
172 | 189 | return aDaysInMonth[ nMonth ]; |
173 | 189 | } |
174 | | |
175 | | |
176 | | /** |
177 | | * Convert a date to a count of days starting from 01/01/0001 |
178 | | * |
179 | | * The internal representation of a Date used in this Addin |
180 | | * is the number of days between 01/01/0001 and the date |
181 | | * this function converts a Day , Month, Year representation |
182 | | * to this internal Date value. |
183 | | * |
184 | | */ |
185 | | |
186 | | sal_Int32 DateToDays( sal_uInt16 nDay, sal_uInt16 nMonth, sal_uInt16 nYear ) |
187 | 15 | { |
188 | 15 | sal_Int32 nDays = (static_cast<sal_Int32>(nYear)-1) * 365; |
189 | 15 | nDays += ((nYear-1) / 4) - ((nYear-1) / 100) + ((nYear-1) / 400); |
190 | | |
191 | 160 | for( sal_uInt16 i = 1; i < nMonth; i++ ) |
192 | 145 | nDays += DaysInMonth(i,nYear); |
193 | 15 | nDays += nDay; |
194 | | |
195 | 15 | return nDays; |
196 | 15 | } |
197 | | |
198 | | |
199 | | /** |
200 | | * Convert a count of days starting from 01/01/0001 to a date |
201 | | * |
202 | | * The internal representation of a Date used in this Addin |
203 | | * is the number of days between 01/01/0001 and the date |
204 | | * this function converts this internal Date value |
205 | | * to a Day , Month, Year representation of a Date. |
206 | | * |
207 | | */ |
208 | | |
209 | | void DaysToDate( sal_Int32 nDays, sal_uInt16& rDay, sal_uInt16& rMonth, sal_uInt16& rYear ) |
210 | 18 | { |
211 | 18 | if( nDays < 0 ) |
212 | 0 | throw lang::IllegalArgumentException(); |
213 | | |
214 | 18 | sal_Int32 nTempDays; |
215 | 18 | sal_Int32 i = 0; |
216 | 18 | bool bCalc; |
217 | | |
218 | 18 | do |
219 | 18 | { |
220 | 18 | nTempDays = nDays; |
221 | 18 | rYear = static_cast<sal_uInt16>((nTempDays / 365) - i); |
222 | 18 | nTempDays -= (static_cast<sal_Int32>(rYear) -1) * 365; |
223 | 18 | nTempDays -= (( rYear -1) / 4) - (( rYear -1) / 100) + ((rYear -1) / 400); |
224 | 18 | bCalc = false; |
225 | 18 | if ( nTempDays < 1 ) |
226 | 0 | { |
227 | 0 | i++; |
228 | 0 | bCalc = true; |
229 | 0 | } |
230 | 18 | else |
231 | 18 | { |
232 | 18 | if ( nTempDays > 365 ) |
233 | 0 | { |
234 | 0 | if ( (nTempDays != 366) || !IsLeapYear( rYear ) ) |
235 | 0 | { |
236 | 0 | i--; |
237 | 0 | bCalc = true; |
238 | 0 | } |
239 | 0 | } |
240 | 18 | } |
241 | 18 | } |
242 | 18 | while ( bCalc ); |
243 | | |
244 | 18 | rMonth = 1; |
245 | 20 | while ( nTempDays > DaysInMonth( rMonth, rYear ) ) |
246 | 2 | { |
247 | 2 | nTempDays -= DaysInMonth( rMonth, rYear ); |
248 | 2 | rMonth++; |
249 | 2 | } |
250 | 18 | rDay = static_cast<sal_uInt16>(nTempDays); |
251 | 18 | } |
252 | | |
253 | | |
254 | | /** |
255 | | * Get the null date used by the spreadsheet document |
256 | | * |
257 | | * The internal representation of a Date used in this Addin |
258 | | * is the number of days between 01/01/0001 and the date |
259 | | * this function returns this internal Date value for the document null date |
260 | | * |
261 | | */ |
262 | | |
263 | | sal_Int32 GetNullDate( const uno::Reference< beans::XPropertySet >& xOpt ) |
264 | 13 | { |
265 | 13 | if( xOpt.is() ) |
266 | 13 | { |
267 | 13 | try |
268 | 13 | { |
269 | 13 | uno::Any aAny = xOpt->getPropertyValue( u"NullDate"_ustr ); |
270 | 13 | util::Date aDate; |
271 | 13 | if( aAny >>= aDate ) |
272 | 13 | return DateToDays( aDate.Day, aDate.Month, aDate.Year ); |
273 | 13 | } |
274 | 13 | catch( uno::Exception& ) |
275 | 13 | { |
276 | 0 | } |
277 | 13 | } |
278 | | |
279 | | // no null date available -> no calculations possible |
280 | 0 | throw uno::RuntimeException(); |
281 | 13 | } |
282 | | |
283 | | |
284 | | sal_Int32 GetDiffDate360( |
285 | | sal_uInt16 nDay1, sal_uInt16 nMonth1, sal_uInt16 nYear1, bool bLeapYear1, |
286 | | sal_uInt16 nDay2, sal_uInt16 nMonth2, sal_uInt16 nYear2, |
287 | | bool bUSAMethod ) |
288 | 0 | { |
289 | 0 | if( nDay1 == 31 ) |
290 | 0 | nDay1--; |
291 | 0 | else if( bUSAMethod && ( nMonth1 == 2 && ( nDay1 == 29 || ( nDay1 == 28 && !bLeapYear1 ) ) ) ) |
292 | 0 | nDay1 = 30; |
293 | |
|
294 | 0 | if( nDay2 == 31 ) |
295 | 0 | { |
296 | 0 | if( bUSAMethod && nDay1 != 30 ) |
297 | 0 | { |
298 | 0 | nDay2 = 1; |
299 | 0 | if( nMonth2 == 12 ) |
300 | 0 | { |
301 | 0 | nYear2++; |
302 | 0 | nMonth2 = 1; |
303 | 0 | } |
304 | 0 | else |
305 | 0 | nMonth2++; |
306 | 0 | } |
307 | 0 | else |
308 | 0 | nDay2 = 30; |
309 | 0 | } |
310 | |
|
311 | 0 | return nDay2 + nMonth2 * 30 + nYear2 * 360 - nDay1 - nMonth1 * 30 - nYear1 * 360; |
312 | 0 | } |
313 | | |
314 | | |
315 | | sal_Int32 GetDiffDate360( sal_Int32 nNullDate, sal_Int32 nDate1, sal_Int32 nDate2, bool bUSAMethod ) |
316 | 0 | { |
317 | 0 | nDate1 += nNullDate; |
318 | 0 | nDate2 += nNullDate; |
319 | |
|
320 | 0 | sal_uInt16 nDay1, nMonth1, nYear1, nDay2, nMonth2, nYear2; |
321 | |
|
322 | 0 | DaysToDate( nDate1, nDay1, nMonth1, nYear1 ); |
323 | 0 | DaysToDate( nDate2, nDay2, nMonth2, nYear2 ); |
324 | |
|
325 | 0 | return GetDiffDate360( nDay1, nMonth1, nYear1, IsLeapYear( nYear1 ), nDay2, nMonth2, nYear2, bUSAMethod ); |
326 | 0 | } |
327 | | |
328 | | |
329 | | sal_Int32 GetDaysInYears( sal_uInt16 nYear1, sal_uInt16 nYear2 ) |
330 | 0 | { |
331 | 0 | sal_uInt16 nLeaps = 0; |
332 | 0 | for( sal_uInt16 n = nYear1 ; n <= nYear2 ; n++ ) |
333 | 0 | { |
334 | 0 | if( IsLeapYear( n ) ) |
335 | 0 | nLeaps++; |
336 | 0 | } |
337 | |
|
338 | 0 | sal_uInt32 nSum = 1; |
339 | 0 | nSum += nYear2; |
340 | 0 | nSum -= nYear1; |
341 | 0 | nSum *= 365; |
342 | 0 | nSum += nLeaps; |
343 | |
|
344 | 0 | return nSum; |
345 | 0 | } |
346 | | |
347 | | |
348 | | sal_Int32 GetDiffDate( sal_Int32 nNullDate, sal_Int32 nStartDate, sal_Int32 nEndDate, sal_Int32 nMode, |
349 | | sal_Int32* pOptDaysIn1stYear ) |
350 | 0 | { |
351 | 0 | bool bNeg = nStartDate > nEndDate; |
352 | |
|
353 | 0 | if( bNeg ) |
354 | 0 | std::swap( nStartDate, nEndDate ); |
355 | |
|
356 | 0 | sal_Int32 nRet; |
357 | |
|
358 | 0 | switch( nMode ) |
359 | 0 | { |
360 | 0 | case 0: // 0=USA (NASD) 30/360 |
361 | 0 | case 4: // 4=Europe 30/360 |
362 | 0 | { |
363 | 0 | sal_uInt16 nD1, nM1, nY1, nD2, nM2, nY2; |
364 | |
|
365 | 0 | nStartDate += nNullDate; |
366 | 0 | nEndDate += nNullDate; |
367 | |
|
368 | 0 | DaysToDate( nStartDate, nD1, nM1, nY1 ); |
369 | 0 | DaysToDate( nEndDate, nD2, nM2, nY2 ); |
370 | |
|
371 | 0 | bool bLeap = IsLeapYear( nY1 ); |
372 | 0 | sal_Int32 nDays, nMonths; |
373 | |
|
374 | 0 | nMonths = nM2 - nM1; |
375 | 0 | nDays = nD2 - nD1; |
376 | |
|
377 | 0 | nMonths += ( nY2 - nY1 ) * 12; |
378 | |
|
379 | 0 | nRet = nMonths * 30 + nDays; |
380 | 0 | if( nMode == 0 && nM1 == 2 && nM2 != 2 && nY1 == nY2 ) |
381 | 0 | nRet -= bLeap? 1 : 2; |
382 | |
|
383 | 0 | if( pOptDaysIn1stYear ) |
384 | 0 | *pOptDaysIn1stYear = 360; |
385 | 0 | } |
386 | 0 | break; |
387 | 0 | case 1: // 1=exact/exact |
388 | 0 | if( pOptDaysIn1stYear ) |
389 | 0 | { |
390 | 0 | sal_uInt16 nD, nM, nY; |
391 | |
|
392 | 0 | DaysToDate( nStartDate + nNullDate, nD, nM, nY ); |
393 | |
|
394 | 0 | *pOptDaysIn1stYear = IsLeapYear( nY )? 366 : 365; |
395 | 0 | } |
396 | 0 | nRet = nEndDate - nStartDate; |
397 | 0 | break; |
398 | 0 | case 2: // 2=exact/360 |
399 | 0 | nRet = nEndDate - nStartDate; |
400 | 0 | if( pOptDaysIn1stYear ) |
401 | 0 | *pOptDaysIn1stYear = 360; |
402 | 0 | break; |
403 | 0 | case 3: //3=exact/365 |
404 | 0 | nRet = nEndDate - nStartDate; |
405 | 0 | if( pOptDaysIn1stYear ) |
406 | 0 | *pOptDaysIn1stYear = 365; |
407 | 0 | break; |
408 | 0 | default: |
409 | 0 | throw lang::IllegalArgumentException(); |
410 | 0 | } |
411 | | |
412 | 0 | return bNeg? -nRet : nRet; |
413 | 0 | } |
414 | | |
415 | | |
416 | | double GetYearDiff( sal_Int32 nNullDate, sal_Int32 nStartDate, sal_Int32 nEndDate, sal_Int32 nMode ) |
417 | 0 | { |
418 | 0 | sal_Int32 nDays1stYear; |
419 | 0 | sal_Int32 nTotalDays = GetDiffDate( nNullDate, nStartDate, nEndDate, nMode, &nDays1stYear ); |
420 | |
|
421 | 0 | return double( nTotalDays ) / double( nDays1stYear ); |
422 | 0 | } |
423 | | |
424 | | |
425 | | sal_Int32 GetDaysInYear( sal_Int32 nNullDate, sal_Int32 nDate, sal_Int32 nMode ) |
426 | 0 | { |
427 | 0 | switch( nMode ) |
428 | 0 | { |
429 | 0 | case 0: // 0=USA (NASD) 30/360 |
430 | 0 | case 2: // 2=exact/360 |
431 | 0 | case 4: // 4=Europe 30/360 |
432 | 0 | return 360; |
433 | 0 | case 1: // 1=exact/exact |
434 | 0 | { |
435 | 0 | sal_uInt16 nD, nM, nY; |
436 | 0 | nDate += nNullDate; |
437 | 0 | DaysToDate( nDate, nD, nM, nY ); |
438 | 0 | return IsLeapYear( nY )? 366 : 365; |
439 | 0 | } |
440 | 0 | case 3: //3=exact/365 |
441 | 0 | return 365; |
442 | 0 | default: |
443 | 0 | throw lang::IllegalArgumentException(); |
444 | 0 | } |
445 | 0 | } |
446 | | |
447 | | |
448 | | // tdf69569 making code compliant with change request for ODFF1.2 par 4.11.7.7 |
449 | | /** |
450 | | * Function GetYearFrac implements YEARFRAC as defined in: |
451 | | * Open Document Format for Office Applications version 1.2 Part 2, par. 6.10.24 |
452 | | * The calculations are defined in: |
453 | | * Open Document Format for Office Applications version 1.2 Part 2, par. 4.11.7 |
454 | | */ |
455 | | double GetYearFrac( sal_Int32 nNullDate, sal_Int32 nStartDate, sal_Int32 nEndDate, sal_Int32 nMode ) |
456 | 4 | { |
457 | 4 | if( nStartDate == nEndDate ) |
458 | 0 | return 0.0; // nothing to do... |
459 | | |
460 | 4 | if( nStartDate > nEndDate ) |
461 | 0 | std::swap( nStartDate, nEndDate ); |
462 | | |
463 | 4 | sal_Int32 nDate1 = nStartDate + nNullDate; |
464 | 4 | sal_Int32 nDate2 = nEndDate + nNullDate; |
465 | | |
466 | 4 | sal_uInt16 nDay1, nDay2; |
467 | 4 | sal_uInt16 nMonth1, nMonth2; |
468 | 4 | sal_uInt16 nYear1, nYear2; |
469 | | |
470 | 4 | DaysToDate( nDate1, nDay1, nMonth1, nYear1 ); |
471 | 4 | DaysToDate( nDate2, nDay2, nMonth2, nYear2 ); |
472 | | |
473 | | // calculate days between nDate1 and nDate2 |
474 | 4 | sal_Int32 nDayDiff; |
475 | 4 | switch( nMode ) |
476 | 4 | { |
477 | 0 | case 0: // 0=USA (NASD) 30/360 |
478 | 0 | if ( nDay1 == 31 ) |
479 | 0 | { |
480 | 0 | nDay1--; |
481 | 0 | } |
482 | 0 | if ( nDay1 == 30 && nDay2 == 31 ) |
483 | 0 | { |
484 | 0 | nDay2--; |
485 | 0 | } |
486 | 0 | else |
487 | 0 | { |
488 | 0 | if ( nMonth1 == 2 && nDay1 == ( IsLeapYear( nYear1 ) ? 29 : 28 ) ) |
489 | 0 | { |
490 | 0 | nDay1 = 30; |
491 | 0 | if ( nMonth2 == 2 && nDay2 == ( IsLeapYear( nYear2 ) ? 29 : 28 ) ) |
492 | 0 | { |
493 | 0 | nDay2 = 30; |
494 | 0 | } |
495 | 0 | } |
496 | 0 | } |
497 | 0 | nDayDiff = ( nYear2 - nYear1 ) * 360 + ( nMonth2 - nMonth1 ) * 30 + ( nDay2 - nDay1 ); |
498 | 0 | break; |
499 | 0 | case 1: // 1=exact/exact |
500 | 0 | case 2: // 2=exact/360 |
501 | 0 | case 3: // 3=exact/365 |
502 | 0 | nDayDiff = nDate2 - nDate1; |
503 | 0 | break; |
504 | 4 | case 4: // 4=Europe 30/360 |
505 | 4 | if ( nDay1 == 31 ) |
506 | 0 | { |
507 | 0 | nDay1--; |
508 | 0 | } |
509 | 4 | if ( nDay2 == 31 ) |
510 | 0 | { |
511 | 0 | nDay2--; |
512 | 0 | } |
513 | 4 | nDayDiff = ( nYear2 - nYear1 ) * 360 + ( nMonth2 - nMonth1 ) * 30 + ( nDay2 - nDay1 ); |
514 | 4 | break; |
515 | 0 | default: |
516 | 0 | throw lang::IllegalArgumentException(); |
517 | 4 | } |
518 | | |
519 | | //calculate days in year |
520 | 4 | double nDaysInYear; |
521 | 4 | switch( nMode ) |
522 | 4 | { |
523 | 0 | case 0: // 0=USA (NASD) 30/360 |
524 | 0 | case 2: // 2=exact/360 |
525 | 4 | case 4: // 4=Europe 30/360 |
526 | 4 | nDaysInYear = 360; |
527 | 4 | break; |
528 | 0 | case 1: // 1=exact/exact |
529 | 0 | { |
530 | 0 | const bool isYearDifferent = ( nYear1 != nYear2 ); |
531 | | // ODFv1.2 part 2 section 4.11.7.7.7 |
532 | 0 | if ( isYearDifferent && |
533 | 0 | ( ( nYear2 != nYear1 + 1 ) || |
534 | 0 | ( nMonth1 < nMonth2 ) || |
535 | 0 | ( nMonth1 == nMonth2 && nDay1 < nDay2 ) ) ) |
536 | 0 | { |
537 | | // return average of days in year between nDate1 and nDate2, inclusive |
538 | 0 | sal_Int32 nDayCount = 0; |
539 | 0 | for ( sal_uInt16 i = nYear1; i <= nYear2; i++ ) |
540 | 0 | nDayCount += ( IsLeapYear( i ) ? 366 : 365 ); |
541 | |
|
542 | 0 | nDaysInYear = static_cast<double>(nDayCount) / static_cast<double>( nYear2 - nYear1 + 1 ); |
543 | 0 | } |
544 | 0 | else |
545 | 0 | { |
546 | | // as a consequence, !isYearDifferent or |
547 | | // nYear2 == nYear + 1 and (nMonth1 > nMonth2 or |
548 | | // (nMonth1 == nMonth2 and nDay1 >= nDay2)) |
549 | 0 | assert( ( !isYearDifferent || |
550 | 0 | ( nYear1 + 1 == nYear2 && |
551 | 0 | ( nMonth1 > nMonth2 || |
552 | 0 | ( nMonth1 == nMonth2 || nDay1 >= nDay2 ) ) ) ) ); |
553 | | |
554 | | // ODFv1.2 part 2 section 4.11.7.7.8 (CHANGE REQUEST PENDING, see tdf6959) |
555 | 0 | if ( !isYearDifferent && IsLeapYear( nYear1 ) ) |
556 | 0 | { |
557 | 0 | nDaysInYear = 366; |
558 | 0 | } |
559 | 0 | else |
560 | 0 | { |
561 | | // ODFv1.2 part 2 section 4.11.7.7.9/10 (CHANGE REQUEST PENDING, see tdf69569) |
562 | | // we need to determine whether there is a 29 February |
563 | | // between nDate1 (inclusive) and nDate2 (inclusive) |
564 | | // the case of nYear1 == nYear2 is adequately tested in previous test |
565 | 0 | if( isYearDifferent && |
566 | 0 | ( ( IsLeapYear( nYear1 ) && |
567 | 0 | ( ( nMonth1 < 2 ) || ( ( nMonth1 == 2 ) && ( nDay1 <= 29 ) ) ) ) || |
568 | 0 | ( IsLeapYear( nYear2 ) && |
569 | 0 | ( nMonth2 > 2 || ( ( nMonth2 == 2 ) && ( nDay2 == 29 ) ) ) ) ) ) |
570 | 0 | { |
571 | 0 | nDaysInYear = 366; |
572 | 0 | } |
573 | 0 | else |
574 | 0 | { |
575 | 0 | nDaysInYear = 365; |
576 | 0 | } |
577 | 0 | } |
578 | 0 | } |
579 | 0 | } |
580 | 0 | break; |
581 | 0 | case 3: // 3=exact/365 |
582 | 0 | nDaysInYear = 365; |
583 | 0 | break; |
584 | | // coverity[dead_error_begin] - following conditions exist to avoid compiler warning |
585 | 0 | default: |
586 | 0 | throw lang::IllegalArgumentException(); |
587 | 4 | } |
588 | | |
589 | 4 | return double( nDayDiff ) / nDaysInYear; |
590 | 4 | } |
591 | | |
592 | | double BinomialCoefficient( double n, double k ) |
593 | 0 | { |
594 | | // This method is a copy of BinomCoeff() |
595 | | // found in sc/source/core/tool/interpr3.cxx |
596 | |
|
597 | 0 | double nVal = 0.0; |
598 | 0 | k = ::rtl::math::approxFloor(k); |
599 | 0 | if (n < k) |
600 | 0 | nVal = 0.0; |
601 | 0 | else if (k == 0.0) |
602 | 0 | nVal = 1.0; |
603 | 0 | else |
604 | 0 | { |
605 | 0 | nVal = n/k; |
606 | 0 | n--; |
607 | 0 | k--; |
608 | 0 | while (k > 0.0) |
609 | 0 | { |
610 | 0 | nVal *= n/k; |
611 | 0 | k--; |
612 | 0 | n--; |
613 | 0 | } |
614 | 0 | } |
615 | 0 | return nVal; |
616 | 0 | } |
617 | | |
618 | | double GetGcd( double f1, double f2 ) |
619 | 0 | { |
620 | 0 | double f = fmod( f1, f2 ); |
621 | 0 | while( f > 0.0 ) |
622 | 0 | { |
623 | 0 | f1 = f2; |
624 | 0 | f2 = f; |
625 | 0 | f = fmod( f1, f2 ); |
626 | 0 | } |
627 | |
|
628 | 0 | return f2; |
629 | 0 | } |
630 | | |
631 | | |
632 | | double ConvertToDec( const OUString& aStr, sal_uInt16 nBase, sal_uInt16 nCharLim ) |
633 | 0 | { |
634 | 0 | if ( nBase < 2 || nBase > 36 ) |
635 | 0 | throw lang::IllegalArgumentException(); |
636 | | |
637 | 0 | sal_uInt32 nStrLen = aStr.getLength(); |
638 | 0 | if( nStrLen > nCharLim ) |
639 | 0 | throw lang::IllegalArgumentException(); |
640 | 0 | else if( !nStrLen ) |
641 | 0 | return 0.0; |
642 | | |
643 | 0 | double fVal = 0.0; |
644 | |
|
645 | 0 | const sal_Unicode* p = aStr.getStr(); |
646 | |
|
647 | 0 | sal_uInt16 nFirstDig = 0; |
648 | 0 | bool bFirstDig = true; |
649 | 0 | double fBase = nBase; |
650 | |
|
651 | 0 | while ( *p ) |
652 | 0 | { |
653 | 0 | sal_uInt16 n; |
654 | |
|
655 | 0 | if( '0' <= *p && *p <= '9' ) |
656 | 0 | n = *p - '0'; |
657 | 0 | else if( 'A' <= *p && *p <= 'Z' ) |
658 | 0 | n = 10 + ( *p - 'A' ); |
659 | 0 | else if ( 'a' <= *p && *p <= 'z' ) |
660 | 0 | n = 10 + ( *p - 'a' ); |
661 | 0 | else |
662 | 0 | n = nBase; |
663 | |
|
664 | 0 | if( n >= nBase ) |
665 | 0 | throw lang::IllegalArgumentException(); // illegal char! |
666 | | |
667 | 0 | if( bFirstDig ) |
668 | 0 | { |
669 | 0 | bFirstDig = false; |
670 | 0 | nFirstDig = n; |
671 | 0 | } |
672 | 0 | fVal = fVal * fBase + double( n ); |
673 | |
|
674 | 0 | p++; |
675 | |
|
676 | 0 | } |
677 | | |
678 | 0 | if( nStrLen == nCharLim && !bFirstDig && (nFirstDig >= nBase / 2) ) |
679 | 0 | { // handling negative values |
680 | 0 | fVal = ( pow( double( nBase ), double( nCharLim ) ) - fVal ); // complement |
681 | 0 | fVal *= -1.0; |
682 | 0 | } |
683 | |
|
684 | 0 | return fVal; |
685 | 0 | } |
686 | | |
687 | | |
688 | | static char GetMaxChar( sal_uInt16 nBase ) |
689 | 0 | { |
690 | 0 | const char* const c = "--123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; |
691 | 0 | return c[ nBase ]; |
692 | 0 | } |
693 | | |
694 | | |
695 | | OUString ConvertFromDec( double fNum, double fMin, double fMax, sal_uInt16 nBase, |
696 | | sal_Int32 nPlaces, sal_Int32 nMaxPlaces, bool bUsePlaces ) |
697 | 21.3k | { |
698 | 21.3k | fNum = ::rtl::math::approxFloor( fNum ); |
699 | 21.3k | fMin = ::rtl::math::approxFloor( fMin ); |
700 | 21.3k | fMax = ::rtl::math::approxFloor( fMax ); |
701 | | |
702 | 21.3k | if( fNum < fMin || fNum > fMax || ( bUsePlaces && ( nPlaces <= 0 || nPlaces > nMaxPlaces ) ) ) |
703 | 0 | throw lang::IllegalArgumentException(); |
704 | | |
705 | 21.3k | sal_Int64 nNum = static_cast< sal_Int64 >( fNum ); |
706 | 21.3k | bool bNeg = nNum < 0; |
707 | 21.3k | if( bNeg ) |
708 | 18 | nNum = sal_Int64( pow( double( nBase ), double( nMaxPlaces ) ) ) + nNum; |
709 | | |
710 | 21.3k | OUString aRet(OUString::number(nNum, nBase).toAsciiUpperCase()); |
711 | | |
712 | | |
713 | 21.3k | if( bUsePlaces ) |
714 | 0 | { |
715 | 0 | sal_Int32 nLen = aRet.getLength(); |
716 | 0 | if( !bNeg && nLen > nPlaces ) |
717 | 0 | { |
718 | 0 | throw lang::IllegalArgumentException(); |
719 | 0 | } |
720 | 0 | else if( ( bNeg && nLen < nMaxPlaces ) || ( !bNeg && nLen < nPlaces ) ) |
721 | 0 | { |
722 | 0 | sal_Int32 nLeft = nPlaces - nLen; |
723 | 0 | std::unique_ptr<char[]> p( new char[ nLeft + 1 ] ); |
724 | 0 | memset( p.get(), bNeg ? GetMaxChar( nBase ) : '0', nLeft ); |
725 | 0 | p[ nLeft ] = 0x00; |
726 | 0 | aRet = OUString( p.get(), nLeft, RTL_TEXTENCODING_MS_1252 ) + aRet; |
727 | 0 | } |
728 | 0 | } |
729 | | |
730 | 21.3k | return aRet; |
731 | 21.3k | } |
732 | | |
733 | | double Erf( double x ) |
734 | 4 | { |
735 | 4 | return std::erf(x); |
736 | 4 | } |
737 | | |
738 | | double Erfc( double x ) |
739 | 2 | { |
740 | 2 | return std::erfc(x); |
741 | 2 | } |
742 | | |
743 | | static bool IsNum( sal_Unicode c ) |
744 | 116 | { |
745 | 116 | return c >= '0' && c <= '9'; |
746 | 116 | } |
747 | | |
748 | | |
749 | | static bool IsComma( sal_Unicode c ) |
750 | 28 | { |
751 | 28 | return c == '.' || c == ','; |
752 | 28 | } |
753 | | |
754 | | |
755 | | static bool IsExpStart( sal_Unicode c ) |
756 | 28 | { |
757 | 28 | return c == 'e' || c == 'E'; |
758 | 28 | } |
759 | | |
760 | | |
761 | | static bool IsImagUnit( sal_Unicode c ) |
762 | 0 | { |
763 | 0 | return c == 'i' || c == 'j'; |
764 | 0 | } |
765 | | |
766 | | |
767 | | static sal_uInt16 GetVal( sal_Unicode c ) |
768 | 84 | { |
769 | 84 | return sal_uInt16( c - '0' ); |
770 | 84 | } |
771 | | |
772 | | |
773 | | bool ParseDouble( const sal_Unicode*& rp, double& rRet ) |
774 | 28 | { |
775 | 28 | double fInt = 0.0; |
776 | 28 | double fFrac = 0.0; |
777 | 28 | double fMult = 0.1; // multiplier to multiply digits with, when adding fractional ones |
778 | 28 | sal_Int32 nExp = 0; |
779 | 28 | sal_Int32 nMaxExp = 307; |
780 | 28 | sal_uInt16 nDigCnt = 18; // max. number of digits to read in, rest doesn't matter |
781 | | |
782 | 28 | enum State { S_End, S_Sign, S_IntStart, S_Int, S_IgnoreIntDigs, S_Frac, S_IgnoreFracDigs, S_ExpSign, S_Exp }; |
783 | | |
784 | 28 | State eS = S_Sign; |
785 | | |
786 | 28 | bool bNegNum = false; |
787 | 28 | bool bNegExp = false; |
788 | | |
789 | 28 | const sal_Unicode* p = rp; |
790 | 28 | sal_Unicode c; |
791 | | |
792 | 144 | while( eS != S_End ) |
793 | 116 | { |
794 | 116 | c = *p; |
795 | 116 | switch( eS ) |
796 | 116 | { |
797 | 28 | case S_Sign: |
798 | 28 | if( IsNum( c ) ) |
799 | 28 | { |
800 | 28 | fInt = GetVal( c ); |
801 | 28 | nDigCnt--; |
802 | 28 | eS = S_Int; |
803 | 28 | } |
804 | 0 | else if( c == '-' ) |
805 | 0 | { |
806 | 0 | bNegNum = true; |
807 | 0 | eS = S_IntStart; |
808 | 0 | } |
809 | 0 | else if( c == '+' ) |
810 | 0 | eS = S_IntStart; |
811 | 0 | else if( IsComma( c ) ) |
812 | 0 | eS = S_Frac; |
813 | 0 | else |
814 | 0 | return false; |
815 | 28 | break; |
816 | 28 | case S_IntStart: |
817 | 0 | if( IsNum( c ) ) |
818 | 0 | { |
819 | 0 | fInt = GetVal( c ); |
820 | 0 | nDigCnt--; |
821 | 0 | eS = S_Int; |
822 | 0 | } |
823 | 0 | else if( IsComma( c ) ) |
824 | 0 | eS = S_Frac; |
825 | 0 | else if( IsImagUnit( c ) ) |
826 | 0 | { |
827 | 0 | rRet = 0.0; |
828 | 0 | return true; |
829 | 0 | } |
830 | 0 | else |
831 | 0 | return false; |
832 | 0 | break; |
833 | 28 | case S_Int: |
834 | 28 | if( IsNum( c ) ) |
835 | 0 | { |
836 | 0 | fInt *= 10.0; |
837 | 0 | fInt += double( GetVal( c ) ); |
838 | 0 | nDigCnt--; |
839 | 0 | if( !nDigCnt ) |
840 | 0 | eS = S_IgnoreIntDigs; |
841 | 0 | } |
842 | 28 | else if( IsComma( c ) ) |
843 | 4 | eS = S_Frac; |
844 | 24 | else if( IsExpStart( c ) ) |
845 | 0 | eS = S_ExpSign; |
846 | 24 | else |
847 | 24 | eS = S_End; |
848 | 28 | break; |
849 | 0 | case S_IgnoreIntDigs: |
850 | 0 | if( IsNum( c ) ) |
851 | 0 | nExp++; // just multiply num with 10... ;-) |
852 | 0 | else if( IsComma( c ) ) |
853 | 0 | eS = S_Frac; |
854 | 0 | else if( IsExpStart( c ) ) |
855 | 0 | eS = S_ExpSign; |
856 | 0 | else |
857 | 0 | eS = S_End; |
858 | 0 | break; |
859 | 60 | case S_Frac: |
860 | 60 | if( IsNum( c ) ) |
861 | 56 | { |
862 | 56 | fFrac += double( GetVal( c ) ) * fMult; |
863 | 56 | nDigCnt--; |
864 | 56 | if( nDigCnt ) |
865 | 56 | fMult *= 0.1; |
866 | 0 | else |
867 | 0 | eS = S_IgnoreFracDigs; |
868 | 56 | } |
869 | 4 | else if( IsExpStart( c ) ) |
870 | 0 | eS = S_ExpSign; |
871 | 4 | else |
872 | 4 | eS = S_End; |
873 | 60 | break; |
874 | 0 | case S_IgnoreFracDigs: |
875 | 0 | if( IsExpStart( c ) ) |
876 | 0 | eS = S_ExpSign; |
877 | 0 | else if( !IsNum( c ) ) |
878 | 0 | eS = S_End; |
879 | 0 | break; |
880 | 0 | case S_ExpSign: |
881 | 0 | if( IsNum( c ) ) |
882 | 0 | { |
883 | 0 | nExp = GetVal( c ); |
884 | 0 | eS = S_Exp; |
885 | 0 | } |
886 | 0 | else if( c == '-' ) |
887 | 0 | { |
888 | 0 | bNegExp = true; |
889 | 0 | eS = S_Exp; |
890 | 0 | } |
891 | 0 | else if( c != '+' ) |
892 | 0 | eS = S_End; |
893 | 0 | break; |
894 | 0 | case S_Exp: |
895 | 0 | if( IsNum( c ) ) |
896 | 0 | { |
897 | 0 | nExp *= 10; |
898 | 0 | nExp += GetVal( c ); |
899 | 0 | if( nExp > nMaxExp ) |
900 | 0 | return false; |
901 | 0 | } |
902 | 0 | else |
903 | 0 | eS = S_End; |
904 | 0 | break; |
905 | | // coverity[dead_error_begin] - following conditions exist to avoid compiler warning |
906 | 0 | case S_End: |
907 | 0 | break; |
908 | 116 | } |
909 | | |
910 | 116 | p++; |
911 | 116 | } |
912 | | |
913 | 28 | p--; // set pointer back to last |
914 | 28 | rp = p; |
915 | | |
916 | 28 | fInt += fFrac; |
917 | | |
918 | 28 | if (fInt != 0.0) // exact check; log10(0.0) may entail a pole error |
919 | 28 | { |
920 | 28 | sal_Int32 nLog10 = sal_Int32( log10( fInt ) ); |
921 | | |
922 | 28 | if( bNegExp ) |
923 | 0 | nExp = -nExp; |
924 | | |
925 | 28 | if( nLog10 + nExp > nMaxExp ) |
926 | 0 | return false; |
927 | | |
928 | 28 | fInt = ::rtl::math::pow10Exp( fInt, nExp ); |
929 | 28 | } |
930 | | |
931 | 28 | if( bNegNum ) |
932 | 0 | fInt = -fInt; |
933 | | |
934 | 28 | rRet = fInt; |
935 | | |
936 | 28 | return true; |
937 | 28 | } |
938 | | |
939 | | |
940 | | OUString GetString( double f, bool bLeadingSign, sal_uInt16 nMaxDig ) |
941 | 28 | { |
942 | 28 | const int nBuff = 256; |
943 | 28 | char aBuff[ nBuff + 1 ]; |
944 | 28 | const char* pFormStr = bLeadingSign? "%+.*g" : "%.*g"; |
945 | 28 | int nLen = snprintf( aBuff, nBuff, pFormStr, int( nMaxDig ), f ); |
946 | | // you never know which underlying implementation you get ... |
947 | 28 | aBuff[nBuff] = 0; |
948 | 28 | if ( nLen < 0 || nLen > nBuff ) |
949 | 0 | nLen = strlen( aBuff ); |
950 | | |
951 | 28 | OUString aRet( aBuff, nLen, RTL_TEXTENCODING_MS_1252 ); |
952 | | |
953 | 28 | return aRet; |
954 | 28 | } |
955 | | |
956 | | |
957 | | double GetAmordegrc( sal_Int32 nNullDate, double fCost, sal_Int32 nDate, sal_Int32 nFirstPer, |
958 | | double fRestVal, double fPer, double fRate, sal_Int32 nBase ) |
959 | 0 | { |
960 | 0 | sal_uInt32 nPer = sal_uInt32( fPer ); |
961 | 0 | double fUsePer = 1.0 / fRate; |
962 | 0 | double fAmorCoeff; |
963 | |
|
964 | 0 | if( fUsePer < 3.0 ) |
965 | 0 | fAmorCoeff = 1.0; |
966 | 0 | else if( fUsePer < 5.0 ) |
967 | 0 | fAmorCoeff = 1.5; |
968 | 0 | else if( fUsePer <= 6.0 ) |
969 | 0 | fAmorCoeff = 2.0; |
970 | 0 | else |
971 | 0 | fAmorCoeff = 2.5; |
972 | |
|
973 | 0 | fRate *= fAmorCoeff; |
974 | 0 | double fNRate = ::rtl::math::round( GetYearFrac( nNullDate, nDate, nFirstPer, nBase ) * fRate * fCost ); |
975 | 0 | fCost -= fNRate; |
976 | 0 | double fRest = fCost - fRestVal; // aboriginal cost - residual value - sum of all write-downs |
977 | |
|
978 | 0 | for( sal_uInt32 n = 0 ; n < nPer ; n++ ) |
979 | 0 | { |
980 | 0 | fNRate = ::rtl::math::round( fRate * fCost ); |
981 | 0 | fRest -= fNRate; |
982 | |
|
983 | 0 | if( fRest < 0.0 ) |
984 | 0 | { |
985 | 0 | switch( nPer - n ) |
986 | 0 | { |
987 | 0 | case 0: |
988 | 0 | case 1: |
989 | 0 | return ::rtl::math::round( fCost * 0.5 ); |
990 | 0 | default: |
991 | 0 | return 0.0; |
992 | 0 | } |
993 | 0 | } |
994 | | |
995 | 0 | fCost -= fNRate; |
996 | 0 | } |
997 | | |
998 | 0 | return fNRate; |
999 | 0 | } |
1000 | | |
1001 | | |
1002 | | double GetAmorlinc( sal_Int32 nNullDate, double fCost, sal_Int32 nDate, sal_Int32 nFirstPer, |
1003 | | double fRestVal, double fPer, double fRate, sal_Int32 nBase ) |
1004 | 0 | { |
1005 | 0 | sal_uInt32 nPer = sal_uInt32( fPer ); |
1006 | 0 | double fOneRate = fCost * fRate; |
1007 | 0 | double fCostDelta = fCost - fRestVal; |
1008 | 0 | double f0Rate = GetYearFrac( nNullDate, nDate, nFirstPer, nBase ) * fRate * fCost; |
1009 | 0 | sal_uInt32 nNumOfFullPeriods = sal_uInt32( ( fCost - fRestVal - f0Rate) / fOneRate ); |
1010 | |
|
1011 | 0 | double fResult = 0.0; |
1012 | 0 | if( nPer == 0 ) |
1013 | 0 | fResult = f0Rate; |
1014 | 0 | else if( nPer <= nNumOfFullPeriods ) |
1015 | 0 | fResult = fOneRate; |
1016 | 0 | else if( nPer == nNumOfFullPeriods + 1 ) |
1017 | 0 | fResult = fCostDelta - fOneRate * nNumOfFullPeriods - f0Rate; |
1018 | |
|
1019 | 0 | if ( fResult > 0.0 ) |
1020 | 0 | return fResult; |
1021 | 0 | else |
1022 | 0 | return 0.0; |
1023 | 0 | } |
1024 | | |
1025 | | |
1026 | | double GetDuration( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, double fCoup, |
1027 | | double fYield, sal_Int32 nFreq, sal_Int32 nBase ) |
1028 | 4 | { |
1029 | 4 | double fYearfrac = GetYearFrac( nNullDate, nSettle, nMat, nBase ); |
1030 | 4 | double fNumOfCoups = GetCoupnum( nNullDate, nSettle, nMat, nFreq, nBase ); |
1031 | 4 | double fDur = 0.0; |
1032 | 4 | const double f100 = 100.0; |
1033 | 4 | fCoup *= f100 / double( nFreq ); // fCoup is used as cash flow |
1034 | 4 | fYield /= nFreq; |
1035 | 4 | fYield += 1.0; |
1036 | | |
1037 | 4 | double nDiff = fYearfrac * nFreq - fNumOfCoups; |
1038 | | |
1039 | 4 | double t; |
1040 | | |
1041 | 80 | for( t = 1.0 ; t < fNumOfCoups ; t++ ) |
1042 | 76 | fDur += ( t + nDiff ) * fCoup / pow( fYield, t + nDiff ); |
1043 | | |
1044 | 4 | fDur += ( fNumOfCoups + nDiff ) * ( fCoup + f100 ) / pow( fYield, fNumOfCoups + nDiff ); |
1045 | | |
1046 | 4 | double p = 0.0; |
1047 | 80 | for( t = 1.0 ; t < fNumOfCoups ; t++ ) |
1048 | 76 | p += fCoup / pow( fYield, t + nDiff ); |
1049 | | |
1050 | 4 | p += ( fCoup + f100 ) / pow( fYield, fNumOfCoups + nDiff ); |
1051 | | |
1052 | 4 | fDur /= p; |
1053 | 4 | fDur /= double( nFreq ); |
1054 | | |
1055 | 4 | return fDur; |
1056 | 4 | } |
1057 | | |
1058 | | |
1059 | | double GetYieldmat( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nIssue, |
1060 | | double fRate, double fPrice, sal_Int32 nBase ) |
1061 | 0 | { |
1062 | 0 | double fIssMat = GetYearFrac( nNullDate, nIssue, nMat, nBase ); |
1063 | 0 | double fIssSet = GetYearFrac( nNullDate, nIssue, nSettle, nBase ); |
1064 | 0 | double fSetMat = GetYearFrac( nNullDate, nSettle, nMat, nBase ); |
1065 | |
|
1066 | 0 | double y = 1.0 + fIssMat * fRate; |
1067 | 0 | y /= fPrice / 100.0 + fIssSet * fRate; |
1068 | 0 | y--; |
1069 | 0 | return o3tl::div_allow_zero(y, fSetMat); |
1070 | 0 | } |
1071 | | |
1072 | | |
1073 | | double GetOddfprice( sal_Int32 /*nNullDate*/, sal_Int32 /*nSettle*/, sal_Int32 /*nMat*/, sal_Int32 /*nIssue*/, |
1074 | | sal_Int32 /*nFirstCoup*/, double /*fRate*/, double /*fYield*/, double /*fRedemp*/, sal_Int32 /*nFreq*/, |
1075 | | sal_Int32 /*nBase*/ ) |
1076 | 0 | { |
1077 | | // If you change this to not unconditionally throw, the |
1078 | | // SAL_WNOUNREACHABLE_CODE_PUSH/POP around the caller in |
1079 | | // financial.cxx can be removed. |
1080 | 0 | throw uno::RuntimeException(); |
1081 | 0 | } |
1082 | | |
1083 | | |
1084 | | double getYield_( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, double fCoup, double fPrice, |
1085 | | double fRedemp, sal_Int32 nFreq, sal_Int32 nBase ) |
1086 | 0 | { |
1087 | 0 | double fRate = fCoup; |
1088 | 0 | double fPriceN = 0.0; |
1089 | 0 | double fYield1 = 0.0; |
1090 | 0 | double fYield2 = 1.0; |
1091 | 0 | double fPrice1 = getPrice_( nNullDate, nSettle, nMat, fRate, fYield1, fRedemp, nFreq, nBase ); |
1092 | 0 | double fPrice2 = getPrice_( nNullDate, nSettle, nMat, fRate, fYield2, fRedemp, nFreq, nBase ); |
1093 | 0 | double fYieldN = ( fYield2 - fYield1 ) * 0.5; |
1094 | |
|
1095 | 0 | for( sal_uInt32 nIter = 0 ; nIter < 100 && !rtl::math::approxEqual(fPriceN, fPrice) ; nIter++ ) |
1096 | 0 | { |
1097 | 0 | fPriceN = getPrice_( nNullDate, nSettle, nMat, fRate, fYieldN, fRedemp, nFreq, nBase ); |
1098 | |
|
1099 | 0 | if( rtl::math::approxEqual(fPrice, fPrice1) ) |
1100 | 0 | return fYield1; |
1101 | 0 | else if( rtl::math::approxEqual(fPrice, fPrice2) ) |
1102 | 0 | return fYield2; |
1103 | 0 | else if( rtl::math::approxEqual(fPrice, fPriceN) ) |
1104 | 0 | return fYieldN; |
1105 | 0 | else if( fPrice < fPrice2 ) |
1106 | 0 | { |
1107 | 0 | fYield2 *= 2.0; |
1108 | 0 | fPrice2 = getPrice_( nNullDate, nSettle, nMat, fRate, fYield2, fRedemp, nFreq, nBase ); |
1109 | |
|
1110 | 0 | fYieldN = ( fYield2 - fYield1 ) * 0.5; |
1111 | 0 | } |
1112 | 0 | else |
1113 | 0 | { |
1114 | 0 | if( fPrice < fPriceN ) |
1115 | 0 | { |
1116 | 0 | fYield1 = fYieldN; |
1117 | 0 | fPrice1 = fPriceN; |
1118 | 0 | } |
1119 | 0 | else |
1120 | 0 | { |
1121 | 0 | fYield2 = fYieldN; |
1122 | 0 | fPrice2 = fPriceN; |
1123 | 0 | } |
1124 | |
|
1125 | 0 | fYieldN = fYield2 - ( fYield2 - fYield1 ) * ( ( fPrice - fPrice2 ) / ( fPrice1 - fPrice2 ) ); |
1126 | 0 | } |
1127 | 0 | } |
1128 | | |
1129 | 0 | if( fabs( fPrice - fPriceN ) > fPrice / 100.0 ) |
1130 | 0 | throw lang::IllegalArgumentException(); // result not precise enough |
1131 | | |
1132 | 0 | return fYieldN; |
1133 | 0 | } |
1134 | | |
1135 | | |
1136 | | double getPrice_( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, double fRate, double fYield, |
1137 | | double fRedemp, sal_Int32 nFreq, sal_Int32 nBase ) |
1138 | 0 | { |
1139 | 0 | double fFreq = nFreq; |
1140 | |
|
1141 | 0 | double fE = GetCoupdays( nNullDate, nSettle, nMat, nFreq, nBase ); |
1142 | 0 | double fDSC_E = GetCoupdaysnc( nNullDate, nSettle, nMat, nFreq, nBase ) / fE; |
1143 | 0 | double fN = GetCoupnum( nNullDate, nSettle, nMat, nFreq, nBase ); |
1144 | 0 | double fA = GetCoupdaybs( nNullDate, nSettle, nMat, nFreq, nBase ); |
1145 | |
|
1146 | 0 | double fRet = fRedemp / ( pow( 1.0 + fYield / fFreq, fN - 1.0 + fDSC_E ) ); |
1147 | 0 | fRet -= 100.0 * fRate / fFreq * fA / fE; |
1148 | |
|
1149 | 0 | double fT1 = 100.0 * fRate / fFreq; |
1150 | 0 | double fT2 = 1.0 + fYield / fFreq; |
1151 | |
|
1152 | 0 | for( double fK = 0.0 ; fK < fN ; fK++ ) |
1153 | 0 | fRet += fT1 / pow( fT2, fK + fDSC_E ); |
1154 | |
|
1155 | 0 | return fRet; |
1156 | 0 | } |
1157 | | |
1158 | | |
1159 | | double GetOddfyield( sal_Int32 /*nNullDate*/, sal_Int32 /*nSettle*/, sal_Int32 /*nMat*/, sal_Int32 /*nIssue*/, |
1160 | | sal_Int32 /*nFirstCoup*/, double /*fRate*/, double /*fPrice*/, double /*fRedemp*/, sal_Int32 /*nFreq*/, |
1161 | | sal_Int32 /*nBase*/ ) |
1162 | 0 | { |
1163 | | // If you change this to not unconditionally throw, the |
1164 | | // SAL_WNOUNREACHABLE_CODE_PUSH/POP around the caller in |
1165 | | // financial.cxx can be removed. |
1166 | 0 | throw uno::RuntimeException(); |
1167 | 0 | } |
1168 | | |
1169 | | |
1170 | | double GetOddlprice( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nLastCoup, |
1171 | | double fRate, double fYield, double fRedemp, sal_Int32 nFreq, sal_Int32 nBase ) |
1172 | 0 | { |
1173 | 0 | double fFreq = double( nFreq ); |
1174 | 0 | double fDCi = GetYearFrac( nNullDate, nLastCoup, nMat, nBase ) * fFreq; |
1175 | 0 | double fDSCi = GetYearFrac( nNullDate, nSettle, nMat, nBase ) * fFreq; |
1176 | 0 | double fAi = GetYearFrac( nNullDate, nLastCoup, nSettle, nBase ) * fFreq; |
1177 | |
|
1178 | 0 | double p = fRedemp + fDCi * 100.0 * fRate / fFreq; |
1179 | 0 | p /= fDSCi * fYield / fFreq + 1.0; |
1180 | 0 | p -= fAi * 100.0 * fRate / fFreq; |
1181 | |
|
1182 | 0 | return p; |
1183 | 0 | } |
1184 | | |
1185 | | |
1186 | | double GetOddlyield( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nLastCoup, |
1187 | | double fRate, double fPrice, double fRedemp, sal_Int32 nFreq, sal_Int32 nBase ) |
1188 | 0 | { |
1189 | 0 | double fFreq = double( nFreq ); |
1190 | 0 | double fDCi = GetYearFrac( nNullDate, nLastCoup, nMat, nBase ) * fFreq; |
1191 | 0 | double fDSCi = GetYearFrac( nNullDate, nSettle, nMat, nBase ) * fFreq; |
1192 | 0 | double fAi = GetYearFrac( nNullDate, nLastCoup, nSettle, nBase ) * fFreq; |
1193 | |
|
1194 | 0 | double y = fRedemp + fDCi * 100.0 * fRate / fFreq; |
1195 | 0 | y /= fPrice + fAi * 100.0 * fRate / fFreq; |
1196 | 0 | y--; |
1197 | 0 | return y * o3tl::div_allow_zero(fFreq, fDSCi); |
1198 | 0 | } |
1199 | | |
1200 | | |
1201 | | double GetPmt( double fRate, double fNper, double fPv, double fFv, sal_Int32 nPayType ) |
1202 | 0 | { |
1203 | 0 | double fPmt; |
1204 | 0 | if( fRate == 0.0 ) |
1205 | 0 | fPmt = ( fPv + fFv ) / fNper; |
1206 | 0 | else |
1207 | 0 | { |
1208 | 0 | double fTerm = pow( 1.0 + fRate, fNper ); |
1209 | 0 | if( nPayType > 0 ) |
1210 | 0 | fPmt = ( fFv * fRate / ( fTerm - 1.0 ) + fPv * fRate / ( 1.0 - 1.0 / fTerm ) ) / ( 1.0 + fRate ); |
1211 | 0 | else |
1212 | 0 | fPmt = fFv * fRate / ( fTerm - 1.0 ) + fPv * fRate / ( 1.0 - 1.0 / fTerm ); |
1213 | 0 | } |
1214 | |
|
1215 | 0 | return -fPmt; |
1216 | 0 | } |
1217 | | |
1218 | | |
1219 | | double GetFv( double fRate, double fNper, double fPmt, double fPv, sal_Int32 nPayType ) |
1220 | 0 | { |
1221 | 0 | double fFv; |
1222 | 0 | if( fRate == 0.0 ) |
1223 | 0 | fFv = fPv + fPmt * fNper; |
1224 | 0 | else |
1225 | 0 | { |
1226 | 0 | double fTerm = pow( 1.0 + fRate, fNper ); |
1227 | 0 | if( nPayType > 0 ) |
1228 | 0 | fFv = fPv * fTerm + fPmt * ( 1.0 + fRate ) * ( fTerm - 1.0 ) / fRate; |
1229 | 0 | else |
1230 | 0 | fFv = fPv * fTerm + fPmt * ( fTerm - 1.0 ) / fRate; |
1231 | 0 | } |
1232 | |
|
1233 | 0 | return -fFv; |
1234 | 0 | } |
1235 | | |
1236 | | // financial functions COUP*** |
1237 | | |
1238 | | // COUPPCD: find last coupon date before settlement (can be equal to settlement) |
1239 | | /// @throws css::lang::IllegalArgumentException |
1240 | | static void lcl_GetCouppcd( ScaDate& rDate, const ScaDate& rSettle, const ScaDate& rMat, sal_Int32 nFreq ) |
1241 | 4 | { |
1242 | 4 | rDate = rMat; |
1243 | 4 | rDate.setYear( rSettle.getYear() ); |
1244 | 4 | if( rDate < rSettle ) |
1245 | 0 | rDate.addYears( 1 ); |
1246 | 4 | while( rDate > rSettle ) |
1247 | 0 | rDate.addMonths( -12 / nFreq ); |
1248 | 4 | } |
1249 | | |
1250 | | double GetCouppcd( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nFreq, sal_Int32 nBase ) |
1251 | 0 | { |
1252 | 0 | if( nSettle >= nMat || isFreqInvalid(nFreq) ) |
1253 | 0 | throw lang::IllegalArgumentException(); |
1254 | | |
1255 | 0 | ScaDate aDate; |
1256 | 0 | lcl_GetCouppcd( aDate, ScaDate( nNullDate, nSettle, nBase ), ScaDate( nNullDate, nMat, nBase ), nFreq ); |
1257 | 0 | return aDate.getDate( nNullDate ); |
1258 | 0 | } |
1259 | | |
1260 | | // COUPNCD: find first coupon date after settlement (is never equal to settlement) |
1261 | | /// @throws css::lang::IllegalArgumentException |
1262 | | static void lcl_GetCoupncd( ScaDate& rDate, const ScaDate& rSettle, const ScaDate& rMat, sal_Int32 nFreq ) |
1263 | 0 | { |
1264 | 0 | rDate = rMat; |
1265 | 0 | rDate.setYear( rSettle.getYear() ); |
1266 | 0 | if( rDate > rSettle ) |
1267 | 0 | rDate.addYears( -1 ); |
1268 | 0 | while( rDate <= rSettle ) |
1269 | 0 | rDate.addMonths( 12 / nFreq ); |
1270 | 0 | } |
1271 | | |
1272 | | double GetCoupncd( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nFreq, sal_Int32 nBase ) |
1273 | 0 | { |
1274 | 0 | if( nSettle >= nMat || isFreqInvalid(nFreq) ) |
1275 | 0 | throw lang::IllegalArgumentException(); |
1276 | | |
1277 | 0 | ScaDate aDate; |
1278 | 0 | lcl_GetCoupncd( aDate, ScaDate( nNullDate, nSettle, nBase ), ScaDate( nNullDate, nMat, nBase ), nFreq ); |
1279 | 0 | return aDate.getDate( nNullDate ); |
1280 | 0 | } |
1281 | | |
1282 | | // COUPDAYBS: get day count: coupon date before settlement <-> settlement |
1283 | | double GetCoupdaybs( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nFreq, sal_Int32 nBase ) |
1284 | 0 | { |
1285 | 0 | if( nSettle >= nMat || isFreqInvalid(nFreq) ) |
1286 | 0 | throw lang::IllegalArgumentException(); |
1287 | | |
1288 | 0 | ScaDate aSettle( nNullDate, nSettle, nBase ); |
1289 | 0 | ScaDate aDate; |
1290 | 0 | lcl_GetCouppcd( aDate, aSettle, ScaDate( nNullDate, nMat, nBase ), nFreq ); |
1291 | 0 | return ScaDate::getDiff( aDate, aSettle ); |
1292 | 0 | } |
1293 | | |
1294 | | // COUPDAYSNC: get day count: settlement <-> coupon date after settlement |
1295 | | double GetCoupdaysnc( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nFreq, sal_Int32 nBase ) |
1296 | 0 | { |
1297 | 0 | if( nSettle >= nMat || isFreqInvalid(nFreq) ) |
1298 | 0 | throw lang::IllegalArgumentException(); |
1299 | | |
1300 | 0 | if( (nBase != 0) && (nBase != 4) ) |
1301 | 0 | { |
1302 | 0 | ScaDate aSettle( nNullDate, nSettle, nBase ); |
1303 | 0 | ScaDate aDate; |
1304 | 0 | lcl_GetCoupncd( aDate, aSettle, ScaDate( nNullDate, nMat, nBase ), nFreq ); |
1305 | 0 | return ScaDate::getDiff( aSettle, aDate ); |
1306 | 0 | } |
1307 | 0 | return GetCoupdays( nNullDate, nSettle, nMat, nFreq, nBase ) - GetCoupdaybs( nNullDate, nSettle, nMat, nFreq, nBase ); |
1308 | 0 | } |
1309 | | |
1310 | | // COUPDAYS: get day count: coupon date before settlement <-> coupon date after settlement |
1311 | | double GetCoupdays( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nFreq, sal_Int32 nBase ) |
1312 | 0 | { |
1313 | 0 | if( nSettle >= nMat || isFreqInvalid(nFreq) ) |
1314 | 0 | throw lang::IllegalArgumentException(); |
1315 | | |
1316 | 0 | if( nBase == 1 ) |
1317 | 0 | { |
1318 | 0 | ScaDate aDate; |
1319 | 0 | lcl_GetCouppcd( aDate, ScaDate( nNullDate, nSettle, nBase ), ScaDate( nNullDate, nMat, nBase ), nFreq ); |
1320 | 0 | ScaDate aNextDate( aDate ); |
1321 | 0 | aNextDate.addMonths( 12 / nFreq ); |
1322 | 0 | return ScaDate::getDiff( aDate, aNextDate ); |
1323 | 0 | } |
1324 | 0 | return static_cast< double >( GetDaysInYear( 0, 0, nBase ) ) / nFreq; |
1325 | 0 | } |
1326 | | |
1327 | | // COUPNUM: get count of coupon dates |
1328 | | double GetCoupnum( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nFreq, sal_Int32 nBase ) |
1329 | 4 | { |
1330 | 4 | if( nSettle >= nMat || isFreqInvalid(nFreq) ) |
1331 | 0 | throw lang::IllegalArgumentException(); |
1332 | | |
1333 | 4 | ScaDate aMat( nNullDate, nMat, nBase ); |
1334 | 4 | ScaDate aDate; |
1335 | 4 | lcl_GetCouppcd( aDate, ScaDate( nNullDate, nSettle, nBase ), aMat, nFreq ); |
1336 | 4 | sal_uInt16 nMonths = (aMat.getYear() - aDate.getYear()) * 12 + aMat.getMonth() - aDate.getMonth(); |
1337 | 4 | return static_cast< double >( nMonths * nFreq / 12 ); |
1338 | 4 | } |
1339 | | |
1340 | | FuncData::FuncData(const FuncDataBase& r) : |
1341 | 1.01k | aIntName( OUString::createFromAscii( r.pIntName ) ), |
1342 | 1.01k | pUINameID( r.pUINameID ), |
1343 | 1.01k | pDescrID( r.pDescrID ), |
1344 | 1.01k | bDouble( r.bDouble ), |
1345 | 1.01k | bWithOpt( r.bWithOpt ), |
1346 | 1.01k | nParam( r.nNumOfParams ), |
1347 | 1.01k | eCat( r.eCat ) |
1348 | 1.01k | { |
1349 | 1.01k | if (r.pSuffix) |
1350 | 40 | aSuffix = OUString::createFromAscii(r.pSuffix); |
1351 | | |
1352 | 1.01k | aCompList.resize(2); |
1353 | 1.01k | aCompList[0] = OUString(r.pCompListID[0], strlen(r.pCompListID[0]), RTL_TEXTENCODING_UTF8); |
1354 | 1.01k | aCompList[1] = OUString(r.pCompListID[1], strlen(r.pCompListID[1]), RTL_TEXTENCODING_UTF8); |
1355 | 1.01k | } |
1356 | | |
1357 | | sal_uInt16 FuncData::GetStrIndex( sal_uInt16 nParamNum ) const |
1358 | 2.91k | { |
1359 | 2.91k | if( !bWithOpt ) |
1360 | 850 | nParamNum++; |
1361 | | |
1362 | 2.91k | if( nParamNum > nParam ) |
1363 | 50 | return nParam * 2; |
1364 | 2.86k | else |
1365 | 2.86k | return nParamNum * 2; |
1366 | 2.91k | } |
1367 | | |
1368 | | void InitFuncDataList(FuncDataList& rList) |
1369 | 10 | { |
1370 | 10 | for(const auto & rFuncData : pFuncDatas) |
1371 | 1.01k | rList.emplace_back(rFuncData); |
1372 | 10 | } |
1373 | | |
1374 | | SortedIndividualInt32List::SortedIndividualInt32List() |
1375 | 7 | { |
1376 | 7 | } |
1377 | | |
1378 | | |
1379 | | SortedIndividualInt32List::~SortedIndividualInt32List() |
1380 | 7 | { |
1381 | 7 | } |
1382 | | |
1383 | | |
1384 | | void SortedIndividualInt32List::Insert( sal_Int32 nDay ) |
1385 | 0 | { |
1386 | 0 | sal_uInt32 nIndex = Count(); |
1387 | 0 | while( nIndex ) |
1388 | 0 | { |
1389 | 0 | nIndex--; |
1390 | 0 | sal_Int32 nRef = Get( nIndex ); |
1391 | 0 | if( nDay == nRef ) |
1392 | 0 | return; |
1393 | 0 | else if( nDay > nRef ) |
1394 | 0 | { |
1395 | 0 | maVector.insert( maVector.begin() + nIndex + 1, nDay ); |
1396 | 0 | return; |
1397 | 0 | } |
1398 | 0 | } |
1399 | 0 | maVector.insert( maVector.begin(), nDay ); |
1400 | 0 | } |
1401 | | |
1402 | | |
1403 | | void SortedIndividualInt32List::Insert( sal_Int32 nDay, sal_Int32 nNullDate, bool bInsertOnWeekend ) |
1404 | 0 | { |
1405 | 0 | if( !nDay ) |
1406 | 0 | return; |
1407 | | |
1408 | 0 | nDay += nNullDate; |
1409 | 0 | if( bInsertOnWeekend || (GetDayOfWeek( nDay ) < 5) ) |
1410 | 0 | Insert( nDay ); |
1411 | 0 | } |
1412 | | |
1413 | | |
1414 | | void SortedIndividualInt32List::Insert( |
1415 | | double fDay, sal_Int32 nNullDate, bool bInsertOnWeekend ) |
1416 | 0 | { |
1417 | 0 | if( (fDay < -2147483648.0) || (fDay > 2147483649.0) ) |
1418 | 0 | throw lang::IllegalArgumentException(); |
1419 | 0 | Insert( static_cast< sal_Int32 >( fDay ), nNullDate, bInsertOnWeekend ); |
1420 | 0 | } |
1421 | | |
1422 | | |
1423 | | bool SortedIndividualInt32List::Find( sal_Int32 nVal ) const |
1424 | 84.3k | { |
1425 | 84.3k | sal_uInt32 nE = Count(); |
1426 | | |
1427 | 84.3k | if( !nE || nVal < Get( 0 ) || nVal > Get( nE - 1 ) ) |
1428 | 84.3k | return false; |
1429 | | |
1430 | | // linear search |
1431 | | |
1432 | 0 | for( sal_uInt32 n = 0 ; n < nE ; n++ ) |
1433 | 0 | { |
1434 | 0 | sal_Int32 nRef = Get( n ); |
1435 | |
|
1436 | 0 | if( nRef == nVal ) |
1437 | 0 | return true; |
1438 | 0 | else if( nRef > nVal ) |
1439 | 0 | return false; |
1440 | 0 | } |
1441 | 0 | return false; |
1442 | 0 | } |
1443 | | |
1444 | | |
1445 | | void SortedIndividualInt32List::InsertHolidayList( |
1446 | | const ScaAnyConverter& rAnyConv, |
1447 | | const uno::Any& rHolAny, |
1448 | | sal_Int32 nNullDate, |
1449 | | bool bInsertOnWeekend ) |
1450 | 7 | { |
1451 | 7 | double fDay; |
1452 | 7 | if( rAnyConv.getDouble( fDay, rHolAny ) ) |
1453 | 0 | Insert( fDay, nNullDate, bInsertOnWeekend ); |
1454 | 7 | } |
1455 | | |
1456 | | |
1457 | | void SortedIndividualInt32List::InsertHolidayList( |
1458 | | ScaAnyConverter& rAnyConv, |
1459 | | const uno::Reference< beans::XPropertySet >& xOptions, |
1460 | | const uno::Any& rHolAny, |
1461 | | sal_Int32 nNullDate ) |
1462 | 7 | { |
1463 | 7 | rAnyConv.init( xOptions ); |
1464 | 7 | if( rHolAny.getValueTypeClass() == uno::TypeClass_SEQUENCE ) |
1465 | 0 | { |
1466 | 0 | uno::Sequence< uno::Sequence< uno::Any > > aAnySeq; |
1467 | 0 | if( !(rHolAny >>= aAnySeq) ) |
1468 | 0 | throw lang::IllegalArgumentException(); |
1469 | | |
1470 | 0 | for (const uno::Sequence<uno::Any>& rSubSeq : aAnySeq) |
1471 | 0 | { |
1472 | 0 | for( const uno::Any& rAny : rSubSeq ) |
1473 | 0 | InsertHolidayList( rAnyConv, rAny, nNullDate, false/*bInsertOnWeekend*/ ); |
1474 | 0 | } |
1475 | 0 | } |
1476 | 7 | else |
1477 | 7 | InsertHolidayList( rAnyConv, rHolAny, nNullDate, false/*bInsertOnWeekend*/ ); |
1478 | 7 | } |
1479 | | |
1480 | | |
1481 | | void ScaDoubleList::Append( |
1482 | | const uno::Sequence< uno::Sequence< double > >& rValueSeq ) |
1483 | 4 | { |
1484 | 4 | for( const uno::Sequence< double >& rSubSeq : rValueSeq ) |
1485 | 20 | { |
1486 | 20 | for( const double fValue : rSubSeq ) |
1487 | 20 | Append( fValue ); |
1488 | 20 | } |
1489 | 4 | } |
1490 | | |
1491 | | |
1492 | | void ScaDoubleList::Append( |
1493 | | const uno::Sequence< uno::Sequence< sal_Int32 > >& rValueSeq ) |
1494 | 4 | { |
1495 | 4 | for( const uno::Sequence< sal_Int32 >& rSubSeq : rValueSeq ) |
1496 | 20 | { |
1497 | 20 | for( const sal_Int32 nValue : rSubSeq ) |
1498 | 20 | Append( nValue ); |
1499 | 20 | } |
1500 | 4 | } |
1501 | | |
1502 | | void ScaDoubleList::Append( |
1503 | | const ScaAnyConverter& rAnyConv, |
1504 | | const uno::Any& rAny, |
1505 | | bool bIgnoreEmpty ) |
1506 | 0 | { |
1507 | 0 | if( auto s = o3tl::tryAccess< |
1508 | 0 | css::uno::Sequence<css::uno::Sequence<css::uno::Any>>>(rAny) ) |
1509 | 0 | Append( rAnyConv, *s, bIgnoreEmpty ); |
1510 | 0 | else |
1511 | 0 | { |
1512 | 0 | double fValue; |
1513 | 0 | if( rAnyConv.getDouble( fValue, rAny ) ) |
1514 | 0 | Append( fValue ); |
1515 | 0 | else if( !bIgnoreEmpty ) |
1516 | 0 | Append( 0.0 ); |
1517 | 0 | } |
1518 | 0 | } |
1519 | | |
1520 | | |
1521 | | void ScaDoubleList::Append( |
1522 | | const ScaAnyConverter& rAnyConv, |
1523 | | const uno::Sequence< uno::Any >& rAnySeq, |
1524 | | bool bIgnoreEmpty ) |
1525 | 0 | { |
1526 | 0 | for( const uno::Any& rAny : rAnySeq ) |
1527 | 0 | Append( rAnyConv, rAny, bIgnoreEmpty ); |
1528 | 0 | } |
1529 | | |
1530 | | |
1531 | | void ScaDoubleList::Append( |
1532 | | const ScaAnyConverter& rAnyConv, |
1533 | | const uno::Sequence< uno::Sequence< uno::Any > >& rAnySeq, |
1534 | | bool bIgnoreEmpty ) |
1535 | 0 | { |
1536 | 0 | for( const uno::Sequence< uno::Any >& rArray : rAnySeq ) |
1537 | 0 | Append( rAnyConv, rArray, bIgnoreEmpty ); |
1538 | 0 | } |
1539 | | |
1540 | | void ScaDoubleList::Append( |
1541 | | ScaAnyConverter& rAnyConv, |
1542 | | const uno::Reference< beans::XPropertySet >& xOpt, |
1543 | | const uno::Sequence< uno::Any >& rAnySeq ) |
1544 | 0 | { |
1545 | 0 | rAnyConv.init( xOpt ); |
1546 | 0 | Append( rAnyConv, rAnySeq, true/*bIgnoreEmpty*/ ); |
1547 | 0 | } |
1548 | | |
1549 | | |
1550 | | bool ScaDoubleList::CheckInsert( double ) const |
1551 | 40 | { |
1552 | 40 | return true; |
1553 | 40 | } |
1554 | | |
1555 | | |
1556 | | bool ScaDoubleListGT0::CheckInsert( double fValue ) const |
1557 | 0 | { |
1558 | 0 | if( fValue < 0.0 ) |
1559 | 0 | throw lang::IllegalArgumentException(); |
1560 | 0 | return fValue > 0.0; |
1561 | 0 | } |
1562 | | |
1563 | | |
1564 | | bool ScaDoubleListGE0::CheckInsert( double fValue ) const |
1565 | 0 | { |
1566 | 0 | if( fValue < 0.0 ) |
1567 | 0 | throw lang::IllegalArgumentException(); |
1568 | 0 | return true; |
1569 | 0 | } |
1570 | | |
1571 | | |
1572 | | Complex::Complex( const OUString& rStr ) |
1573 | 28 | { |
1574 | 28 | if( !ParseString( rStr, *this ) ) |
1575 | 0 | throw lang::IllegalArgumentException(); |
1576 | 28 | } |
1577 | | |
1578 | | |
1579 | | inline bool Complex::IsImagUnit( sal_Unicode c ) |
1580 | 28 | { |
1581 | 28 | return c == 'i' || c == 'j'; |
1582 | 28 | } |
1583 | | |
1584 | | bool Complex::ParseString( const OUString& rStr, Complex& rCompl ) |
1585 | 28 | { |
1586 | 28 | rCompl.c = '\0'; // do not force a symbol, if only real part present |
1587 | | |
1588 | 28 | const sal_Unicode* pStr = rStr.getStr(); |
1589 | | |
1590 | 28 | if( IsImagUnit( *pStr ) && rStr.getLength() == 1) |
1591 | 0 | { |
1592 | 0 | rCompl.c = *pStr; |
1593 | 0 | rCompl.num = std::complex(0.0, 1.0); |
1594 | 0 | return true; |
1595 | 0 | } |
1596 | | |
1597 | 28 | double f; |
1598 | | |
1599 | 28 | if( !ParseDouble( pStr, f ) ) |
1600 | 0 | return false; |
1601 | | |
1602 | 28 | switch( *pStr ) |
1603 | 28 | { |
1604 | 0 | case '-': // imag part follows |
1605 | 0 | case '+': |
1606 | 0 | { |
1607 | 0 | double r = f; |
1608 | 0 | if( IsImagUnit( pStr[ 1 ] ) ) |
1609 | 0 | { |
1610 | 0 | rCompl.c = pStr[ 1 ]; |
1611 | 0 | if( pStr[ 2 ] == 0 ) |
1612 | 0 | { |
1613 | 0 | rCompl.num = std::complex(f, ( *pStr == '+' )? 1.0 : -1.0); |
1614 | 0 | return true; |
1615 | 0 | } |
1616 | 0 | } |
1617 | 0 | else if( ParseDouble( pStr, f ) && IsImagUnit( *pStr ) ) |
1618 | 0 | { |
1619 | 0 | rCompl.c = *pStr; |
1620 | 0 | pStr++; |
1621 | 0 | if( *pStr == 0 ) |
1622 | 0 | { |
1623 | 0 | rCompl.num = std::complex(r, f); |
1624 | 0 | return true; |
1625 | 0 | } |
1626 | 0 | } |
1627 | 0 | } |
1628 | 0 | break; |
1629 | 0 | case 'j': |
1630 | 0 | case 'i': |
1631 | 0 | rCompl.c = *pStr; |
1632 | 0 | pStr++; |
1633 | 0 | if( *pStr == 0 ) |
1634 | 0 | { |
1635 | 0 | rCompl.num = std::complex(0.0, f); |
1636 | 0 | return true; |
1637 | 0 | } |
1638 | 0 | break; |
1639 | 28 | case 0: // only real-part |
1640 | 28 | rCompl.num = std::complex(f, 0.0); |
1641 | 28 | return true; |
1642 | 28 | } |
1643 | | |
1644 | 0 | return false; |
1645 | 28 | } |
1646 | | |
1647 | | OUString Complex::GetString() const |
1648 | 28 | { |
1649 | 28 | finiteOrThrow(num.real()); |
1650 | 28 | finiteOrThrow(num.imag()); |
1651 | 28 | OUStringBuffer aRet; |
1652 | | |
1653 | 28 | bool bHasImag = num.imag() != 0.0; |
1654 | 28 | bool bHasReal = !bHasImag || (num.real() != 0.0); |
1655 | | |
1656 | 28 | if( bHasReal ) |
1657 | 28 | aRet.append(::GetString( num.real(), false )); |
1658 | 28 | if( bHasImag ) |
1659 | 0 | { |
1660 | 0 | if( num.imag() == 1.0 ) |
1661 | 0 | { |
1662 | 0 | if( bHasReal ) |
1663 | 0 | aRet.append('+'); |
1664 | 0 | } |
1665 | 0 | else if( num.imag() == -1.0 ) |
1666 | 0 | aRet.append('-'); |
1667 | 0 | else |
1668 | 0 | aRet.append(::GetString( num.imag(), bHasReal )); |
1669 | 0 | aRet.append((c != 'j') ? 'i' : 'j'); |
1670 | 0 | } |
1671 | | |
1672 | 28 | return aRet.makeStringAndClear(); |
1673 | 28 | } |
1674 | | |
1675 | | |
1676 | | double Complex::Arg() const |
1677 | 0 | { |
1678 | | // Note: there are differing opinions on whether arg(0) should be 0 or undefined, we are treating it as undefined |
1679 | 0 | if( num.real() == 0.0 && num.imag() == 0.0 ) |
1680 | 0 | throw lang::IllegalArgumentException(); |
1681 | 0 | return std::arg(num); |
1682 | 0 | } |
1683 | | |
1684 | | |
1685 | | void Complex::Power( double fPower ) |
1686 | 2 | { |
1687 | 2 | if( num.real() == 0.0 && num.imag() == 0.0 && fPower <= 0 ) |
1688 | 0 | throw lang::IllegalArgumentException(); |
1689 | 2 | num = std::pow(num, fPower); |
1690 | 2 | } |
1691 | | |
1692 | | |
1693 | | void Complex::Sqrt() |
1694 | 0 | { |
1695 | 0 | num = std::sqrt(num); |
1696 | 0 | } |
1697 | | |
1698 | | |
1699 | | void Complex::Sin() |
1700 | 3 | { |
1701 | 3 | if( !::rtl::math::isValidArcArg( num.real() ) ) |
1702 | 0 | throw lang::IllegalArgumentException(); |
1703 | 3 | num = std::sin(num); |
1704 | 3 | } |
1705 | | |
1706 | | |
1707 | | void Complex::Cos() |
1708 | 3 | { |
1709 | 3 | if( !::rtl::math::isValidArcArg( num.real() ) ) |
1710 | 0 | throw lang::IllegalArgumentException(); |
1711 | 3 | num = std::cos(num); |
1712 | 3 | } |
1713 | | |
1714 | | |
1715 | | void Complex::Div( const Complex& z ) |
1716 | 0 | { |
1717 | 0 | if( z.num.real() == 0 && z.num.imag() == 0 ) |
1718 | 0 | throw lang::IllegalArgumentException(); |
1719 | 0 | num = num / z.num; |
1720 | 0 | } |
1721 | | |
1722 | | |
1723 | | void Complex::Exp() |
1724 | 0 | { |
1725 | 0 | num = std::exp(num); |
1726 | 0 | } |
1727 | | |
1728 | | void Complex::Ln() |
1729 | 2 | { |
1730 | 2 | num = std::log(num); |
1731 | 2 | } |
1732 | | |
1733 | | |
1734 | | void Complex::Log10() |
1735 | 0 | { |
1736 | 0 | num = std::log10(num); |
1737 | 0 | } |
1738 | | |
1739 | | |
1740 | | void Complex::Log2() |
1741 | 2 | { |
1742 | 2 | Ln(); |
1743 | 2 | Mult( M_LOG2E ); |
1744 | 2 | } |
1745 | | |
1746 | | |
1747 | | void Complex::Tan() |
1748 | 6 | { |
1749 | | // using 2.0 * num.real/imag as a precaution because a) this is what our previous implementation did and |
1750 | | // b) the std::complex implementation may use cos(2x) etc, see the comment in isValidArcArg for details |
1751 | 6 | if ( ( num.imag() && !::rtl::math::isValidArcArg( 2.0 * num.real() ) ) |
1752 | 6 | || ( !num.imag() && !::rtl::math::isValidArcArg( num.real() ) ) ) |
1753 | 0 | throw lang::IllegalArgumentException(); |
1754 | 6 | num = std::tan(num); |
1755 | 6 | } |
1756 | | |
1757 | | |
1758 | | void Complex::Sec() |
1759 | 3 | { |
1760 | 3 | Cos(); |
1761 | 3 | num = 1.0 / num; |
1762 | 3 | } |
1763 | | |
1764 | | |
1765 | | void Complex::Csc() |
1766 | 3 | { |
1767 | 3 | Sin(); |
1768 | 3 | num = 1.0 / num; |
1769 | 3 | } |
1770 | | |
1771 | | |
1772 | | void Complex::Cot() |
1773 | 3 | { |
1774 | | |
1775 | 3 | Tan(); |
1776 | 3 | num = 1.0 / num; |
1777 | 3 | } |
1778 | | |
1779 | | |
1780 | | void Complex::Sinh() |
1781 | 6 | { |
1782 | 6 | if( !::rtl::math::isValidArcArg( num.imag() ) ) |
1783 | 0 | throw lang::IllegalArgumentException(); |
1784 | 6 | num = std::sinh(num); |
1785 | 6 | } |
1786 | | |
1787 | | |
1788 | | void Complex::Cosh() |
1789 | 6 | { |
1790 | 6 | if( !::rtl::math::isValidArcArg( num.imag() ) ) |
1791 | 0 | throw lang::IllegalArgumentException(); |
1792 | 6 | num = std::cosh(num); |
1793 | 6 | } |
1794 | | |
1795 | | |
1796 | | void Complex::Sech() |
1797 | 3 | { |
1798 | 3 | Cosh(); |
1799 | 3 | num = 1.0 / num; |
1800 | 3 | } |
1801 | | |
1802 | | |
1803 | | void Complex::Csch() |
1804 | 3 | { |
1805 | 3 | Sinh(); |
1806 | 3 | num = 1.0 / num; |
1807 | 3 | } |
1808 | | |
1809 | | |
1810 | | ComplexList::~ComplexList() |
1811 | 0 | { |
1812 | 0 | } |
1813 | | |
1814 | | |
1815 | | void ComplexList::Append( const uno::Sequence< uno::Sequence< OUString > >& r ) |
1816 | 0 | { |
1817 | 0 | for( const uno::Sequence< OUString >& rList : r ) |
1818 | 0 | { |
1819 | 0 | for( const OUString& rStr : rList ) |
1820 | 0 | { |
1821 | 0 | if( !rStr.isEmpty() ) |
1822 | 0 | Append( Complex( rStr ) ); |
1823 | 0 | } |
1824 | 0 | } |
1825 | 0 | } |
1826 | | |
1827 | | |
1828 | | void ComplexList::Append( const uno::Sequence< uno::Any >& aMultPars ) |
1829 | 0 | { |
1830 | 0 | for( const uno::Any& r : aMultPars ) |
1831 | 0 | { |
1832 | 0 | switch( r.getValueTypeClass() ) |
1833 | 0 | { |
1834 | 0 | case uno::TypeClass_VOID: break; |
1835 | 0 | case uno::TypeClass_STRING: |
1836 | 0 | { |
1837 | 0 | auto pStr = o3tl::forceAccess<OUString>(r); |
1838 | |
|
1839 | 0 | if( !pStr->isEmpty() ) |
1840 | 0 | Append( Complex( *pStr ) ); |
1841 | 0 | } |
1842 | 0 | break; |
1843 | 0 | case uno::TypeClass_DOUBLE: |
1844 | 0 | Append( Complex( *o3tl::forceAccess<double>(r), 0.0 ) ); |
1845 | 0 | break; |
1846 | 0 | case uno::TypeClass_SEQUENCE: |
1847 | 0 | { |
1848 | 0 | uno::Sequence< uno::Sequence< uno::Any > > aValArr; |
1849 | 0 | if( !(r >>= aValArr) ) |
1850 | 0 | throw lang::IllegalArgumentException(); |
1851 | | |
1852 | 0 | for (const uno::Sequence<uno::Any>& rArr : aValArr) |
1853 | 0 | Append( rArr ); |
1854 | 0 | } |
1855 | 0 | break; |
1856 | 0 | default: |
1857 | 0 | throw lang::IllegalArgumentException(); |
1858 | 0 | } |
1859 | 0 | } |
1860 | 0 | } |
1861 | | |
1862 | | ConvertData::ConvertData(std::u16string_view sUnitName, double fC, ConvertDataClass e, bool bPrefSupport) |
1863 | 146 | : fConst(fC) |
1864 | 146 | , aName(sUnitName) |
1865 | 146 | , eClass(e) |
1866 | 146 | , bPrefixSupport(bPrefSupport) |
1867 | 146 | { |
1868 | 146 | assert(!aName.empty()); |
1869 | 146 | } |
1870 | | |
1871 | 0 | ConvertData::~ConvertData() = default; |
1872 | | |
1873 | | sal_Int16 ConvertData::GetMatchingLevel( const OUString& rRef ) const |
1874 | 674 | { |
1875 | 674 | OUString aStr = rRef; |
1876 | 674 | if (sal_Int32 nIndex = rRef.lastIndexOf('^'); nIndex > 0 && nIndex == (rRef.getLength() - 2)) |
1877 | 0 | aStr = aStr.replaceAt(nIndex, 1, ""); |
1878 | 674 | if( aName == aStr ) |
1879 | 8 | return 0; |
1880 | 666 | if (std::u16string_view prefix; bPrefixSupport && aStr.endsWith(aName, &prefix)) |
1881 | 4 | { |
1882 | 4 | if (prefix.size() == 1 || prefix == u"da") |
1883 | 4 | { |
1884 | 4 | sal_Int16 n; |
1885 | 4 | switch (prefix[0]) |
1886 | 4 | { |
1887 | 0 | case 'y': n = -24; break; // yocto |
1888 | 0 | case 'z': n = -21; break; // zepto |
1889 | 0 | case 'a': n = -18; break; |
1890 | 0 | case 'f': n = -15; break; |
1891 | 0 | case 'p': n = -12; break; |
1892 | 0 | case 'n': n = -9; break; |
1893 | 0 | case 'u': n = -6; break; |
1894 | 0 | case 'm': n = -3; break; |
1895 | 0 | case 'c': n = -2; break; |
1896 | 0 | case 'd': |
1897 | 0 | if (prefix.size() == 1) |
1898 | 0 | n = -1; // deci |
1899 | 0 | else |
1900 | 0 | n = 1; // deca |
1901 | 0 | break; |
1902 | 0 | case 'e': n = 1; break; |
1903 | 0 | case 'h': n = 2; break; |
1904 | 4 | case 'k': n = 3; break; |
1905 | 0 | case 'M': n = 6; break; |
1906 | 0 | case 'G': n = 9; break; |
1907 | 0 | case 'T': n = 12; break; |
1908 | 0 | case 'P': n = 15; break; |
1909 | 0 | case 'E': n = 18; break; |
1910 | 0 | case 'Z': n = 21; break; // zetta |
1911 | 0 | case 'Y': n = 24; break; // yotta |
1912 | 0 | default: return INV_MATCHLEV; |
1913 | 4 | } |
1914 | | |
1915 | | // We could weed some nonsense out, ODFF doesn't say so though. |
1916 | | #if 0 |
1917 | | if (n < 0 && Class() == CDC_Information) |
1918 | | return INV_MATCHLEV; // milli-bits doesn't make sense |
1919 | | #endif |
1920 | | |
1921 | | //! <HACK> "cm3" is not 10^-2 m^3 but 10^-6 m^3 !!! ------------------ |
1922 | 4 | if (aStr.endsWith("2")) |
1923 | 0 | n *= 2; |
1924 | 4 | else if (aStr.endsWith("3")) |
1925 | 0 | n *= 3; |
1926 | | //! </HACK> ------------------------------------------------------------------- |
1927 | | |
1928 | 4 | return n; |
1929 | 4 | } |
1930 | 0 | else if (prefix.size() == 2 && prefix[1] == 'i' && Class() == CDC_Information) |
1931 | 0 | { |
1932 | 0 | switch (prefix[0]) |
1933 | 0 | { |
1934 | 0 | case 'k': return 10; |
1935 | 0 | case 'M': return 20; |
1936 | 0 | case 'G': return 30; |
1937 | 0 | case 'T': return 40; |
1938 | 0 | case 'P': return 50; |
1939 | 0 | case 'E': return 60; |
1940 | 0 | case 'Z': return 70; |
1941 | 0 | case 'Y': return 80; |
1942 | 0 | default: return INV_MATCHLEV; |
1943 | 0 | } |
1944 | 0 | } |
1945 | 4 | } |
1946 | 662 | return INV_MATCHLEV; |
1947 | 666 | } |
1948 | | |
1949 | | |
1950 | | double ConvertData::Convert( |
1951 | | double f, const ConvertData& r, sal_Int16 nLevFrom, sal_Int16 nLevTo ) const |
1952 | 6 | { |
1953 | 6 | assert(Class() == r.Class()); |
1954 | | |
1955 | 6 | f *= r.fConst / fConst; |
1956 | | |
1957 | 6 | if (Class() == CDC_Information) |
1958 | 0 | { |
1959 | 0 | bool bBinFromLev = (nLevFrom > 0 && (nLevFrom % 10) == 0); |
1960 | 0 | bool bBinToLev = (nLevTo > 0 && (nLevTo % 10) == 0); |
1961 | 0 | if (bBinFromLev || bBinToLev) |
1962 | 0 | { |
1963 | 0 | if (bBinFromLev && bBinToLev) |
1964 | 0 | { |
1965 | 0 | nLevFrom -= nLevTo; |
1966 | 0 | if (nLevFrom) |
1967 | 0 | f *= pow(2.0, nLevFrom); |
1968 | 0 | } |
1969 | 0 | else if (bBinFromLev) |
1970 | 0 | f *= pow(2.0, nLevFrom) / pow(10.0, nLevTo); |
1971 | 0 | else |
1972 | 0 | f *= pow(10.0, nLevFrom) / pow(2.0, nLevTo); |
1973 | 0 | return f; |
1974 | 0 | } |
1975 | 0 | } |
1976 | | |
1977 | 6 | nLevFrom -= nLevTo; // effective level |
1978 | 6 | if( nLevFrom ) |
1979 | 4 | f = ::rtl::math::pow10Exp( f, nLevFrom ); |
1980 | | |
1981 | 6 | return f; |
1982 | 6 | } |
1983 | | |
1984 | | |
1985 | | ConvertDataLinear::~ConvertDataLinear() = default; |
1986 | | |
1987 | | double ConvertDataLinear::Convert( |
1988 | | double f, const ConvertData& r, sal_Int16 nLevFrom, sal_Int16 nLevTo ) const |
1989 | 0 | { |
1990 | 0 | assert(Class() == r.Class()); |
1991 | 0 | assert(dynamic_cast<const ConvertDataLinear*>(&r)); |
1992 | 0 | return static_cast<const ConvertDataLinear&>(r).ConvertFromBase( ConvertToBase( f, nLevFrom ), nLevTo ); |
1993 | 0 | } |
1994 | | |
1995 | | |
1996 | | double ConvertDataLinear::ConvertToBase( double f, sal_Int16 n ) const |
1997 | 0 | { |
1998 | 0 | if( n ) |
1999 | 0 | f = ::rtl::math::pow10Exp( f, n ); |
2000 | |
|
2001 | 0 | f /= fConst; |
2002 | 0 | f -= fOffs; |
2003 | |
|
2004 | 0 | return f; |
2005 | 0 | } |
2006 | | |
2007 | | |
2008 | | double ConvertDataLinear::ConvertFromBase( double f, sal_Int16 n ) const |
2009 | 0 | { |
2010 | 0 | f += fOffs; |
2011 | 0 | f *= fConst; |
2012 | |
|
2013 | 0 | if( n ) |
2014 | 0 | f = ::rtl::math::pow10Exp( f, -n ); |
2015 | |
|
2016 | 0 | return f; |
2017 | 0 | } |
2018 | | |
2019 | | |
2020 | | ConvertDataList::ConvertDataList() |
2021 | 1 | { |
2022 | 94 | #define NEWD(str,unit,cl) maVector.push_back(std::make_unique<ConvertData>(u"" str,unit,cl)) |
2023 | 44 | #define NEWDP(str,unit,cl) maVector.push_back(std::make_unique<ConvertData>(u"" str,unit,cl,true)) |
2024 | 6 | #define NEWL(str,unit,offs,cl) maVector.push_back(std::make_unique<ConvertDataLinear>(u"" str,unit,offs,cl)) |
2025 | 2 | #define NEWLP(str,unit,offs,cl) maVector.push_back(std::make_unique<ConvertDataLinear>(u"" str,unit,offs,cl,true)) |
2026 | | |
2027 | 1 | const size_t expected_size = 146; |
2028 | 1 | maVector.reserve(expected_size); |
2029 | | |
2030 | | // *** are extra and not standard Excel Analysis Addin! |
2031 | | |
2032 | | // MASS: 1 Gram is... |
2033 | 1 | NEWDP( "g", 1.0000000000000000E00, CDC_Mass ); // Gram |
2034 | 1 | NEWD( "sg", 6.8522050005347800E-05, CDC_Mass ); // Pieces |
2035 | 1 | NEWD( "lbm", 2.2046229146913400E-03, CDC_Mass ); // Pound (commercial weight) |
2036 | 1 | NEWDP( "u", 6.0221370000000000E23, CDC_Mass ); // U (atomic mass) |
2037 | 1 | NEWD( "ozm", 3.5273971800362700E-02, CDC_Mass ); // Ounce (commercial weight) |
2038 | 1 | NEWD( "stone", 1.574730e-04, CDC_Mass ); // *** Stone |
2039 | 1 | NEWD( "ton", 1.102311e-06, CDC_Mass ); // *** Ton |
2040 | 1 | NEWD( "grain", 1.543236E01, CDC_Mass ); // *** Grain |
2041 | 1 | NEWD( "pweight", 7.054792E-01, CDC_Mass ); // *** Pennyweight |
2042 | 1 | NEWD( "hweight", 1.968413E-05, CDC_Mass ); // *** Hundredweight |
2043 | 1 | NEWD( "shweight", 2.204623E-05, CDC_Mass ); // *** Shorthundredweight |
2044 | 1 | NEWD( "brton", 9.842065E-07, CDC_Mass ); // *** Gross Registered Ton |
2045 | 1 | NEWD( "cwt", 2.2046226218487758E-05, CDC_Mass ); // U.S. (short) hundredweight |
2046 | 1 | NEWD( "shweight", 2.2046226218487758E-05, CDC_Mass ); // U.S. (short) hundredweight also |
2047 | 1 | NEWD( "uk_cwt", 1.9684130552221213E-05, CDC_Mass ); // Imperial hundredweight |
2048 | 1 | NEWD( "lcwt", 1.9684130552221213E-05, CDC_Mass ); // Imperial hundredweight also |
2049 | 1 | NEWD( "hweight", 1.9684130552221213E-05, CDC_Mass ); // Imperial hundredweight also |
2050 | 1 | NEWD( "uk_ton", 9.8420652761106063E-07, CDC_Mass ); // Imperial ton |
2051 | 1 | NEWD( "LTON", 9.8420652761106063E-07, CDC_Mass ); // Imperial ton also |
2052 | | |
2053 | | // LENGTH: 1 Meter is... |
2054 | 1 | NEWDP( "m", 1.0000000000000000E00, CDC_Length ); // Meter |
2055 | 1 | NEWD( "mi", 6.2137119223733397E-04, CDC_Length ); // Britsh Mile 6,21371192237333969617434184363e-4 |
2056 | 1 | NEWD( "Nmi", 5.3995680345572354E-04, CDC_Length ); // Nautical Mile 5,39956803455723542116630669546e-4 |
2057 | 1 | NEWD( "in", 3.9370078740157480E01, CDC_Length ); // Inch 39,37007874015748031496062992126 |
2058 | 1 | NEWD( "ft", 3.2808398950131234E00, CDC_Length ); // Foot 3,2808398950131233595800524934383 |
2059 | 1 | NEWD( "yd", 1.0936132983377078E00, CDC_Length ); // Yard 1,0936132983377077865266841644794 |
2060 | 1 | NEWDP( "ang", 1.0000000000000000E10, CDC_Length ); // Angstrom |
2061 | 1 | NEWD( "Pica", 2.8346456692913386E03, CDC_Length ); // Pica Point (1/72 Inch) 2834,6456692913385826771653543307 |
2062 | 1 | NEWD( "picapt", 2.8346456692913386E03, CDC_Length ); // Pica Point (1/72 Inch) 2834,6456692913385826771653543307 |
2063 | 1 | NEWD( "pica", 2.36220472441E02, CDC_Length ); // pica (1/6 Inch) |
2064 | 1 | NEWD( "ell", 8.748906E-01, CDC_Length ); // *** Ell |
2065 | 1 | NEWDP( "parsec", 3.240779E-17, CDC_Length ); // *** Parsec |
2066 | 1 | NEWDP( "pc", 3.240779E-17, CDC_Length ); // *** Parsec also |
2067 | 1 | NEWDP( "lightyear", 1.0570234557732930E-16, CDC_Length ); // *** Light Year |
2068 | 1 | NEWDP( "ly", 1.0570234557732930E-16, CDC_Length ); // *** Light Year also |
2069 | 1 | NEWD( "survey_mi", 6.2136994949494949E-04, CDC_Length ); // U.S. survey mile |
2070 | | |
2071 | | // TIME: 1 Second is... |
2072 | 1 | NEWD( "yr", 3.1688087814028950E-08, CDC_Time ); // Year |
2073 | 1 | NEWD( "day", 1.1574074074074074E-05, CDC_Time ); // Day |
2074 | 1 | NEWD( "d", 1.1574074074074074E-05, CDC_Time ); // Day also |
2075 | 1 | NEWD( "hr", 2.7777777777777778E-04, CDC_Time ); // Hour |
2076 | 1 | NEWD( "mn", 1.6666666666666667E-02, CDC_Time ); // Minute |
2077 | 1 | NEWD( "min", 1.6666666666666667E-02, CDC_Time ); // Minute also |
2078 | 1 | NEWDP( "sec", 1.0000000000000000E00, CDC_Time ); // Second |
2079 | 1 | NEWDP( "s", 1.0000000000000000E00, CDC_Time ); // Second also |
2080 | | |
2081 | | // PRESSURE: 1 Pascal is... |
2082 | 1 | NEWDP( "Pa", 1.0000000000000000E00, CDC_Pressure ); // Pascal |
2083 | 1 | NEWDP( "atm", 9.8692329999819300E-06, CDC_Pressure ); // Atmosphere |
2084 | 1 | NEWDP( "at", 9.8692329999819300E-06, CDC_Pressure ); // Atmosphere also |
2085 | 1 | NEWDP( "mmHg", 7.5006170799862700E-03, CDC_Pressure ); // mm Hg (Mercury) |
2086 | 1 | NEWD( "Torr", 7.5006380000000000E-03, CDC_Pressure ); // *** Torr |
2087 | 1 | NEWD( "psi", 1.4503770000000000E-04, CDC_Pressure ); // *** Psi |
2088 | | |
2089 | | // FORCE: 1 Newton is... |
2090 | 1 | NEWDP( "N", 1.0000000000000000E00, CDC_Force ); // Newton |
2091 | 1 | NEWDP( "dyn", 1.0000000000000000E05, CDC_Force ); // Dyn |
2092 | 1 | NEWDP( "dy", 1.0000000000000000E05, CDC_Force ); // Dyn also |
2093 | 1 | NEWD( "lbf", 2.24808923655339E-01, CDC_Force ); // Pound-Force |
2094 | 1 | NEWDP( "pond", 1.019716E02, CDC_Force ); // *** Pond |
2095 | | |
2096 | | // ENERGY: 1 Joule is... |
2097 | 1 | NEWDP( "J", 1.0000000000000000E00, CDC_Energy ); // Joule |
2098 | 1 | NEWDP( "e", 1.0000000000000000E07, CDC_Energy ); // Erg -> https://en.wikipedia.org/wiki/Erg |
2099 | 1 | NEWDP( "c", 2.3900624947346700E-01, CDC_Energy ); // Thermodynamical Calorie |
2100 | 1 | NEWDP( "cal", 2.3884619064201700E-01, CDC_Energy ); // Calorie |
2101 | 1 | NEWDP( "eV", 6.2414570000000000E18, CDC_Energy ); // Electronvolt |
2102 | 1 | NEWDP( "ev", 6.2414570000000000E18, CDC_Energy ); // Electronvolt also |
2103 | 1 | NEWD( "HPh", 3.7250611111111111E-07, CDC_Energy ); // Horsepower Hours |
2104 | 1 | NEWD( "hh", 3.7250611111111111E-07, CDC_Energy ); // Horsepower Hours also |
2105 | 1 | NEWDP( "Wh", 2.7777777777777778E-04, CDC_Energy ); // Watt Hours |
2106 | 1 | NEWDP( "wh", 2.7777777777777778E-04, CDC_Energy ); // Watt Hours also |
2107 | 1 | NEWD( "flb", 2.37304222192651E01, CDC_Energy ); // Foot Pound |
2108 | 1 | NEWD( "BTU", 9.4781506734901500E-04, CDC_Energy ); // British Thermal Unit |
2109 | 1 | NEWD( "btu", 9.4781506734901500E-04, CDC_Energy ); // British Thermal Unit also |
2110 | | |
2111 | | // POWER: 1 Watt is... |
2112 | 1 | NEWDP( "W", 1.0000000000000000E00, CDC_Power ); // Watt |
2113 | 1 | NEWDP( "w", 1.0000000000000000E00, CDC_Power ); // Watt also |
2114 | 1 | NEWD( "HP", 1.341022E-03, CDC_Power ); // Horsepower |
2115 | 1 | NEWD( "h", 1.341022E-03, CDC_Power ); // Horsepower also |
2116 | 1 | NEWD( "PS", 1.359622E-03, CDC_Power ); // *** German Pferdestaerke |
2117 | | |
2118 | | // MAGNETISM: 1 Tesla is... |
2119 | 1 | NEWDP( "T", 1.0000000000000000E00, CDC_Magnetism ); // Tesla |
2120 | 1 | NEWDP( "ga", 1.0000000000000000E04, CDC_Magnetism ); // Gauss |
2121 | | |
2122 | | // TEMPERATURE: 1 Kelvin is... |
2123 | 1 | NEWL( "C", 1.0000000000000000E00, -2.7315000000000000E02, CDC_Temperature ); // Celsius |
2124 | 1 | NEWL( "cel", 1.0000000000000000E00, -2.7315000000000000E02, CDC_Temperature ); // Celsius also |
2125 | 1 | NEWL( "F", 1.8000000000000000E00, -2.5537222222222222E02, CDC_Temperature ); // Fahrenheit |
2126 | 1 | NEWL( "fah", 1.8000000000000000E00, -2.5537222222222222E02, CDC_Temperature ); // Fahrenheit also |
2127 | 1 | NEWLP( "K", 1.0000000000000000E00, +0.0000000000000000E00, CDC_Temperature ); // Kelvin |
2128 | 1 | NEWLP( "kel", 1.0000000000000000E00, +0.0000000000000000E00, CDC_Temperature ); // Kelvin also |
2129 | 1 | NEWL( "Reau", 8.0000000000000000E-01, -2.7315000000000000E02, CDC_Temperature ); // *** Reaumur |
2130 | 1 | NEWL( "Rank", 1.8000000000000000E00, +0.0000000000000000E00, CDC_Temperature ); // *** Rankine |
2131 | | |
2132 | | // VOLUME: 1 Liter is... |
2133 | 1 | NEWD( "tsp", 2.0288413621105798E02, CDC_Volume ); // US teaspoon 1/768 gallon |
2134 | 1 | NEWD( "tbs", 6.7628045403685994E01, CDC_Volume ); // US tablespoon 1/256 gallon |
2135 | 1 | NEWD( "oz", 3.3814022701842997E01, CDC_Volume ); // Ounce Liquid 1/128 gallon |
2136 | 1 | NEWD( "cup", 4.2267528377303746E00, CDC_Volume ); // Cup 1/16 gallon |
2137 | 1 | NEWD( "pt", 2.1133764188651873E00, CDC_Volume ); // US Pint 1/8 gallon |
2138 | 1 | NEWD( "us_pt", 2.1133764188651873E00, CDC_Volume ); // US Pint also |
2139 | 1 | NEWD( "uk_pt", 1.7597539863927023E00, CDC_Volume ); // UK Pint 1/8 imperial gallon |
2140 | 1 | NEWD( "qt", 1.0566882094325937E00, CDC_Volume ); // Quart 1/4 gallon |
2141 | 1 | NEWD( "gal", 2.6417205235814842E-01, CDC_Volume ); // Gallon 1/3.785411784 |
2142 | 1 | NEWDP( "l", 1.0000000000000000E00, CDC_Volume ); // Liter |
2143 | 1 | NEWDP( "L", 1.0000000000000000E00, CDC_Volume ); // Liter also |
2144 | 1 | NEWDP( "lt", 1.0000000000000000E00, CDC_Volume ); // Liter also |
2145 | 1 | NEWDP( "m3", 1.0000000000000000E-03, CDC_Volume ); // *** Cubic Meter |
2146 | 1 | NEWD( "mi3", 2.3991275857892772E-13, CDC_Volume ); // *** Cubic Britsh Mile |
2147 | 1 | NEWD( "Nmi3", 1.5742621468581148E-13, CDC_Volume ); // *** Cubic Nautical Mile |
2148 | 1 | NEWD( "in3", 6.1023744094732284E01, CDC_Volume ); // *** Cubic Inch |
2149 | 1 | NEWD( "ft3", 3.5314666721488590E-02, CDC_Volume ); // *** Cubic Foot |
2150 | 1 | NEWD( "yd3", 1.3079506193143922E-03, CDC_Volume ); // *** Cubic Yard |
2151 | 1 | NEWDP( "ang3", 1.0000000000000000E27, CDC_Volume ); // *** Cubic Angstrom |
2152 | 1 | NEWD( "Pica3", 2.2776990435870636E07, CDC_Volume ); // *** Cubic Pica Point (1/72 inch) |
2153 | 1 | NEWD( "picapt3", 2.2776990435870636E07, CDC_Volume ); // *** Cubic Pica Point (1/72 inch) |
2154 | 1 | NEWD( "pica3", 1.31811287245E04, CDC_Volume ); // *** Cubic Pica (1/6 inch) |
2155 | 1 | NEWD( "barrel", 6.2898107704321051E-03, CDC_Volume ); // *** Barrel (=42gal) |
2156 | 1 | NEWD( "bushel", 2.837759E-02, CDC_Volume ); // *** Bushel |
2157 | 1 | NEWD( "regton", 3.531467E-04, CDC_Volume ); // *** Register ton |
2158 | 1 | NEWD( "GRT", 3.531467E-04, CDC_Volume ); // *** Register ton also |
2159 | 1 | NEWD( "Schooner", 2.3529411764705882E00, CDC_Volume ); // *** austr. Schooner |
2160 | 1 | NEWD( "Middy", 3.5087719298245614E00, CDC_Volume ); // *** austr. Middy |
2161 | 1 | NEWD( "Glass", 5.0000000000000000E00, CDC_Volume ); // *** austr. Glass |
2162 | 1 | NEWD( "Sixpack", 0.5, CDC_Volume ); // *** |
2163 | 1 | NEWD( "Humpen", 2.0, CDC_Volume ); // *** |
2164 | 1 | NEWD( "ly3", 1.1810108125623799E-51, CDC_Volume ); // *** Cubic light-year |
2165 | 1 | NEWD( "MTON", 1.4125866688595436E00, CDC_Volume ); // *** Measurement ton |
2166 | 1 | NEWD( "tspm", 2.0000000000000000E02, CDC_Volume ); // *** Modern teaspoon |
2167 | 1 | NEWD( "uk_gal", 2.1996924829908779E-01, CDC_Volume ); // U.K. / Imperial gallon 1/4.54609 |
2168 | 1 | NEWD( "uk_qt", 8.7987699319635115E-01, CDC_Volume ); // U.K. / Imperial quart 1/4 imperial gallon |
2169 | | |
2170 | | // 1 Square Meter is... |
2171 | 1 | NEWDP( "m2", 1.0000000000000000E00, CDC_Area ); // *** Square Meter |
2172 | 1 | NEWD( "mi2", 3.8610215854244585E-07, CDC_Area ); // *** Square Britsh Mile |
2173 | 1 | NEWD( "Nmi2", 2.9155334959812286E-07, CDC_Area ); // *** Square Nautical Mile |
2174 | 1 | NEWD( "in2", 1.5500031000062000E03, CDC_Area ); // *** Square Inch |
2175 | 1 | NEWD( "ft2", 1.0763910416709722E01, CDC_Area ); // *** Square Foot |
2176 | 1 | NEWD( "yd2", 1.1959900463010803E00, CDC_Area ); // *** Square Yard |
2177 | 1 | NEWDP( "ang2", 1.0000000000000000E20, CDC_Area ); // *** Square Angstrom |
2178 | 1 | NEWD( "Pica2", 8.0352160704321409E06, CDC_Area ); // *** Square Pica Point (1/72 inch) |
2179 | 1 | NEWD( "picapt2", 8.0352160704321409E06, CDC_Area ); // *** Square Pica Point (1/72 inch) |
2180 | 1 | NEWD( "pica2", 5.58001116002232E04, CDC_Area ); // *** Square Pica (1/6 inch) |
2181 | 1 | NEWD( "Morgen", 4.0000000000000000E-04, CDC_Area ); // *** Morgen |
2182 | 1 | NEWDP( "ar", 1.000000E-02, CDC_Area ); // *** Ar |
2183 | 1 | NEWD( "acre", 2.471053815E-04, CDC_Area ); // *** Acre |
2184 | 1 | NEWD( "uk_acre", 2.4710538146716534E-04, CDC_Area ); // *** International acre |
2185 | 1 | NEWD( "us_acre", 2.4710439304662790E-04, CDC_Area ); // *** U.S. survey/statute acre |
2186 | 1 | NEWD( "ly2", 1.1172985860549147E-32, CDC_Area ); // *** Square Light-year |
2187 | 1 | NEWD( "ha", 1.000000E-04, CDC_Area ); // *** Hectare |
2188 | | |
2189 | | // SPEED: 1 Meter per Second is... |
2190 | 1 | NEWDP( "m/s", 1.0000000000000000E00, CDC_Speed ); // *** Meters per Second |
2191 | 1 | NEWDP( "m/sec", 1.0000000000000000E00, CDC_Speed ); // *** Meters per Second also |
2192 | 1 | NEWDP( "m/h", 3.6000000000000000E03, CDC_Speed ); // *** Meters per Hour |
2193 | 1 | NEWDP( "m/hr", 3.6000000000000000E03, CDC_Speed ); // *** Meters per Hour also |
2194 | 1 | NEWD( "mph", 2.2369362920544023E00, CDC_Speed ); // *** Britsh Miles per Hour |
2195 | 1 | NEWD( "kn", 1.9438444924406048E00, CDC_Speed ); // *** Knot = Nautical Miles per Hour |
2196 | 1 | NEWD( "admkn", 1.9438446603753486E00, CDC_Speed ); // *** Admiralty Knot |
2197 | 1 | NEWD( "ludicrous speed", 2.0494886343432328E-14, CDC_Speed ); // *** |
2198 | 1 | NEWD( "ridiculous speed", 4.0156958471424288E-06, CDC_Speed); // *** |
2199 | | |
2200 | | // INFORMATION: 1 Bit is... |
2201 | 1 | NEWDP( "bit", 1.00E00, CDC_Information); // *** Bit |
2202 | 1 | NEWDP( "byte", 1.25E-01, CDC_Information); // *** Byte |
2203 | | |
2204 | 1 | assert(maVector.size() == expected_size); |
2205 | 1 | } |
2206 | | |
2207 | | |
2208 | 0 | ConvertDataList::~ConvertDataList() = default; |
2209 | | |
2210 | | |
2211 | | double ConvertDataList::Convert( double fVal, const OUString& rFrom, const OUString& rTo ) |
2212 | 6 | { |
2213 | 6 | ConvertData* pFrom = nullptr; |
2214 | 6 | ConvertData* pTo = nullptr; |
2215 | 6 | bool bSearchFrom = true; |
2216 | 6 | bool bSearchTo = true; |
2217 | 6 | sal_Int16 nLevelFrom = 0; |
2218 | 6 | sal_Int16 nLevelTo = 0; |
2219 | | |
2220 | 6 | for( const auto& rItem : maVector ) |
2221 | 630 | { |
2222 | 630 | if( bSearchFrom ) |
2223 | 624 | { |
2224 | 624 | sal_Int16 n = rItem->GetMatchingLevel(rFrom); |
2225 | 624 | if( n != INV_MATCHLEV ) |
2226 | 6 | { |
2227 | 6 | pFrom = rItem.get(); |
2228 | 6 | nLevelFrom = n; |
2229 | 6 | if (!n) |
2230 | 2 | { // only first match for partial equality rulz a little bit more |
2231 | | // ... but exact match rulz most |
2232 | 2 | bSearchFrom = false; |
2233 | 2 | } |
2234 | 6 | } |
2235 | 624 | } |
2236 | | |
2237 | 630 | if( bSearchTo ) |
2238 | 50 | { |
2239 | 50 | sal_Int16 n = rItem->GetMatchingLevel(rTo); |
2240 | 50 | if( n != INV_MATCHLEV ) |
2241 | 6 | { |
2242 | 6 | pTo = rItem.get(); |
2243 | 6 | nLevelTo = n; |
2244 | 6 | if (!n) |
2245 | 6 | { // only first match for partial equality rulz a little bit more |
2246 | | // ... but exact match rulz most |
2247 | 6 | bSearchTo = false; |
2248 | 6 | } |
2249 | 6 | } |
2250 | 50 | } |
2251 | | |
2252 | 630 | if( !bSearchFrom && !bSearchTo ) |
2253 | 2 | break; |
2254 | 630 | } |
2255 | | |
2256 | 6 | if( !pFrom || !pTo ) |
2257 | 0 | throw lang::IllegalArgumentException(); |
2258 | | |
2259 | 6 | if (pFrom->Class() != pTo->Class()) |
2260 | 0 | throw lang::IllegalArgumentException(); |
2261 | | |
2262 | 6 | return pFrom->Convert( fVal, *pTo, nLevelFrom, nLevelTo ); |
2263 | 6 | } |
2264 | | |
2265 | | |
2266 | | ScaDate::ScaDate() : |
2267 | 4 | nOrigDay( 1 ), |
2268 | 4 | nDay( 1 ), |
2269 | 4 | nMonth( 1 ), |
2270 | 4 | nYear( 1900 ), |
2271 | 4 | bLastDayMode( true ), |
2272 | 4 | bLastDay( false ), |
2273 | 4 | b30Days( false ), |
2274 | 4 | bUSMode( false ) |
2275 | 4 | { |
2276 | 4 | } |
2277 | | |
2278 | | ScaDate::ScaDate( sal_Int32 nNullDate, sal_Int32 nDate, sal_Int32 nBase ) |
2279 | 8 | { |
2280 | 8 | DaysToDate( nNullDate + nDate, nOrigDay, nMonth, nYear ); |
2281 | 8 | bLastDayMode = (nBase != 5); |
2282 | 8 | bLastDay = (nOrigDay >= ::DaysInMonth( nMonth, nYear )); |
2283 | 8 | b30Days = (nBase == 0) || (nBase == 4); |
2284 | 8 | bUSMode = (nBase == 0); |
2285 | 8 | setDay(); |
2286 | 8 | } |
2287 | | |
2288 | | ScaDate::ScaDate( const ScaDate& rCopy ) : |
2289 | 0 | nOrigDay( rCopy.nOrigDay ), |
2290 | 0 | nDay( rCopy.nDay ), |
2291 | 0 | nMonth( rCopy.nMonth ), |
2292 | 0 | nYear( rCopy.nYear ), |
2293 | 0 | bLastDayMode( rCopy.bLastDayMode ), |
2294 | 0 | bLastDay( rCopy.bLastDay ), |
2295 | 0 | b30Days( rCopy.b30Days ), |
2296 | 0 | bUSMode( rCopy.bUSMode ) |
2297 | 0 | { |
2298 | 0 | } |
2299 | | |
2300 | | ScaDate& ScaDate::operator=( const ScaDate& rCopy ) |
2301 | 4 | { |
2302 | 4 | if( this != &rCopy ) |
2303 | 4 | { |
2304 | 4 | nOrigDay = rCopy.nOrigDay; |
2305 | 4 | nDay = rCopy.nDay; |
2306 | 4 | nMonth = rCopy.nMonth; |
2307 | 4 | nYear = rCopy.nYear; |
2308 | 4 | bLastDayMode = rCopy.bLastDayMode; |
2309 | 4 | bLastDay = rCopy.bLastDay; |
2310 | 4 | b30Days = rCopy.b30Days; |
2311 | 4 | bUSMode = rCopy.bUSMode; |
2312 | 4 | } |
2313 | 4 | return *this; |
2314 | 4 | } |
2315 | | |
2316 | | void ScaDate::setDay() |
2317 | 12 | { |
2318 | 12 | if( b30Days ) |
2319 | 12 | { |
2320 | | // 30-days-mode: set nDay to 30 if original was last day in month |
2321 | 12 | nDay = std::min( nOrigDay, static_cast< sal_uInt16 >( 30 ) ); |
2322 | 12 | if( bLastDay || (nDay >= ::DaysInMonth( nMonth, nYear )) ) |
2323 | 0 | nDay = 30; |
2324 | 12 | } |
2325 | 0 | else |
2326 | 0 | { |
2327 | | // set nDay to last day in this month if original was last day |
2328 | 0 | sal_uInt16 nLastDay = ::DaysInMonth( nMonth, nYear ); |
2329 | 0 | nDay = bLastDay ? nLastDay : std::min( nOrigDay, nLastDay ); |
2330 | 0 | } |
2331 | 12 | } |
2332 | | |
2333 | | sal_Int32 ScaDate::getDaysInMonthRange( sal_uInt16 nFrom, sal_uInt16 nTo ) const |
2334 | 0 | { |
2335 | 0 | if( nFrom > nTo ) |
2336 | 0 | return 0; |
2337 | | |
2338 | 0 | sal_Int32 nRet = 0; |
2339 | 0 | if( b30Days ) |
2340 | 0 | nRet = (nTo - nFrom + 1) * 30; |
2341 | 0 | else |
2342 | 0 | { |
2343 | 0 | for( sal_uInt16 nMonthIx = nFrom; nMonthIx <= nTo; ++nMonthIx ) |
2344 | 0 | nRet += getDaysInMonth( nMonthIx ); |
2345 | 0 | } |
2346 | 0 | return nRet; |
2347 | 0 | } |
2348 | | |
2349 | | sal_Int32 ScaDate::getDaysInYearRange( sal_uInt16 nFrom, sal_uInt16 nTo ) const |
2350 | 0 | { |
2351 | 0 | if( nFrom > nTo ) |
2352 | 0 | return 0; |
2353 | | |
2354 | 0 | return b30Days ? ((nTo - nFrom + 1) * 360) : ::GetDaysInYears( nFrom, nTo ); |
2355 | 0 | } |
2356 | | |
2357 | | void ScaDate::doAddYears( sal_Int32 nYearCount ) |
2358 | 0 | { |
2359 | 0 | sal_Int32 nNewYear = nYearCount + nYear; |
2360 | 0 | if( (nNewYear < 0) || (nNewYear > 0x7FFF) ) |
2361 | 0 | throw lang::IllegalArgumentException(); |
2362 | 0 | nYear = static_cast< sal_uInt16 >( nNewYear ); |
2363 | 0 | } |
2364 | | |
2365 | | void ScaDate::addMonths( sal_Int32 nMonthCount ) |
2366 | 0 | { |
2367 | 0 | sal_Int32 nNewMonth = nMonthCount + nMonth; |
2368 | 0 | if( nNewMonth > 12 ) |
2369 | 0 | { |
2370 | 0 | --nNewMonth; |
2371 | 0 | doAddYears( nNewMonth / 12 ); |
2372 | 0 | nMonth = static_cast< sal_uInt16 >( nNewMonth % 12 ) + 1; |
2373 | 0 | } |
2374 | 0 | else if( nNewMonth < 1 ) |
2375 | 0 | { |
2376 | 0 | doAddYears( nNewMonth / 12 - 1 ); |
2377 | 0 | nMonth = static_cast< sal_uInt16 >( nNewMonth % 12 + 12 ); |
2378 | 0 | } |
2379 | 0 | else |
2380 | 0 | nMonth = static_cast< sal_uInt16 >( nNewMonth ); |
2381 | 0 | setDay(); |
2382 | 0 | } |
2383 | | |
2384 | | sal_Int32 ScaDate::getDate( sal_Int32 nNullDate ) const |
2385 | 0 | { |
2386 | 0 | sal_uInt16 nLastDay = ::DaysInMonth( nMonth, nYear ); |
2387 | 0 | sal_uInt16 nRealDay = (bLastDayMode && bLastDay) ? nLastDay : std::min( nLastDay, nOrigDay ); |
2388 | 0 | return ::DateToDays( nRealDay, nMonth, nYear ) - nNullDate; |
2389 | 0 | } |
2390 | | |
2391 | | sal_Int32 ScaDate::getDiff( const ScaDate& rFrom, const ScaDate& rTo ) |
2392 | 0 | { |
2393 | 0 | if( rFrom > rTo ) |
2394 | 0 | return getDiff( rTo, rFrom ); |
2395 | | |
2396 | 0 | sal_Int32 nDiff = 0; |
2397 | 0 | ScaDate aFrom( rFrom ); |
2398 | 0 | ScaDate aTo( rTo ); |
2399 | |
|
2400 | 0 | if( rTo.b30Days ) |
2401 | 0 | { |
2402 | | // corrections for base 0 (US NASD) |
2403 | 0 | if( rTo.bUSMode ) |
2404 | 0 | { |
2405 | 0 | if( ((rFrom.nMonth == 2) || (rFrom.nDay < 30)) && (aTo.nOrigDay == 31) ) |
2406 | 0 | aTo.nDay = 31; |
2407 | 0 | else if( (aTo.nMonth == 2) && aTo.bLastDay ) |
2408 | 0 | aTo.nDay = ::DaysInMonth( 2, aTo.nYear ); |
2409 | 0 | } |
2410 | | // corrections for base 4 (Europe) |
2411 | 0 | else |
2412 | 0 | { |
2413 | 0 | if( (aFrom.nMonth == 2) && (aFrom.nDay == 30) ) |
2414 | 0 | aFrom.nDay = ::DaysInMonth( 2, aFrom.nYear ); |
2415 | 0 | if( (aTo.nMonth == 2) && (aTo.nDay == 30) ) |
2416 | 0 | aTo.nDay = ::DaysInMonth( 2, aTo.nYear ); |
2417 | 0 | } |
2418 | 0 | } |
2419 | |
|
2420 | 0 | if( (aFrom.nYear < aTo.nYear) || ((aFrom.nYear == aTo.nYear) && (aFrom.nMonth < aTo.nMonth)) ) |
2421 | 0 | { |
2422 | | // move aFrom to 1st day of next month |
2423 | 0 | nDiff = aFrom.getDaysInMonth() - aFrom.nDay + 1; |
2424 | 0 | aFrom.nOrigDay = aFrom.nDay = 1; |
2425 | 0 | aFrom.bLastDay = false; |
2426 | 0 | aFrom.addMonths( 1 ); |
2427 | |
|
2428 | 0 | if( aFrom.nYear < aTo.nYear ) |
2429 | 0 | { |
2430 | | // move aFrom to 1st day of next year |
2431 | 0 | nDiff += aFrom.getDaysInMonthRange( aFrom.nMonth, 12 ); |
2432 | 0 | aFrom.addMonths( 13 - aFrom.nMonth ); |
2433 | | |
2434 | | // move aFrom to 1st day of this year |
2435 | 0 | nDiff += aFrom.getDaysInYearRange( aFrom.nYear, aTo.nYear - 1 ); |
2436 | 0 | aFrom.addYears( aTo.nYear - aFrom.nYear ); |
2437 | 0 | } |
2438 | | |
2439 | | // move aFrom to 1st day of this month |
2440 | 0 | nDiff += aFrom.getDaysInMonthRange( aFrom.nMonth, aTo.nMonth - 1 ); |
2441 | 0 | aFrom.addMonths( aTo.nMonth - aFrom.nMonth ); |
2442 | 0 | } |
2443 | | // finally add remaining days in this month |
2444 | 0 | nDiff += aTo.nDay - aFrom.nDay; |
2445 | 0 | return std::max<sal_Int32>(nDiff, 0); |
2446 | 0 | } |
2447 | | |
2448 | | bool ScaDate::operator<( const ScaDate& rCmp ) const |
2449 | 8 | { |
2450 | 8 | if( nYear != rCmp.nYear ) |
2451 | 0 | return nYear < rCmp.nYear; |
2452 | 8 | if( nMonth != rCmp.nMonth ) |
2453 | 0 | return nMonth < rCmp.nMonth; |
2454 | 8 | if( nDay != rCmp.nDay ) |
2455 | 0 | return nDay < rCmp.nDay; |
2456 | 8 | if( bLastDay || rCmp.bLastDay ) |
2457 | 0 | return !bLastDay && rCmp.bLastDay; |
2458 | 8 | return nOrigDay < rCmp.nOrigDay; |
2459 | 8 | } |
2460 | | |
2461 | | |
2462 | | ScaAnyConverter::ScaAnyConverter( const uno::Reference< uno::XComponentContext >& xContext ) |
2463 | 5 | : nDefaultFormat(0) |
2464 | 5 | , bHasValidFormat(false) |
2465 | 5 | { |
2466 | 5 | xFormatter = util::NumberFormatter::create(xContext); |
2467 | 5 | } |
2468 | | |
2469 | | ScaAnyConverter::~ScaAnyConverter() |
2470 | 0 | { |
2471 | 0 | } |
2472 | | |
2473 | | void ScaAnyConverter::init( const uno::Reference< beans::XPropertySet >& xPropSet ) |
2474 | 21.3k | { |
2475 | | // try to get default number format |
2476 | 21.3k | bHasValidFormat = false; |
2477 | 21.3k | if( !xFormatter.is() ) |
2478 | 0 | return; |
2479 | | |
2480 | | // get XFormatsSupplier from outer XPropertySet |
2481 | 21.3k | uno::Reference< util::XNumberFormatsSupplier > xFormatsSupp( xPropSet, uno::UNO_QUERY ); |
2482 | 21.3k | if( !xFormatsSupp.is() ) |
2483 | 0 | return; |
2484 | | |
2485 | | // get XNumberFormatTypes from XNumberFormatsSupplier to get standard index |
2486 | 21.3k | uno::Reference< util::XNumberFormats > xFormats( xFormatsSupp->getNumberFormats() ); |
2487 | 21.3k | uno::Reference< util::XNumberFormatTypes > xFormatTypes( xFormats, uno::UNO_QUERY ); |
2488 | 21.3k | if( xFormatTypes.is() ) |
2489 | 21.3k | { |
2490 | 21.3k | lang::Locale eLocale; |
2491 | 21.3k | nDefaultFormat = xFormatTypes->getStandardIndex( eLocale ); |
2492 | 21.3k | xFormatter->attachNumberFormatsSupplier( xFormatsSupp ); |
2493 | 21.3k | bHasValidFormat = true; |
2494 | 21.3k | } |
2495 | 21.3k | } |
2496 | | |
2497 | | double ScaAnyConverter::convertToDouble( const OUString& rString ) const |
2498 | 0 | { |
2499 | 0 | double fValue = 0.0; |
2500 | 0 | if( bHasValidFormat ) |
2501 | 0 | { |
2502 | 0 | try |
2503 | 0 | { |
2504 | 0 | fValue = xFormatter->convertStringToNumber( nDefaultFormat, rString ); |
2505 | 0 | } |
2506 | 0 | catch( uno::Exception& ) |
2507 | 0 | { |
2508 | 0 | throw lang::IllegalArgumentException(); |
2509 | 0 | } |
2510 | 0 | } |
2511 | 0 | else |
2512 | 0 | { |
2513 | 0 | rtl_math_ConversionStatus eStatus; |
2514 | 0 | sal_Int32 nEnd; |
2515 | 0 | fValue = ::rtl::math::stringToDouble( rString, '.', ',', &eStatus, &nEnd ); |
2516 | 0 | if( (eStatus != rtl_math_ConversionStatus_Ok) || (nEnd < rString.getLength()) ) |
2517 | 0 | throw lang::IllegalArgumentException(); |
2518 | 0 | } |
2519 | 0 | return fValue; |
2520 | 0 | } |
2521 | | |
2522 | | bool ScaAnyConverter::getDouble( |
2523 | | double& rfResult, |
2524 | | const uno::Any& rAny ) const |
2525 | 21.3k | { |
2526 | 21.3k | rfResult = 0.0; |
2527 | 21.3k | bool bContainsVal = true; |
2528 | 21.3k | switch( rAny.getValueTypeClass() ) |
2529 | 21.3k | { |
2530 | 21.3k | case uno::TypeClass_VOID: |
2531 | 21.3k | bContainsVal = false; |
2532 | 21.3k | break; |
2533 | 0 | case uno::TypeClass_STRING: |
2534 | 0 | { |
2535 | 0 | auto pString = o3tl::forceAccess< OUString >( rAny ); |
2536 | 0 | if( !pString->isEmpty() ) |
2537 | 0 | rfResult = convertToDouble( *pString ); |
2538 | 0 | else |
2539 | 0 | bContainsVal = false; |
2540 | 0 | } |
2541 | 0 | break; |
2542 | 0 | case uno::TypeClass_HYPER: |
2543 | 0 | rfResult = rAny.get<sal_Int64>(); |
2544 | 0 | break; |
2545 | 0 | case uno::TypeClass_UNSIGNED_HYPER: |
2546 | 0 | rfResult = rAny.get<sal_uInt64>(); |
2547 | 0 | break; |
2548 | 10 | default: |
2549 | 10 | if( !( rAny >>= rfResult ) ) |
2550 | 0 | throw lang::IllegalArgumentException(); |
2551 | 21.3k | } |
2552 | | |
2553 | 21.3k | return bContainsVal; |
2554 | 21.3k | } |
2555 | | |
2556 | | bool ScaAnyConverter::getDouble( |
2557 | | double& rfResult, |
2558 | | const uno::Reference< beans::XPropertySet >& xPropSet, |
2559 | | const uno::Any& rAny ) |
2560 | 21.3k | { |
2561 | 21.3k | init( xPropSet ); |
2562 | 21.3k | return getDouble( rfResult, rAny ); |
2563 | 21.3k | } |
2564 | | |
2565 | | double ScaAnyConverter::getDouble( |
2566 | | const uno::Reference< beans::XPropertySet >& xPropSet, |
2567 | | const uno::Any& rAny, |
2568 | | double fDefault ) |
2569 | 4 | { |
2570 | 4 | double fResult; |
2571 | 4 | if( !getDouble( fResult, xPropSet, rAny ) ) |
2572 | 0 | fResult = fDefault; |
2573 | 4 | return fResult; |
2574 | 4 | } |
2575 | | |
2576 | | bool ScaAnyConverter::getInt32( |
2577 | | sal_Int32& rnResult, |
2578 | | const uno::Reference< beans::XPropertySet >& xPropSet, |
2579 | | const uno::Any& rAny ) |
2580 | 21.3k | { |
2581 | 21.3k | double fResult; |
2582 | 21.3k | bool bContainsVal = getDouble( fResult, xPropSet, rAny ); |
2583 | 21.3k | if( (fResult <= -2147483649.0) || (fResult >= 2147483648.0) ) |
2584 | 0 | throw lang::IllegalArgumentException(); |
2585 | | |
2586 | 21.3k | rnResult = static_cast< sal_Int32 >( fResult ); |
2587 | 21.3k | return bContainsVal; |
2588 | 21.3k | } |
2589 | | |
2590 | | sal_Int32 ScaAnyConverter::getInt32( |
2591 | | const uno::Reference< beans::XPropertySet >& xPropSet, |
2592 | | const uno::Any& rAny, |
2593 | | sal_Int32 nDefault ) |
2594 | 4 | { |
2595 | 4 | sal_Int32 nResult; |
2596 | 4 | if( !getInt32( nResult, xPropSet, rAny ) ) |
2597 | 0 | nResult = nDefault; |
2598 | 4 | return nResult; |
2599 | 4 | } |
2600 | | |
2601 | | } |
2602 | | |
2603 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |