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