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