| File: | sal/rtl/source/math.cxx |
| Location: | line 514, column 29 |
| Description: | Dereference of null pointer |
| 1 | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ | |||
| 2 | /************************************************************************* | |||
| 3 | * | |||
| 4 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |||
| 5 | * | |||
| 6 | * Copyright 2000, 2010 Oracle and/or its affiliates. | |||
| 7 | * | |||
| 8 | * OpenOffice.org - a multi-platform office productivity suite | |||
| 9 | * | |||
| 10 | * This file is part of OpenOffice.org. | |||
| 11 | * | |||
| 12 | * OpenOffice.org is free software: you can redistribute it and/or modify | |||
| 13 | * it under the terms of the GNU Lesser General Public License version 3 | |||
| 14 | * only, as published by the Free Software Foundation. | |||
| 15 | * | |||
| 16 | * OpenOffice.org is distributed in the hope that it will be useful, | |||
| 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| 19 | * GNU Lesser General Public License version 3 for more details | |||
| 20 | * (a copy is included in the LICENSE file that accompanied this code). | |||
| 21 | * | |||
| 22 | * You should have received a copy of the GNU Lesser General Public License | |||
| 23 | * version 3 along with OpenOffice.org. If not, see | |||
| 24 | * <http://www.openoffice.org/license.html> | |||
| 25 | * for a copy of the LGPLv3 License. | |||
| 26 | * | |||
| 27 | ************************************************************************/ | |||
| 28 | ||||
| 29 | ||||
| 30 | #include "rtl/math.h" | |||
| 31 | ||||
| 32 | #include "osl/diagnose.h" | |||
| 33 | #include "rtl/alloc.h" | |||
| 34 | #include "rtl/math.hxx" | |||
| 35 | #include "rtl/strbuf.h" | |||
| 36 | #include "rtl/string.h" | |||
| 37 | #include "rtl/ustrbuf.h" | |||
| 38 | #include "rtl/ustring.h" | |||
| 39 | #include "sal/mathconf.h" | |||
| 40 | #include "sal/types.h" | |||
| 41 | ||||
| 42 | #include <algorithm> | |||
| 43 | #include <float.h> | |||
| 44 | #include <limits.h> | |||
| 45 | #include <math.h> | |||
| 46 | #include <stdlib.h> | |||
| 47 | ||||
| 48 | ||||
| 49 | static int const n10Count = 16; | |||
| 50 | static double const n10s[2][n10Count] = { | |||
| 51 | { 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, | |||
| 52 | 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16 }, | |||
| 53 | { 1e-1, 1e-2, 1e-3, 1e-4, 1e-5, 1e-6, 1e-7, 1e-8, | |||
| 54 | 1e-9, 1e-10, 1e-11, 1e-12, 1e-13, 1e-14, 1e-15, 1e-16 } | |||
| 55 | }; | |||
| 56 | ||||
| 57 | // return pow(10.0,nExp) optimized for exponents in the interval [-16,16] | |||
| 58 | static double getN10Exp( int nExp ) | |||
| 59 | { | |||
| 60 | if ( nExp < 0 ) | |||
| 61 | { | |||
| 62 | // && -nExp > 0 necessary for std::numeric_limits<int>::min() | |||
| 63 | // because -nExp = nExp | |||
| 64 | if ( -nExp <= n10Count && -nExp > 0 ) | |||
| 65 | return n10s[1][-nExp-1]; | |||
| 66 | else | |||
| 67 | return pow( 10.0, static_cast<double>( nExp ) ); | |||
| 68 | } | |||
| 69 | else if ( nExp > 0 ) | |||
| 70 | { | |||
| 71 | if ( nExp <= n10Count ) | |||
| 72 | return n10s[0][nExp-1]; | |||
| 73 | else | |||
| 74 | return pow( 10.0, static_cast<double>( nExp ) ); | |||
| 75 | } | |||
| 76 | else // ( nExp == 0 ) | |||
| 77 | return 1.0; | |||
| 78 | } | |||
| 79 | ||||
| 80 | /** Approximation algorithm for erf for 0 < x < 0.65. */ | |||
| 81 | void lcl_Erf0065( double x, double& fVal ) | |||
| 82 | { | |||
| 83 | static const double pn[] = { | |||
| 84 | 1.12837916709551256, | |||
| 85 | 1.35894887627277916E-1, | |||
| 86 | 4.03259488531795274E-2, | |||
| 87 | 1.20339380863079457E-3, | |||
| 88 | 6.49254556481904354E-5 | |||
| 89 | }; | |||
| 90 | static const double qn[] = { | |||
| 91 | 1.00000000000000000, | |||
| 92 | 4.53767041780002545E-1, | |||
| 93 | 8.69936222615385890E-2, | |||
| 94 | 8.49717371168693357E-3, | |||
| 95 | 3.64915280629351082E-4 | |||
| 96 | }; | |||
| 97 | double fPSum = 0.0; | |||
| 98 | double fQSum = 0.0; | |||
| 99 | double fXPow = 1.0; | |||
| 100 | for ( unsigned int i = 0; i <= 4; ++i ) | |||
| 101 | { | |||
| 102 | fPSum += pn[i]*fXPow; | |||
| 103 | fQSum += qn[i]*fXPow; | |||
| 104 | fXPow *= x*x; | |||
| 105 | } | |||
| 106 | fVal = x * fPSum / fQSum; | |||
| 107 | } | |||
| 108 | ||||
| 109 | /** Approximation algorithm for erfc for 0.65 < x < 6.0. */ | |||
| 110 | void lcl_Erfc0600( double x, double& fVal ) | |||
| 111 | { | |||
| 112 | double fPSum = 0.0; | |||
| 113 | double fQSum = 0.0; | |||
| 114 | double fXPow = 1.0; | |||
| 115 | const double *pn; | |||
| 116 | const double *qn; | |||
| 117 | ||||
| 118 | if ( x < 2.2 ) | |||
| 119 | { | |||
| 120 | static const double pn22[] = { | |||
| 121 | 9.99999992049799098E-1, | |||
| 122 | 1.33154163936765307, | |||
| 123 | 8.78115804155881782E-1, | |||
| 124 | 3.31899559578213215E-1, | |||
| 125 | 7.14193832506776067E-2, | |||
| 126 | 7.06940843763253131E-3 | |||
| 127 | }; | |||
| 128 | static const double qn22[] = { | |||
| 129 | 1.00000000000000000, | |||
| 130 | 2.45992070144245533, | |||
| 131 | 2.65383972869775752, | |||
| 132 | 1.61876655543871376, | |||
| 133 | 5.94651311286481502E-1, | |||
| 134 | 1.26579413030177940E-1, | |||
| 135 | 1.25304936549413393E-2 | |||
| 136 | }; | |||
| 137 | pn = pn22; | |||
| 138 | qn = qn22; | |||
| 139 | } | |||
| 140 | else /* if ( x < 6.0 ) this is true, but the compiler does not know */ | |||
| 141 | { | |||
| 142 | static const double pn60[] = { | |||
| 143 | 9.99921140009714409E-1, | |||
| 144 | 1.62356584489366647, | |||
| 145 | 1.26739901455873222, | |||
| 146 | 5.81528574177741135E-1, | |||
| 147 | 1.57289620742838702E-1, | |||
| 148 | 2.25716982919217555E-2 | |||
| 149 | }; | |||
| 150 | static const double qn60[] = { | |||
| 151 | 1.00000000000000000, | |||
| 152 | 2.75143870676376208, | |||
| 153 | 3.37367334657284535, | |||
| 154 | 2.38574194785344389, | |||
| 155 | 1.05074004614827206, | |||
| 156 | 2.78788439273628983E-1, | |||
| 157 | 4.00072964526861362E-2 | |||
| 158 | }; | |||
| 159 | pn = pn60; | |||
| 160 | qn = qn60; | |||
| 161 | } | |||
| 162 | ||||
| 163 | for ( unsigned int i = 0; i < 6; ++i ) | |||
| 164 | { | |||
| 165 | fPSum += pn[i]*fXPow; | |||
| 166 | fQSum += qn[i]*fXPow; | |||
| 167 | fXPow *= x; | |||
| 168 | } | |||
| 169 | fQSum += qn[6]*fXPow; | |||
| 170 | fVal = exp( -1.0*x*x )* fPSum / fQSum; | |||
| 171 | } | |||
| 172 | ||||
| 173 | /** Approximation algorithm for erfc for 6.0 < x < 26.54 (but used for all | |||
| 174 | x > 6.0). */ | |||
| 175 | void lcl_Erfc2654( double x, double& fVal ) | |||
| 176 | { | |||
| 177 | static const double pn[] = { | |||
| 178 | 5.64189583547756078E-1, | |||
| 179 | 8.80253746105525775, | |||
| 180 | 3.84683103716117320E1, | |||
| 181 | 4.77209965874436377E1, | |||
| 182 | 8.08040729052301677 | |||
| 183 | }; | |||
| 184 | static const double qn[] = { | |||
| 185 | 1.00000000000000000, | |||
| 186 | 1.61020914205869003E1, | |||
| 187 | 7.54843505665954743E1, | |||
| 188 | 1.12123870801026015E2, | |||
| 189 | 3.73997570145040850E1 | |||
| 190 | }; | |||
| 191 | ||||
| 192 | double fPSum = 0.0; | |||
| 193 | double fQSum = 0.0; | |||
| 194 | double fXPow = 1.0; | |||
| 195 | ||||
| 196 | for ( unsigned int i = 0; i <= 4; ++i ) | |||
| 197 | { | |||
| 198 | fPSum += pn[i]*fXPow; | |||
| 199 | fQSum += qn[i]*fXPow; | |||
| 200 | fXPow /= x*x; | |||
| 201 | } | |||
| 202 | fVal = exp(-1.0*x*x)*fPSum / (x*fQSum); | |||
| 203 | } | |||
| 204 | ||||
| 205 | namespace { | |||
| 206 | ||||
| 207 | double const nKorrVal[] = { | |||
| 208 | 0, 9e-1, 9e-2, 9e-3, 9e-4, 9e-5, 9e-6, 9e-7, 9e-8, | |||
| 209 | 9e-9, 9e-10, 9e-11, 9e-12, 9e-13, 9e-14, 9e-15 | |||
| 210 | }; | |||
| 211 | ||||
| 212 | struct StringTraits | |||
| 213 | { | |||
| 214 | typedef sal_Char Char; | |||
| 215 | ||||
| 216 | typedef rtl_String String; | |||
| 217 | ||||
| 218 | static inline void createString(rtl_String ** pString, | |||
| 219 | sal_Char const * pChars, sal_Int32 nLen) | |||
| 220 | { | |||
| 221 | rtl_string_newFromStr_WithLength(pString, pChars, nLen); | |||
| 222 | } | |||
| 223 | ||||
| 224 | static inline void createBuffer(rtl_String ** pBuffer, | |||
| 225 | sal_Int32 * pCapacity) | |||
| 226 | { | |||
| 227 | rtl_string_new_WithLength(pBuffer, *pCapacity); | |||
| 228 | } | |||
| 229 | ||||
| 230 | static inline void appendChar(rtl_String ** pBuffer, sal_Int32 * pCapacity, | |||
| 231 | sal_Int32 * pOffset, sal_Char cChar) | |||
| 232 | { | |||
| 233 | rtl_stringbuffer_insert(pBuffer, pCapacity, *pOffset, &cChar, 1); | |||
| 234 | ++*pOffset; | |||
| 235 | } | |||
| 236 | ||||
| 237 | static inline void appendChars(rtl_String ** pBuffer, sal_Int32 * pCapacity, | |||
| 238 | sal_Int32 * pOffset, sal_Char const * pChars, | |||
| 239 | sal_Int32 nLen) | |||
| 240 | { | |||
| 241 | rtl_stringbuffer_insert(pBuffer, pCapacity, *pOffset, pChars, nLen); | |||
| 242 | *pOffset += nLen; | |||
| 243 | } | |||
| 244 | ||||
| 245 | static inline void appendAscii(rtl_String ** pBuffer, sal_Int32 * pCapacity, | |||
| 246 | sal_Int32 * pOffset, sal_Char const * pStr, | |||
| 247 | sal_Int32 nLen) | |||
| 248 | { | |||
| 249 | rtl_stringbuffer_insert(pBuffer, pCapacity, *pOffset, pStr, nLen); | |||
| 250 | *pOffset += nLen; | |||
| 251 | } | |||
| 252 | }; | |||
| 253 | ||||
| 254 | struct UStringTraits | |||
| 255 | { | |||
| 256 | typedef sal_Unicode Char; | |||
| 257 | ||||
| 258 | typedef rtl_uString String; | |||
| 259 | ||||
| 260 | static inline void createString(rtl_uString ** pString, | |||
| 261 | sal_Unicode const * pChars, sal_Int32 nLen) | |||
| 262 | { | |||
| 263 | rtl_uString_newFromStr_WithLength(pString, pChars, nLen); | |||
| 264 | } | |||
| 265 | ||||
| 266 | static inline void createBuffer(rtl_uString ** pBuffer, | |||
| 267 | sal_Int32 * pCapacity) | |||
| 268 | { | |||
| 269 | rtl_uString_new_WithLength(pBuffer, *pCapacity); | |||
| 270 | } | |||
| 271 | ||||
| 272 | static inline void appendChar(rtl_uString ** pBuffer, sal_Int32 * pCapacity, | |||
| 273 | sal_Int32 * pOffset, sal_Unicode cChar) | |||
| 274 | { | |||
| 275 | rtl_uStringbuffer_insert(pBuffer, pCapacity, *pOffset, &cChar, 1); | |||
| 276 | ++*pOffset; | |||
| 277 | } | |||
| 278 | ||||
| 279 | static inline void appendChars(rtl_uString ** pBuffer, | |||
| 280 | sal_Int32 * pCapacity, sal_Int32 * pOffset, | |||
| 281 | sal_Unicode const * pChars, sal_Int32 nLen) | |||
| 282 | { | |||
| 283 | rtl_uStringbuffer_insert(pBuffer, pCapacity, *pOffset, pChars, nLen); | |||
| 284 | *pOffset += nLen; | |||
| 285 | } | |||
| 286 | ||||
| 287 | static inline void appendAscii(rtl_uString ** pBuffer, | |||
| 288 | sal_Int32 * pCapacity, sal_Int32 * pOffset, | |||
| 289 | sal_Char const * pStr, sal_Int32 nLen) | |||
| 290 | { | |||
| 291 | rtl_uStringbuffer_insert_ascii(pBuffer, pCapacity, *pOffset, pStr, | |||
| 292 | nLen); | |||
| 293 | *pOffset += nLen; | |||
| 294 | } | |||
| 295 | }; | |||
| 296 | ||||
| 297 | ||||
| 298 | // Solaris C++ 5.2 compiler has problems when "StringT ** pResult" is | |||
| 299 | // "typename T::String ** pResult" instead: | |||
| 300 | template< typename T, typename StringT > | |||
| 301 | inline void doubleToString(StringT ** pResult, | |||
| 302 | sal_Int32 * pResultCapacity, sal_Int32 nResultOffset, | |||
| 303 | double fValue, rtl_math_StringFormat eFormat, | |||
| 304 | sal_Int32 nDecPlaces, typename T::Char cDecSeparator, | |||
| 305 | sal_Int32 const * pGroups, | |||
| 306 | typename T::Char cGroupSeparator, | |||
| 307 | bool bEraseTrailingDecZeros) | |||
| 308 | { | |||
| 309 | static double const nRoundVal[] = { | |||
| 310 | 5.0e+0, 0.5e+0, 0.5e-1, 0.5e-2, 0.5e-3, 0.5e-4, 0.5e-5, 0.5e-6, | |||
| 311 | 0.5e-7, 0.5e-8, 0.5e-9, 0.5e-10,0.5e-11,0.5e-12,0.5e-13,0.5e-14 | |||
| 312 | }; | |||
| 313 | ||||
| 314 | // sign adjustment, instead of testing for fValue<0.0 this will also fetch | |||
| 315 | // -0.0 | |||
| 316 | bool bSign = rtl::math::isSignBitSet( fValue ); | |||
| 317 | if( bSign ) | |||
| 318 | fValue = -fValue; | |||
| 319 | ||||
| 320 | if ( rtl::math::isNan( fValue ) ) | |||
| 321 | { | |||
| 322 | // #i112652# XMLSchema-2 | |||
| 323 | sal_Int32 nCapacity = RTL_CONSTASCII_LENGTH("NaN")((sal_Int32)((sizeof ("NaN") / sizeof (("NaN")[0]))-1)); | |||
| 324 | if (pResultCapacity == 0) | |||
| 325 | { | |||
| 326 | pResultCapacity = &nCapacity; | |||
| 327 | T::createBuffer(pResult, pResultCapacity); | |||
| 328 | nResultOffset = 0; | |||
| 329 | } | |||
| 330 | T::appendAscii(pResult, pResultCapacity, &nResultOffset, | |||
| 331 | RTL_CONSTASCII_STRINGPARAM("NaN")(&("NaN")[0]), ((sal_Int32)(sizeof ("NaN") / sizeof (("NaN" )[0]))-1)); | |||
| 332 | ||||
| 333 | return; | |||
| 334 | } | |||
| 335 | ||||
| 336 | bool bHuge = fValue == HUGE_VAL(__builtin_huge_val()); // g++ 3.0.1 requires it this way... | |||
| 337 | if ( bHuge || rtl::math::isInf( fValue ) ) | |||
| 338 | { | |||
| 339 | // #i112652# XMLSchema-2 | |||
| 340 | sal_Int32 nCapacity = RTL_CONSTASCII_LENGTH("-INF")((sal_Int32)((sizeof ("-INF") / sizeof (("-INF")[0]))-1)); | |||
| 341 | if (pResultCapacity == 0) | |||
| 342 | { | |||
| 343 | pResultCapacity = &nCapacity; | |||
| 344 | T::createBuffer(pResult, pResultCapacity); | |||
| 345 | nResultOffset = 0; | |||
| 346 | } | |||
| 347 | if ( bSign ) | |||
| 348 | T::appendAscii(pResult, pResultCapacity, &nResultOffset, | |||
| 349 | RTL_CONSTASCII_STRINGPARAM("-")(&("-")[0]), ((sal_Int32)(sizeof ("-") / sizeof (("-")[0] ))-1)); | |||
| 350 | T::appendAscii(pResult, pResultCapacity, &nResultOffset, | |||
| 351 | RTL_CONSTASCII_STRINGPARAM("INF")(&("INF")[0]), ((sal_Int32)(sizeof ("INF") / sizeof (("INF" )[0]))-1)); | |||
| 352 | ||||
| 353 | return; | |||
| 354 | } | |||
| 355 | ||||
| 356 | // find the exponent | |||
| 357 | int nExp = 0; | |||
| 358 | if ( fValue > 0.0 ) | |||
| 359 | { | |||
| 360 | nExp = static_cast< int >( floor( log10( fValue ) ) ); | |||
| 361 | fValue /= getN10Exp( nExp ); | |||
| 362 | } | |||
| 363 | ||||
| 364 | switch ( eFormat ) | |||
| 365 | { | |||
| 366 | case rtl_math_StringFormat_Automatic : | |||
| 367 | { // E or F depending on exponent magnitude | |||
| 368 | int nPrec; | |||
| 369 | if ( nExp <= -15 || nExp >= 15 ) // #58531# was <-16, >16 | |||
| 370 | { | |||
| 371 | nPrec = 14; | |||
| 372 | eFormat = rtl_math_StringFormat_E; | |||
| 373 | } | |||
| 374 | else | |||
| 375 | { | |||
| 376 | if ( nExp < 14 ) | |||
| 377 | { | |||
| 378 | nPrec = 15 - nExp - 1; | |||
| 379 | eFormat = rtl_math_StringFormat_F; | |||
| 380 | } | |||
| 381 | else | |||
| 382 | { | |||
| 383 | nPrec = 15; | |||
| 384 | eFormat = rtl_math_StringFormat_F; | |||
| 385 | } | |||
| 386 | } | |||
| 387 | if ( nDecPlaces == rtl_math_DecimalPlaces_Max ) | |||
| 388 | nDecPlaces = nPrec; | |||
| 389 | } | |||
| 390 | break; | |||
| 391 | case rtl_math_StringFormat_G : | |||
| 392 | { // G-Point, similar to sprintf %G | |||
| 393 | if ( nDecPlaces == rtl_math_DecimalPlaces_DefaultSignificance ) | |||
| 394 | nDecPlaces = 6; | |||
| 395 | if ( nExp < -4 || nExp >= nDecPlaces ) | |||
| 396 | { | |||
| 397 | nDecPlaces = std::max< sal_Int32 >( 1, nDecPlaces - 1 ); | |||
| 398 | eFormat = rtl_math_StringFormat_E; | |||
| 399 | } | |||
| 400 | else | |||
| 401 | { | |||
| 402 | nDecPlaces = std::max< sal_Int32 >( 0, nDecPlaces - nExp - 1 ); | |||
| 403 | eFormat = rtl_math_StringFormat_F; | |||
| 404 | } | |||
| 405 | } | |||
| 406 | break; | |||
| 407 | default: | |||
| 408 | break; | |||
| 409 | } | |||
| 410 | ||||
| 411 | sal_Int32 nDigits = nDecPlaces + 1; | |||
| 412 | ||||
| 413 | if( eFormat == rtl_math_StringFormat_F ) | |||
| 414 | nDigits += nExp; | |||
| 415 | ||||
| 416 | // Round the number | |||
| 417 | if( nDigits >= 0 ) | |||
| 418 | { | |||
| 419 | if( ( fValue += nRoundVal[ nDigits > 15 ? 15 : nDigits ] ) >= 10 ) | |||
| 420 | { | |||
| 421 | fValue = 1.0; | |||
| 422 | nExp++; | |||
| 423 | if( eFormat == rtl_math_StringFormat_F ) | |||
| 424 | nDigits++; | |||
| 425 | } | |||
| 426 | } | |||
| 427 | ||||
| 428 | static sal_Int32 const nBufMax = 256; | |||
| 429 | typename T::Char aBuf[nBufMax]; | |||
| 430 | typename T::Char * pBuf; | |||
| 431 | sal_Int32 nBuf = static_cast< sal_Int32 > | |||
| 432 | ( nDigits <= 0 ? std::max< sal_Int32 >( nDecPlaces, abs(nExp) ) | |||
| 433 | : nDigits + nDecPlaces ) + 10 + (pGroups ? abs(nDigits) * 2 : 0); | |||
| 434 | if ( nBuf > nBufMax ) | |||
| 435 | { | |||
| 436 | pBuf = reinterpret_cast< typename T::Char * >( | |||
| 437 | rtl_allocateMemory(nBuf * sizeof (typename T::Char))); | |||
| 438 | OSL_ENSURE(pBuf != 0, "Out of memory")do { if (true && (!(pBuf != 0))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/usr/local/src/libreoffice/sal/rtl/source/math.cxx" ":" "438" ": "), "%s", "Out of memory"); } } while (false); | |||
| 439 | } | |||
| 440 | else | |||
| 441 | pBuf = aBuf; | |||
| 442 | typename T::Char * p = pBuf; | |||
| 443 | if ( bSign ) | |||
| 444 | *p++ = static_cast< typename T::Char >('-'); | |||
| 445 | ||||
| 446 | bool bHasDec = false; | |||
| 447 | ||||
| 448 | int nDecPos; | |||
| 449 | // Check for F format and number < 1 | |||
| 450 | if( eFormat == rtl_math_StringFormat_F ) | |||
| 451 | { | |||
| 452 | if( nExp < 0 ) | |||
| 453 | { | |||
| 454 | *p++ = static_cast< typename T::Char >('0'); | |||
| 455 | if ( nDecPlaces > 0 ) | |||
| 456 | { | |||
| 457 | *p++ = cDecSeparator; | |||
| 458 | bHasDec = true; | |||
| 459 | } | |||
| 460 | sal_Int32 i = ( nDigits <= 0 ? nDecPlaces : -nExp - 1 ); | |||
| 461 | while( (i--) > 0 ) | |||
| 462 | *p++ = static_cast< typename T::Char >('0'); | |||
| 463 | nDecPos = 0; | |||
| 464 | } | |||
| 465 | else | |||
| 466 | nDecPos = nExp + 1; | |||
| 467 | } | |||
| 468 | else | |||
| 469 | nDecPos = 1; | |||
| 470 | ||||
| 471 | int nGrouping = 0, nGroupSelector = 0, nGroupExceed = 0; | |||
| 472 | if ( nDecPos > 1 && pGroups && pGroups[0] && cGroupSeparator ) | |||
| 473 | { | |||
| 474 | while ( nGrouping + pGroups[nGroupSelector] < nDecPos ) | |||
| 475 | { | |||
| 476 | nGrouping += pGroups[ nGroupSelector ]; | |||
| 477 | if ( pGroups[nGroupSelector+1] ) | |||
| 478 | { | |||
| 479 | if ( nGrouping + pGroups[nGroupSelector+1] >= nDecPos ) | |||
| 480 | break; // while | |||
| 481 | ++nGroupSelector; | |||
| 482 | } | |||
| 483 | else if ( !nGroupExceed ) | |||
| 484 | nGroupExceed = nGrouping; | |||
| 485 | } | |||
| 486 | } | |||
| 487 | ||||
| 488 | // print the number | |||
| 489 | if( nDigits > 0 ) | |||
| 490 | { | |||
| 491 | for ( int i = 0; ; i++ ) | |||
| 492 | { | |||
| 493 | if( i < 15 ) | |||
| 494 | { | |||
| 495 | int nDigit; | |||
| 496 | if (nDigits-1 == 0 && i > 0 && i < 14) | |||
| 497 | nDigit = static_cast< int >( floor( fValue | |||
| 498 | + nKorrVal[15-i] ) ); | |||
| 499 | else | |||
| 500 | nDigit = static_cast< int >( fValue + 1E-15 ); | |||
| 501 | if (nDigit >= 10) | |||
| 502 | { // after-treatment of up-rounding to the next decade | |||
| 503 | sal_Int32 sLen = static_cast< long >(p-pBuf)-1; | |||
| 504 | if (sLen == -1) | |||
| 505 | { | |||
| 506 | p = pBuf; | |||
| 507 | if ( eFormat == rtl_math_StringFormat_F ) | |||
| 508 | { | |||
| 509 | *p++ = static_cast< typename T::Char >('1'); | |||
| 510 | *p++ = static_cast< typename T::Char >('0'); | |||
| 511 | } | |||
| 512 | else | |||
| 513 | { | |||
| 514 | *p++ = static_cast< typename T::Char >('1'); | |||
| ||||
| 515 | *p++ = cDecSeparator; | |||
| 516 | *p++ = static_cast< typename T::Char >('0'); | |||
| 517 | nExp++; | |||
| 518 | bHasDec = true; | |||
| 519 | } | |||
| 520 | } | |||
| 521 | else | |||
| 522 | { | |||
| 523 | for (sal_Int32 j = sLen; j >= 0; j--) | |||
| 524 | { | |||
| 525 | typename T::Char cS = pBuf[j]; | |||
| 526 | if (cS != cDecSeparator) | |||
| 527 | { | |||
| 528 | if ( cS != static_cast< typename T::Char >('9')) | |||
| 529 | { | |||
| 530 | pBuf[j] = ++cS; | |||
| 531 | j = -1; // break loop | |||
| 532 | } | |||
| 533 | else | |||
| 534 | { | |||
| 535 | pBuf[j] | |||
| 536 | = static_cast< typename T::Char >('0'); | |||
| 537 | if (j == 0) | |||
| 538 | { | |||
| 539 | if ( eFormat == rtl_math_StringFormat_F) | |||
| 540 | { // insert '1' | |||
| 541 | typename T::Char * px = p++; | |||
| 542 | while ( pBuf < px ) | |||
| 543 | { | |||
| 544 | *px = *(px-1); | |||
| 545 | px--; | |||
| 546 | } | |||
| 547 | pBuf[0] = static_cast< | |||
| 548 | typename T::Char >('1'); | |||
| 549 | } | |||
| 550 | else | |||
| 551 | { | |||
| 552 | pBuf[j] = static_cast< | |||
| 553 | typename T::Char >('1'); | |||
| 554 | nExp++; | |||
| 555 | } | |||
| 556 | } | |||
| 557 | } | |||
| 558 | } | |||
| 559 | } | |||
| 560 | *p++ = static_cast< typename T::Char >('0'); | |||
| 561 | } | |||
| 562 | fValue = 0.0; | |||
| 563 | } | |||
| 564 | else | |||
| 565 | { | |||
| 566 | *p++ = static_cast< typename T::Char >( | |||
| 567 | nDigit + static_cast< typename T::Char >('0') ); | |||
| 568 | fValue = ( fValue - nDigit ) * 10.0; | |||
| 569 | } | |||
| 570 | } | |||
| 571 | else | |||
| 572 | *p++ = static_cast< typename T::Char >('0'); | |||
| 573 | if( !--nDigits ) | |||
| 574 | break; // for | |||
| 575 | if( nDecPos ) | |||
| 576 | { | |||
| 577 | if( !--nDecPos ) | |||
| 578 | { | |||
| 579 | *p++ = cDecSeparator; | |||
| 580 | bHasDec = true; | |||
| 581 | } | |||
| 582 | else if ( nDecPos == nGrouping ) | |||
| 583 | { | |||
| 584 | *p++ = cGroupSeparator; | |||
| 585 | nGrouping -= pGroups[ nGroupSelector ]; | |||
| 586 | if ( nGroupSelector && nGrouping < nGroupExceed ) | |||
| 587 | --nGroupSelector; | |||
| 588 | } | |||
| 589 | } | |||
| 590 | } | |||
| 591 | } | |||
| 592 | ||||
| 593 | if ( !bHasDec && eFormat == rtl_math_StringFormat_F ) | |||
| 594 | { // nDecPlaces < 0 did round the value | |||
| 595 | while ( --nDecPos > 0 ) | |||
| 596 | { // fill before decimal point | |||
| 597 | if ( nDecPos == nGrouping ) | |||
| 598 | { | |||
| 599 | *p++ = cGroupSeparator; | |||
| 600 | nGrouping -= pGroups[ nGroupSelector ]; | |||
| 601 | if ( nGroupSelector && nGrouping < nGroupExceed ) | |||
| 602 | --nGroupSelector; | |||
| 603 | } | |||
| 604 | *p++ = static_cast< typename T::Char >('0'); | |||
| 605 | } | |||
| 606 | } | |||
| 607 | ||||
| 608 | if ( bEraseTrailingDecZeros && bHasDec && p > pBuf ) | |||
| 609 | { | |||
| 610 | while ( *(p-1) == static_cast< typename T::Char >('0') ) | |||
| 611 | p--; | |||
| 612 | if ( *(p-1) == cDecSeparator ) | |||
| 613 | p--; | |||
| 614 | } | |||
| 615 | ||||
| 616 | // Print the exponent ('E', followed by '+' or '-', followed by exactly | |||
| 617 | // three digits). The code in rtl_[u]str_valueOf{Float|Double} relies on | |||
| 618 | // this format. | |||
| 619 | if( eFormat == rtl_math_StringFormat_E ) | |||
| 620 | { | |||
| 621 | if ( p == pBuf ) | |||
| 622 | *p++ = static_cast< typename T::Char >('1'); | |||
| 623 | // maybe no nDigits if nDecPlaces < 0 | |||
| 624 | *p++ = static_cast< typename T::Char >('E'); | |||
| 625 | if( nExp < 0 ) | |||
| 626 | { | |||
| 627 | nExp = -nExp; | |||
| 628 | *p++ = static_cast< typename T::Char >('-'); | |||
| 629 | } | |||
| 630 | else | |||
| 631 | *p++ = static_cast< typename T::Char >('+'); | |||
| 632 | // if (nExp >= 100 ) | |||
| 633 | *p++ = static_cast< typename T::Char >( | |||
| 634 | nExp / 100 + static_cast< typename T::Char >('0') ); | |||
| 635 | nExp %= 100; | |||
| 636 | *p++ = static_cast< typename T::Char >( | |||
| 637 | nExp / 10 + static_cast< typename T::Char >('0') ); | |||
| 638 | *p++ = static_cast< typename T::Char >( | |||
| 639 | nExp % 10 + static_cast< typename T::Char >('0') ); | |||
| 640 | } | |||
| 641 | ||||
| 642 | if (pResultCapacity == 0) | |||
| 643 | T::createString(pResult, pBuf, p - pBuf); | |||
| 644 | else | |||
| 645 | T::appendChars(pResult, pResultCapacity, &nResultOffset, pBuf, | |||
| 646 | p - pBuf); | |||
| 647 | ||||
| 648 | if ( pBuf != &aBuf[0] ) | |||
| 649 | rtl_freeMemory(pBuf); | |||
| 650 | } | |||
| 651 | ||||
| 652 | } | |||
| 653 | ||||
| 654 | void SAL_CALL rtl_math_doubleToString(rtl_String ** pResult, | |||
| 655 | sal_Int32 * pResultCapacity, | |||
| 656 | sal_Int32 nResultOffset, double fValue, | |||
| 657 | rtl_math_StringFormat eFormat, | |||
| 658 | sal_Int32 nDecPlaces, | |||
| 659 | sal_Char cDecSeparator, | |||
| 660 | sal_Int32 const * pGroups, | |||
| 661 | sal_Char cGroupSeparator, | |||
| 662 | sal_Bool bEraseTrailingDecZeros) | |||
| 663 | SAL_THROW_EXTERN_C()throw () | |||
| 664 | { | |||
| 665 | doubleToString< StringTraits, StringTraits::String >( | |||
| 666 | pResult, pResultCapacity, nResultOffset, fValue, eFormat, nDecPlaces, | |||
| 667 | cDecSeparator, pGroups, cGroupSeparator, bEraseTrailingDecZeros); | |||
| 668 | } | |||
| 669 | ||||
| 670 | void SAL_CALL rtl_math_doubleToUString(rtl_uString ** pResult, | |||
| 671 | sal_Int32 * pResultCapacity, | |||
| 672 | sal_Int32 nResultOffset, double fValue, | |||
| 673 | rtl_math_StringFormat eFormat, | |||
| 674 | sal_Int32 nDecPlaces, | |||
| 675 | sal_Unicode cDecSeparator, | |||
| 676 | sal_Int32 const * pGroups, | |||
| 677 | sal_Unicode cGroupSeparator, | |||
| 678 | sal_Bool bEraseTrailingDecZeros) | |||
| 679 | SAL_THROW_EXTERN_C()throw () | |||
| 680 | { | |||
| 681 | doubleToString< UStringTraits, UStringTraits::String >( | |||
| ||||
| 682 | pResult, pResultCapacity, nResultOffset, fValue, eFormat, nDecPlaces, | |||
| 683 | cDecSeparator, pGroups, cGroupSeparator, bEraseTrailingDecZeros); | |||
| 684 | } | |||
| 685 | ||||
| 686 | ||||
| 687 | namespace { | |||
| 688 | ||||
| 689 | // if nExp * 10 + nAdd would result in overflow | |||
| 690 | inline bool long10Overflow( long& nExp, int nAdd ) | |||
| 691 | { | |||
| 692 | if ( nExp > (LONG_MAX2147483647L/10) | |||
| 693 | || (nExp == (LONG_MAX2147483647L/10) && nAdd > (LONG_MAX2147483647L%10)) ) | |||
| 694 | { | |||
| 695 | nExp = LONG_MAX2147483647L; | |||
| 696 | return true; | |||
| 697 | } | |||
| 698 | return false; | |||
| 699 | } | |||
| 700 | ||||
| 701 | // We are only concerned about ASCII arabic numerical digits here | |||
| 702 | template< typename CharT > | |||
| 703 | inline bool isDigit( CharT c ) | |||
| 704 | { | |||
| 705 | return 0x30 <= c && c <= 0x39; | |||
| 706 | } | |||
| 707 | ||||
| 708 | template< typename CharT > | |||
| 709 | inline double stringToDouble(CharT const * pBegin, CharT const * pEnd, | |||
| 710 | CharT cDecSeparator, CharT cGroupSeparator, | |||
| 711 | rtl_math_ConversionStatus * pStatus, | |||
| 712 | CharT const ** pParsedEnd) | |||
| 713 | { | |||
| 714 | double fVal = 0.0; | |||
| 715 | rtl_math_ConversionStatus eStatus = rtl_math_ConversionStatus_Ok; | |||
| 716 | ||||
| 717 | CharT const * p0 = pBegin; | |||
| 718 | while (p0 != pEnd && (*p0 == CharT(' ') || *p0 == CharT('\t'))) | |||
| 719 | ++p0; | |||
| 720 | bool bSign; | |||
| 721 | if (p0 != pEnd && *p0 == CharT('-')) | |||
| 722 | { | |||
| 723 | bSign = true; | |||
| 724 | ++p0; | |||
| 725 | } | |||
| 726 | else | |||
| 727 | { | |||
| 728 | bSign = false; | |||
| 729 | if (p0 != pEnd && *p0 == CharT('+')) | |||
| 730 | ++p0; | |||
| 731 | } | |||
| 732 | CharT const * p = p0; | |||
| 733 | bool bDone = false; | |||
| 734 | ||||
| 735 | // #i112652# XMLSchema-2 | |||
| 736 | if (3 >= (pEnd - p)) | |||
| 737 | { | |||
| 738 | if ((CharT('N') == p[0]) && (CharT('a') == p[1]) | |||
| 739 | && (CharT('N') == p[2])) | |||
| 740 | { | |||
| 741 | p += 3; | |||
| 742 | rtl::math::setNan( &fVal ); | |||
| 743 | bDone = true; | |||
| 744 | } | |||
| 745 | else if ((CharT('I') == p[0]) && (CharT('N') == p[1]) | |||
| 746 | && (CharT('F') == p[2])) | |||
| 747 | { | |||
| 748 | p += 3; | |||
| 749 | fVal = HUGE_VAL(__builtin_huge_val()); | |||
| 750 | eStatus = rtl_math_ConversionStatus_OutOfRange; | |||
| 751 | bDone = true; | |||
| 752 | } | |||
| 753 | } | |||
| 754 | ||||
| 755 | if (!bDone) // do not recognize e.g. NaN1.23 | |||
| 756 | { | |||
| 757 | // leading zeros and group separators may be safely ignored | |||
| 758 | while (p != pEnd && (*p == CharT('0') || *p == cGroupSeparator)) | |||
| 759 | ++p; | |||
| 760 | ||||
| 761 | long nValExp = 0; // carry along exponent of mantissa | |||
| 762 | ||||
| 763 | // integer part of mantissa | |||
| 764 | for (; p != pEnd; ++p) | |||
| 765 | { | |||
| 766 | CharT c = *p; | |||
| 767 | if (isDigit(c)) | |||
| 768 | { | |||
| 769 | fVal = fVal * 10.0 + static_cast< double >( c - CharT('0') ); | |||
| 770 | ++nValExp; | |||
| 771 | } | |||
| 772 | else if (c != cGroupSeparator) | |||
| 773 | break; | |||
| 774 | } | |||
| 775 | ||||
| 776 | // fraction part of mantissa | |||
| 777 | if (p != pEnd && *p == cDecSeparator) | |||
| 778 | { | |||
| 779 | ++p; | |||
| 780 | double fFrac = 0.0; | |||
| 781 | long nFracExp = 0; | |||
| 782 | while (p != pEnd && *p == CharT('0')) | |||
| 783 | { | |||
| 784 | --nFracExp; | |||
| 785 | ++p; | |||
| 786 | } | |||
| 787 | if ( nValExp == 0 ) | |||
| 788 | nValExp = nFracExp - 1; // no integer part => fraction exponent | |||
| 789 | // one decimal digit needs ld(10) ~= 3.32 bits | |||
| 790 | static const int nSigs = (DBL_MANT_DIG53 / 3) + 1; | |||
| 791 | int nDigs = 0; | |||
| 792 | for (; p != pEnd; ++p) | |||
| 793 | { | |||
| 794 | CharT c = *p; | |||
| 795 | if (!isDigit(c)) | |||
| 796 | break; | |||
| 797 | if ( nDigs < nSigs ) | |||
| 798 | { // further digits (more than nSigs) don't have any | |||
| 799 | // significance | |||
| 800 | fFrac = fFrac * 10.0 + static_cast<double>(c - CharT('0')); | |||
| 801 | --nFracExp; | |||
| 802 | ++nDigs; | |||
| 803 | } | |||
| 804 | } | |||
| 805 | if ( fFrac != 0.0 ) | |||
| 806 | fVal += rtl::math::pow10Exp( fFrac, nFracExp ); | |||
| 807 | else if ( nValExp < 0 ) | |||
| 808 | nValExp = 0; // no digit other than 0 after decimal point | |||
| 809 | } | |||
| 810 | ||||
| 811 | if ( nValExp > 0 ) | |||
| 812 | --nValExp; // started with offset +1 at the first mantissa digit | |||
| 813 | ||||
| 814 | // Exponent | |||
| 815 | if (p != p0 && p != pEnd && (*p == CharT('E') || *p == CharT('e'))) | |||
| 816 | { | |||
| 817 | ++p; | |||
| 818 | bool bExpSign; | |||
| 819 | if (p != pEnd && *p == CharT('-')) | |||
| 820 | { | |||
| 821 | bExpSign = true; | |||
| 822 | ++p; | |||
| 823 | } | |||
| 824 | else | |||
| 825 | { | |||
| 826 | bExpSign = false; | |||
| 827 | if (p != pEnd && *p == CharT('+')) | |||
| 828 | ++p; | |||
| 829 | } | |||
| 830 | if ( fVal == 0.0 ) | |||
| 831 | { // no matter what follows, zero stays zero, but carry on the | |||
| 832 | // offset | |||
| 833 | while (p != pEnd && isDigit(*p)) | |||
| 834 | ++p; | |||
| 835 | } | |||
| 836 | else | |||
| 837 | { | |||
| 838 | bool bOverFlow = false; | |||
| 839 | long nExp = 0; | |||
| 840 | for (; p != pEnd; ++p) | |||
| 841 | { | |||
| 842 | CharT c = *p; | |||
| 843 | if (!isDigit(c)) | |||
| 844 | break; | |||
| 845 | int i = c - CharT('0'); | |||
| 846 | if ( long10Overflow( nExp, i ) ) | |||
| 847 | bOverFlow = true; | |||
| 848 | else | |||
| 849 | nExp = nExp * 10 + i; | |||
| 850 | } | |||
| 851 | if ( nExp ) | |||
| 852 | { | |||
| 853 | if ( bExpSign ) | |||
| 854 | nExp = -nExp; | |||
| 855 | long nAllExp = ( bOverFlow ? 0 : nExp + nValExp ); | |||
| 856 | if ( nAllExp > DBL_MAX_10_EXP308 || (bOverFlow && !bExpSign) ) | |||
| 857 | { // overflow | |||
| 858 | fVal = HUGE_VAL(__builtin_huge_val()); | |||
| 859 | eStatus = rtl_math_ConversionStatus_OutOfRange; | |||
| 860 | } | |||
| 861 | else if ((nAllExp < DBL_MIN_10_EXP(-307)) || | |||
| 862 | (bOverFlow && bExpSign) ) | |||
| 863 | { // underflow | |||
| 864 | fVal = 0.0; | |||
| 865 | eStatus = rtl_math_ConversionStatus_OutOfRange; | |||
| 866 | } | |||
| 867 | else if ( nExp > DBL_MAX_10_EXP308 || nExp < DBL_MIN_10_EXP(-307) ) | |||
| 868 | { // compensate exponents | |||
| 869 | fVal = rtl::math::pow10Exp( fVal, -nValExp ); | |||
| 870 | fVal = rtl::math::pow10Exp( fVal, nAllExp ); | |||
| 871 | } | |||
| 872 | else | |||
| 873 | fVal = rtl::math::pow10Exp( fVal, nExp ); // normal | |||
| 874 | } | |||
| 875 | } | |||
| 876 | } | |||
| 877 | else if (p - p0 == 2 && p != pEnd && p[0] == CharT('#') | |||
| 878 | && p[-1] == cDecSeparator && p[-2] == CharT('1')) | |||
| 879 | { | |||
| 880 | if (pEnd - p >= 4 && p[1] == CharT('I') && p[2] == CharT('N') | |||
| 881 | && p[3] == CharT('F')) | |||
| 882 | { | |||
| 883 | // "1.#INF", "+1.#INF", "-1.#INF" | |||
| 884 | p += 4; | |||
| 885 | fVal = HUGE_VAL(__builtin_huge_val()); | |||
| 886 | eStatus = rtl_math_ConversionStatus_OutOfRange; | |||
| 887 | // Eat any further digits: | |||
| 888 | while (p != pEnd && isDigit(*p)) | |||
| 889 | ++p; | |||
| 890 | } | |||
| 891 | else if (pEnd - p >= 4 && p[1] == CharT('N') && p[2] == CharT('A') | |||
| 892 | && p[3] == CharT('N')) | |||
| 893 | { | |||
| 894 | // "1.#NAN", "+1.#NAN", "-1.#NAN" | |||
| 895 | p += 4; | |||
| 896 | rtl::math::setNan( &fVal ); | |||
| 897 | if (bSign) | |||
| 898 | { | |||
| 899 | union { | |||
| 900 | double sd; | |||
| 901 | sal_math_Double md; | |||
| 902 | } m; | |||
| 903 | m.sd = fVal; | |||
| 904 | m.md.w32_parts.msw |= 0x80000000; // create negative NaN | |||
| 905 | fVal = m.sd; | |||
| 906 | bSign = false; // don't negate again | |||
| 907 | } | |||
| 908 | // Eat any further digits: | |||
| 909 | while (p != pEnd && isDigit(*p)) | |||
| 910 | ++p; | |||
| 911 | } | |||
| 912 | } | |||
| 913 | } | |||
| 914 | ||||
| 915 | // overflow also if more than DBL_MAX_10_EXP digits without decimal | |||
| 916 | // separator, or 0. and more than DBL_MIN_10_EXP digits, ... | |||
| 917 | bool bHuge = fVal == HUGE_VAL(__builtin_huge_val()); // g++ 3.0.1 requires it this way... | |||
| 918 | if ( bHuge ) | |||
| 919 | eStatus = rtl_math_ConversionStatus_OutOfRange; | |||
| 920 | ||||
| 921 | if ( bSign ) | |||
| 922 | fVal = -fVal; | |||
| 923 | ||||
| 924 | if (pStatus != 0) | |||
| 925 | *pStatus = eStatus; | |||
| 926 | if (pParsedEnd != 0) | |||
| 927 | *pParsedEnd = p == p0 ? pBegin : p; | |||
| 928 | ||||
| 929 | return fVal; | |||
| 930 | } | |||
| 931 | ||||
| 932 | } | |||
| 933 | ||||
| 934 | double SAL_CALL rtl_math_stringToDouble(sal_Char const * pBegin, | |||
| 935 | sal_Char const * pEnd, | |||
| 936 | sal_Char cDecSeparator, | |||
| 937 | sal_Char cGroupSeparator, | |||
| 938 | rtl_math_ConversionStatus * pStatus, | |||
| 939 | sal_Char const ** pParsedEnd) | |||
| 940 | SAL_THROW_EXTERN_C()throw () | |||
| 941 | { | |||
| 942 | return stringToDouble(pBegin, pEnd, cDecSeparator, cGroupSeparator, pStatus, | |||
| 943 | pParsedEnd); | |||
| 944 | } | |||
| 945 | ||||
| 946 | double SAL_CALL rtl_math_uStringToDouble(sal_Unicode const * pBegin, | |||
| 947 | sal_Unicode const * pEnd, | |||
| 948 | sal_Unicode cDecSeparator, | |||
| 949 | sal_Unicode cGroupSeparator, | |||
| 950 | rtl_math_ConversionStatus * pStatus, | |||
| 951 | sal_Unicode const ** pParsedEnd) | |||
| 952 | SAL_THROW_EXTERN_C()throw () | |||
| 953 | { | |||
| 954 | return stringToDouble(pBegin, pEnd, cDecSeparator, cGroupSeparator, pStatus, | |||
| 955 | pParsedEnd); | |||
| 956 | } | |||
| 957 | ||||
| 958 | double SAL_CALL rtl_math_round(double fValue, int nDecPlaces, | |||
| 959 | enum rtl_math_RoundingMode eMode) | |||
| 960 | SAL_THROW_EXTERN_C()throw () | |||
| 961 | { | |||
| 962 | OSL_ASSERT(nDecPlaces >= -20 && nDecPlaces <= 20)do { if (true && (!(nDecPlaces >= -20 && nDecPlaces <= 20))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN ), ("legacy.osl"), ("/usr/local/src/libreoffice/sal/rtl/source/math.cxx" ":" "962" ": "), "OSL_ASSERT: %s", "nDecPlaces >= -20 && nDecPlaces <= 20" ); } } while (false); | |||
| 963 | ||||
| 964 | if ( fValue == 0.0 ) | |||
| 965 | return fValue; | |||
| 966 | ||||
| 967 | // sign adjustment | |||
| 968 | bool bSign = rtl::math::isSignBitSet( fValue ); | |||
| 969 | if ( bSign ) | |||
| 970 | fValue = -fValue; | |||
| 971 | ||||
| 972 | double fFac = 0; | |||
| 973 | if ( nDecPlaces != 0 ) | |||
| 974 | { | |||
| 975 | // max 20 decimals, we don't have unlimited precision | |||
| 976 | // #38810# and no overflow on fValue*=fFac | |||
| 977 | if ( nDecPlaces < -20 || 20 < nDecPlaces || fValue > (DBL_MAX1.7976931348623157e+308 / 1e20) ) | |||
| 978 | return bSign ? -fValue : fValue; | |||
| 979 | ||||
| 980 | fFac = getN10Exp( nDecPlaces ); | |||
| 981 | fValue *= fFac; | |||
| 982 | } | |||
| 983 | //else //! uninitialized fFac, not needed | |||
| 984 | ||||
| 985 | switch ( eMode ) | |||
| 986 | { | |||
| 987 | case rtl_math_RoundingMode_Corrected : | |||
| 988 | { | |||
| 989 | int nExp; // exponent for correction | |||
| 990 | if ( fValue > 0.0 ) | |||
| 991 | nExp = static_cast<int>( floor( log10( fValue ) ) ); | |||
| 992 | else | |||
| 993 | nExp = 0; | |||
| 994 | int nIndex = 15 - nExp; | |||
| 995 | if ( nIndex > 15 ) | |||
| 996 | nIndex = 15; | |||
| 997 | else if ( nIndex <= 1 ) | |||
| 998 | nIndex = 0; | |||
| 999 | fValue = floor( fValue + 0.5 + nKorrVal[nIndex] ); | |||
| 1000 | } | |||
| 1001 | break; | |||
| 1002 | case rtl_math_RoundingMode_Down : | |||
| 1003 | fValue = rtl::math::approxFloor( fValue ); | |||
| 1004 | break; | |||
| 1005 | case rtl_math_RoundingMode_Up : | |||
| 1006 | fValue = rtl::math::approxCeil( fValue ); | |||
| 1007 | break; | |||
| 1008 | case rtl_math_RoundingMode_Floor : | |||
| 1009 | fValue = bSign ? rtl::math::approxCeil( fValue ) | |||
| 1010 | : rtl::math::approxFloor( fValue ); | |||
| 1011 | break; | |||
| 1012 | case rtl_math_RoundingMode_Ceiling : | |||
| 1013 | fValue = bSign ? rtl::math::approxFloor( fValue ) | |||
| 1014 | : rtl::math::approxCeil( fValue ); | |||
| 1015 | break; | |||
| 1016 | case rtl_math_RoundingMode_HalfDown : | |||
| 1017 | { | |||
| 1018 | double f = floor( fValue ); | |||
| 1019 | fValue = ((fValue - f) <= 0.5) ? f : ceil( fValue ); | |||
| 1020 | } | |||
| 1021 | break; | |||
| 1022 | case rtl_math_RoundingMode_HalfUp : | |||
| 1023 | { | |||
| 1024 | double f = floor( fValue ); | |||
| 1025 | fValue = ((fValue - f) < 0.5) ? f : ceil( fValue ); | |||
| 1026 | } | |||
| 1027 | break; | |||
| 1028 | case rtl_math_RoundingMode_HalfEven : | |||
| 1029 | #if defined FLT_ROUNDS(__builtin_flt_rounds()) | |||
| 1030 | /* | |||
| 1031 | Use fast version. FLT_ROUNDS may be defined to a function by some compilers! | |||
| 1032 | ||||
| 1033 | DBL_EPSILON is the smallest fractional number which can be represented, | |||
| 1034 | its reciprocal is therefore the smallest number that cannot have a | |||
| 1035 | fractional part. Once you add this reciprocal to `x', its fractional part | |||
| 1036 | is stripped off. Simply subtracting the reciprocal back out returns `x' | |||
| 1037 | without its fractional component. | |||
| 1038 | Simple, clever, and elegant - thanks to Ross Cottrell, the original author, | |||
| 1039 | who placed it into public domain. | |||
| 1040 | ||||
| 1041 | volatile: prevent compiler from being too smart | |||
| 1042 | */ | |||
| 1043 | if ( FLT_ROUNDS(__builtin_flt_rounds()) == 1 ) | |||
| 1044 | { | |||
| 1045 | volatile double x = fValue + 1.0 / DBL_EPSILON2.2204460492503131e-16; | |||
| 1046 | fValue = x - 1.0 / DBL_EPSILON2.2204460492503131e-16; | |||
| 1047 | } | |||
| 1048 | else | |||
| 1049 | #endif // FLT_ROUNDS | |||
| 1050 | { | |||
| 1051 | double f = floor( fValue ); | |||
| 1052 | if ( (fValue - f) != 0.5 ) | |||
| 1053 | fValue = floor( fValue + 0.5 ); | |||
| 1054 | else | |||
| 1055 | { | |||
| 1056 | double g = f / 2.0; | |||
| 1057 | fValue = (g == floor( g )) ? f : (f + 1.0); | |||
| 1058 | } | |||
| 1059 | } | |||
| 1060 | break; | |||
| 1061 | default: | |||
| 1062 | OSL_ASSERT(false)do { if (true && (!(false))) { sal_detail_logFormat(( SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/usr/local/src/libreoffice/sal/rtl/source/math.cxx" ":" "1062" ": "), "OSL_ASSERT: %s", "false"); } } while (false ); | |||
| 1063 | break; | |||
| 1064 | } | |||
| 1065 | ||||
| 1066 | if ( nDecPlaces != 0 ) | |||
| 1067 | fValue /= fFac; | |||
| 1068 | ||||
| 1069 | return bSign ? -fValue : fValue; | |||
| 1070 | } | |||
| 1071 | ||||
| 1072 | ||||
| 1073 | double SAL_CALL rtl_math_pow10Exp(double fValue, int nExp) SAL_THROW_EXTERN_C()throw () | |||
| 1074 | { | |||
| 1075 | return fValue * getN10Exp( nExp ); | |||
| 1076 | } | |||
| 1077 | ||||
| 1078 | ||||
| 1079 | double SAL_CALL rtl_math_approxValue( double fValue ) SAL_THROW_EXTERN_C()throw () | |||
| 1080 | { | |||
| 1081 | if (fValue == 0.0 || fValue == HUGE_VAL(__builtin_huge_val()) || !::rtl::math::isFinite( fValue)) | |||
| 1082 | // We don't handle these conditions. Bail out. | |||
| 1083 | return fValue; | |||
| 1084 | ||||
| 1085 | double fOrigValue = fValue; | |||
| 1086 | ||||
| 1087 | bool bSign = ::rtl::math::isSignBitSet( fValue); | |||
| 1088 | if (bSign) | |||
| 1089 | fValue = -fValue; | |||
| 1090 | ||||
| 1091 | int nExp = static_cast<int>( floor( log10( fValue))); | |||
| 1092 | nExp = 14 - nExp; | |||
| 1093 | double fExpValue = getN10Exp( nExp); | |||
| 1094 | ||||
| 1095 | fValue *= fExpValue; | |||
| 1096 | // If the original value was near DBL_MIN we got an overflow. Restore and | |||
| 1097 | // bail out. | |||
| 1098 | if (!rtl::math::isFinite( fValue)) | |||
| 1099 | return fOrigValue; | |||
| 1100 | fValue = rtl_math_round( fValue, 0, rtl_math_RoundingMode_Corrected); | |||
| 1101 | fValue /= fExpValue; | |||
| 1102 | // If the original value was near DBL_MAX we got an overflow. Restore and | |||
| 1103 | // bail out. | |||
| 1104 | if (!rtl::math::isFinite( fValue)) | |||
| 1105 | return fOrigValue; | |||
| 1106 | ||||
| 1107 | return bSign ? -fValue : fValue; | |||
| 1108 | } | |||
| 1109 | ||||
| 1110 | ||||
| 1111 | double SAL_CALL rtl_math_expm1( double fValue ) SAL_THROW_EXTERN_C()throw () | |||
| 1112 | { | |||
| 1113 | double fe = exp( fValue ); | |||
| 1114 | if (fe == 1.0) | |||
| 1115 | return fValue; | |||
| 1116 | if (fe-1.0 == -1.0) | |||
| 1117 | return -1.0; | |||
| 1118 | return (fe-1.0) * fValue / log(fe); | |||
| 1119 | } | |||
| 1120 | ||||
| 1121 | ||||
| 1122 | double SAL_CALL rtl_math_log1p( double fValue ) SAL_THROW_EXTERN_C()throw () | |||
| 1123 | { | |||
| 1124 | // Use volatile because a compiler may be too smart "optimizing" the | |||
| 1125 | // condition such that in certain cases the else path was called even if | |||
| 1126 | // (fp==1.0) was true, where the term (fp-1.0) then resulted in 0.0 and | |||
| 1127 | // hence the entire expression resulted in NaN. | |||
| 1128 | // Happened with g++ 3.4.1 and an input value of 9.87E-18 | |||
| 1129 | volatile double fp = 1.0 + fValue; | |||
| 1130 | if (fp == 1.0) | |||
| 1131 | return fValue; | |||
| 1132 | else | |||
| 1133 | return log(fp) * fValue / (fp-1.0); | |||
| 1134 | } | |||
| 1135 | ||||
| 1136 | ||||
| 1137 | double SAL_CALL rtl_math_atanh( double fValue ) SAL_THROW_EXTERN_C()throw () | |||
| 1138 | { | |||
| 1139 | return 0.5 * rtl_math_log1p( 2.0 * fValue / (1.0-fValue) ); | |||
| 1140 | } | |||
| 1141 | ||||
| 1142 | ||||
| 1143 | /** Parent error function (erf) that calls different algorithms based on the | |||
| 1144 | value of x. It takes care of cases where x is negative as erf is an odd | |||
| 1145 | function i.e. erf(-x) = -erf(x). | |||
| 1146 | ||||
| 1147 | Kramer, W., and Blomquist, F., 2000, Algorithms with Guaranteed Error Bounds | |||
| 1148 | for the Error Function and the Complementary Error Function | |||
| 1149 | ||||
| 1150 | http://www.math.uni-wuppertal.de/wrswt/literatur_en.html | |||
| 1151 | ||||
| 1152 | @author Kohei Yoshida <kohei@openoffice.org> | |||
| 1153 | ||||
| 1154 | @see #i55735# | |||
| 1155 | */ | |||
| 1156 | double SAL_CALL rtl_math_erf( double x ) SAL_THROW_EXTERN_C()throw () | |||
| 1157 | { | |||
| 1158 | if( x == 0.0 ) | |||
| 1159 | return 0.0; | |||
| 1160 | ||||
| 1161 | bool bNegative = false; | |||
| 1162 | if ( x < 0.0 ) | |||
| 1163 | { | |||
| 1164 | x = fabs( x ); | |||
| 1165 | bNegative = true; | |||
| 1166 | } | |||
| 1167 | ||||
| 1168 | double fErf = 1.0; | |||
| 1169 | if ( x < 1.0e-10 ) | |||
| 1170 | fErf = (double) (x*1.1283791670955125738961589031215452L); | |||
| 1171 | else if ( x < 0.65 ) | |||
| 1172 | lcl_Erf0065( x, fErf ); | |||
| 1173 | else | |||
| 1174 | fErf = 1.0 - rtl_math_erfc( x ); | |||
| 1175 | ||||
| 1176 | if ( bNegative ) | |||
| 1177 | fErf *= -1.0; | |||
| 1178 | ||||
| 1179 | return fErf; | |||
| 1180 | } | |||
| 1181 | ||||
| 1182 | ||||
| 1183 | /** Parent complementary error function (erfc) that calls different algorithms | |||
| 1184 | based on the value of x. It takes care of cases where x is negative as erfc | |||
| 1185 | satisfies relationship erfc(-x) = 2 - erfc(x). See the comment for Erf(x) | |||
| 1186 | for the source publication. | |||
| 1187 | ||||
| 1188 | @author Kohei Yoshida <kohei@openoffice.org> | |||
| 1189 | ||||
| 1190 | @see #i55735#, moved from module scaddins (#i97091#) | |||
| 1191 | ||||
| 1192 | */ | |||
| 1193 | double SAL_CALL rtl_math_erfc( double x ) SAL_THROW_EXTERN_C()throw () | |||
| 1194 | { | |||
| 1195 | if ( x == 0.0 ) | |||
| 1196 | return 1.0; | |||
| 1197 | ||||
| 1198 | bool bNegative = false; | |||
| 1199 | if ( x < 0.0 ) | |||
| 1200 | { | |||
| 1201 | x = fabs( x ); | |||
| 1202 | bNegative = true; | |||
| 1203 | } | |||
| 1204 | ||||
| 1205 | double fErfc = 0.0; | |||
| 1206 | if ( x >= 0.65 ) | |||
| 1207 | { | |||
| 1208 | if ( x < 6.0 ) | |||
| 1209 | lcl_Erfc0600( x, fErfc ); | |||
| 1210 | else | |||
| 1211 | lcl_Erfc2654( x, fErfc ); | |||
| 1212 | } | |||
| 1213 | else | |||
| 1214 | fErfc = 1.0 - rtl_math_erf( x ); | |||
| 1215 | ||||
| 1216 | if ( bNegative ) | |||
| 1217 | fErfc = 2.0 - fErfc; | |||
| 1218 | ||||
| 1219 | return fErfc; | |||
| 1220 | } | |||
| 1221 | ||||
| 1222 | /** improved accuracy of asinh for |x| large and for x near zero | |||
| 1223 | @see #i97605# | |||
| 1224 | */ | |||
| 1225 | double SAL_CALL rtl_math_asinh( double fX ) SAL_THROW_EXTERN_C()throw () | |||
| 1226 | { | |||
| 1227 | if ( fX == 0.0 ) | |||
| 1228 | return 0.0; | |||
| 1229 | else | |||
| 1230 | { | |||
| 1231 | double fSign = 1.0; | |||
| 1232 | if ( fX < 0.0 ) | |||
| 1233 | { | |||
| 1234 | fX = - fX; | |||
| 1235 | fSign = -1.0; | |||
| 1236 | } | |||
| 1237 | if ( fX < 0.125 ) | |||
| 1238 | return fSign * rtl_math_log1p( fX + fX*fX / (1.0 + sqrt( 1.0 + fX*fX))); | |||
| 1239 | else if ( fX < 1.25e7 ) | |||
| 1240 | return fSign * log( fX + sqrt( 1.0 + fX*fX)); | |||
| 1241 | else | |||
| 1242 | return fSign * log( 2.0*fX); | |||
| 1243 | } | |||
| 1244 | } | |||
| 1245 | ||||
| 1246 | /** improved accuracy of acosh for x large and for x near 1 | |||
| 1247 | @see #i97605# | |||
| 1248 | */ | |||
| 1249 | double SAL_CALL rtl_math_acosh( double fX ) SAL_THROW_EXTERN_C()throw () | |||
| 1250 | { | |||
| 1251 | volatile double fZ = fX - 1.0; | |||
| 1252 | if ( fX < 1.0 ) | |||
| 1253 | { | |||
| 1254 | double fResult; | |||
| 1255 | ::rtl::math::setNan( &fResult ); | |||
| 1256 | return fResult; | |||
| 1257 | } | |||
| 1258 | else if ( fX == 1.0 ) | |||
| 1259 | return 0.0; | |||
| 1260 | else if ( fX < 1.1 ) | |||
| 1261 | return rtl_math_log1p( fZ + sqrt( fZ*fZ + 2.0*fZ)); | |||
| 1262 | else if ( fX < 1.25e7 ) | |||
| 1263 | return log( fX + sqrt( fX*fX - 1.0)); | |||
| 1264 | else | |||
| 1265 | return log( 2.0*fX); | |||
| 1266 | } | |||
| 1267 | ||||
| 1268 | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |