1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 24 #if !defined INCLUDED_RTL_MATH_HXX 25 #define INCLUDED_RTL_MATH_HXX 26 27 #include "rtl/math.h" 28 #include "rtl/string.hxx" 29 #include "rtl/ustring.hxx" 30 #include "rtl/ustrbuf.hxx" 31 #include "sal/mathconf.h" 32 #include "sal/types.h" 33 34 #include <math.h> 35 36 namespace rtl { 37 38 namespace math { 39 40 /** A wrapper around rtl_math_doubleToString. 41 */ 42 inline rtl::OString doubleToString(double fValue, rtl_math_StringFormat eFormat, 43 sal_Int32 nDecPlaces, 44 sal_Char cDecSeparator, 45 sal_Int32 const * pGroups, 46 sal_Char cGroupSeparator, 47 bool bEraseTrailingDecZeros = false) 48 { 49 rtl::OString aResult; 50 rtl_math_doubleToString(&aResult.pData, 0, 0, fValue, eFormat, nDecPlaces, 51 cDecSeparator, pGroups, cGroupSeparator, 52 bEraseTrailingDecZeros); 53 return aResult; 54 } 55 56 /** A wrapper around rtl_math_doubleToString, with no grouping. 57 */ 58 inline rtl::OString doubleToString(double fValue, rtl_math_StringFormat eFormat, 59 sal_Int32 nDecPlaces, 60 sal_Char cDecSeparator, 61 bool bEraseTrailingDecZeros = false) 62 { 63 rtl::OString aResult; 64 rtl_math_doubleToString(&aResult.pData, 0, 0, fValue, eFormat, nDecPlaces, 65 cDecSeparator, 0, 0, bEraseTrailingDecZeros); 66 return aResult; 67 } 68 69 /** A wrapper around rtl_math_doubleToUString. 70 */ 71 inline rtl::OUString doubleToUString(double fValue, 72 rtl_math_StringFormat eFormat, 73 sal_Int32 nDecPlaces, 74 sal_Unicode cDecSeparator, 75 sal_Int32 const * pGroups, 76 sal_Unicode cGroupSeparator, 77 bool bEraseTrailingDecZeros = false) 78 { 79 rtl::OUString aResult; 80 rtl_math_doubleToUString(&aResult.pData, 0, 0, fValue, eFormat, nDecPlaces, 81 cDecSeparator, pGroups, cGroupSeparator, 82 bEraseTrailingDecZeros); 83 return aResult; 84 } 85 86 /** A wrapper around rtl_math_doubleToUString, with no grouping. 87 */ 88 inline rtl::OUString doubleToUString(double fValue, 89 rtl_math_StringFormat eFormat, 90 sal_Int32 nDecPlaces, 91 sal_Unicode cDecSeparator, 92 bool bEraseTrailingDecZeros = false) 93 { 94 rtl::OUString aResult; 95 rtl_math_doubleToUString(&aResult.pData, 0, 0, fValue, eFormat, nDecPlaces, 96 cDecSeparator, 0, 0, bEraseTrailingDecZeros); 97 return aResult; 98 } 99 100 /** A wrapper around rtl_math_doubleToUString that appends to an 101 rtl::OUStringBuffer. 102 */ 103 inline void doubleToUStringBuffer( rtl::OUStringBuffer& rBuffer, double fValue, 104 rtl_math_StringFormat eFormat, 105 sal_Int32 nDecPlaces, 106 sal_Unicode cDecSeparator, 107 sal_Int32 const * pGroups, 108 sal_Unicode cGroupSeparator, 109 bool bEraseTrailingDecZeros = false) 110 { 111 rtl_uString ** pData; 112 sal_Int32 * pCapacity; 113 rBuffer.accessInternals( &pData, &pCapacity ); 114 rtl_math_doubleToUString( pData, pCapacity, rBuffer.getLength(), fValue, 115 eFormat, nDecPlaces, cDecSeparator, pGroups, 116 cGroupSeparator, bEraseTrailingDecZeros); 117 } 118 119 /** A wrapper around rtl_math_doubleToUString that appends to an 120 rtl::OUStringBuffer, with no grouping. 121 */ 122 inline void doubleToUStringBuffer( rtl::OUStringBuffer& rBuffer, double fValue, 123 rtl_math_StringFormat eFormat, 124 sal_Int32 nDecPlaces, 125 sal_Unicode cDecSeparator, 126 bool bEraseTrailingDecZeros = false) 127 { 128 rtl_uString ** pData; 129 sal_Int32 * pCapacity; 130 rBuffer.accessInternals( &pData, &pCapacity ); 131 rtl_math_doubleToUString( pData, pCapacity, rBuffer.getLength(), fValue, 132 eFormat, nDecPlaces, cDecSeparator, 0, 0, 133 bEraseTrailingDecZeros); 134 } 135 136 /** A wrapper around rtl_math_stringToDouble. 137 */ 138 inline double stringToDouble(rtl::OString const & rString, 139 sal_Char cDecSeparator, sal_Char cGroupSeparator, 140 rtl_math_ConversionStatus * pStatus, 141 sal_Int32 * pParsedEnd) 142 { 143 sal_Char const * pBegin = rString.getStr(); 144 sal_Char const * pEnd; 145 double fResult = rtl_math_stringToDouble(pBegin, 146 pBegin + rString.getLength(), 147 cDecSeparator, cGroupSeparator, 148 pStatus, &pEnd); 149 if (pParsedEnd != 0) 150 *pParsedEnd = (sal_Int32)(pEnd - pBegin); 151 return fResult; 152 } 153 154 /** A wrapper around rtl_math_uStringToDouble. 155 */ 156 inline double stringToDouble(rtl::OUString const & rString, 157 sal_Unicode cDecSeparator, 158 sal_Unicode cGroupSeparator, 159 rtl_math_ConversionStatus * pStatus, 160 sal_Int32 * pParsedEnd) 161 { 162 sal_Unicode const * pBegin = rString.getStr(); 163 sal_Unicode const * pEnd; 164 double fResult = rtl_math_uStringToDouble(pBegin, 165 pBegin + rString.getLength(), 166 cDecSeparator, cGroupSeparator, 167 pStatus, &pEnd); 168 if (pParsedEnd != 0) 169 *pParsedEnd = (sal_Int32)(pEnd - pBegin); 170 return fResult; 171 } 172 173 /** A wrapper around rtl_math_round. 174 */ 175 inline double round( 176 double fValue, int nDecPlaces = 0, 177 rtl_math_RoundingMode eMode = rtl_math_RoundingMode_Corrected) 178 { 179 return rtl_math_round(fValue, nDecPlaces, eMode); 180 } 181 182 /** A wrapper around rtl_math_pow10Exp. 183 */ 184 inline double pow10Exp(double fValue, int nExp) 185 { 186 return rtl_math_pow10Exp(fValue, nExp); 187 } 188 189 /** A wrapper around rtl_math_approxValue. 190 */ 191 inline double approxValue(double fValue) 192 { 193 return rtl_math_approxValue(fValue); 194 } 195 196 /** A wrapper around rtl_math_expm1. 197 */ 198 inline double expm1(double fValue) 199 { 200 return rtl_math_expm1(fValue); 201 } 202 203 /** A wrapper around rtl_math_log1p. 204 */ 205 inline double log1p(double fValue) 206 { 207 return rtl_math_log1p(fValue); 208 } 209 210 /** A wrapper around rtl_math_atanh. 211 */ 212 inline double atanh(double fValue) 213 { 214 return rtl_math_atanh(fValue); 215 } 216 217 /** A wrapper around rtl_math_erf. 218 */ 219 inline double erf(double fValue) 220 { 221 return rtl_math_erf(fValue); 222 } 223 224 /** A wrapper around rtl_math_erfc. 225 */ 226 inline double erfc(double fValue) 227 { 228 return rtl_math_erfc(fValue); 229 } 230 231 /** A wrapper around rtl_math_asinh. 232 */ 233 inline double asinh(double fValue) 234 { 235 return rtl_math_asinh(fValue); 236 } 237 238 /** A wrapper around rtl_math_acosh. 239 */ 240 inline double acosh(double fValue) 241 { 242 return rtl_math_acosh(fValue); 243 } 244 245 246 /** Test equality of two values with an accuracy of the magnitude of the 247 given values scaled by 2^-48 (4 bits roundoff stripped). 248 249 @ATTENTION 250 approxEqual( value!=0.0, 0.0 ) _never_ yields true. 251 */ 252 inline bool approxEqual(double a, double b) 253 { 254 if ( a == b ) 255 return true; 256 double x = a - b; 257 return (x < 0.0 ? -x : x) 258 < ((a < 0.0 ? -a : a) * (1.0 / (16777216.0 * 16777216.0))); 259 } 260 261 /** Add two values. 262 263 If signs differ and the absolute values are equal according to approxEqual() 264 the method returns 0.0 instead of calculating the sum. 265 266 If you wanted to sum up multiple values it would be convenient not to call 267 approxAdd() for each value but instead remember the first value not equal to 268 0.0, add all other values using normal + operator, and with the result and 269 the remembered value call approxAdd(). 270 */ 271 inline double approxAdd(double a, double b) 272 { 273 if ( ((a < 0.0 && b > 0.0) || (b < 0.0 && a > 0.0)) 274 && approxEqual( a, -b ) ) 275 return 0.0; 276 return a + b; 277 } 278 279 /** Substract two values (a-b). 280 281 If signs are identical and the values are equal according to approxEqual() 282 the method returns 0.0 instead of calculating the substraction. 283 */ 284 inline double approxSub(double a, double b) 285 { 286 if ( ((a < 0.0 && b < 0.0) || (a > 0.0 && b > 0.0)) && approxEqual( a, b ) ) 287 return 0.0; 288 return a - b; 289 } 290 291 /** floor() method taking approxValue() into account. 292 293 Use for expected integer values being calculated by double functions. 294 */ 295 inline double approxFloor(double a) 296 { 297 return floor( approxValue( a )); 298 } 299 300 /** ceil() method taking approxValue() into account. 301 302 Use for expected integer values being calculated by double functions. 303 */ 304 inline double approxCeil(double a) 305 { 306 return ceil( approxValue( a )); 307 } 308 309 /** Tests whether a value is neither INF nor NAN. 310 */ 311 inline bool isFinite(double d) 312 { 313 return SAL_MATH_FINITE(d) != 0; 314 } 315 316 /** If a value represents +INF or -INF. 317 318 The sign bit may be queried with isSignBitSet(). 319 320 If isFinite(d)==false and isInf(d)==false then NAN. 321 */ 322 inline bool isInf(double d) 323 { 324 // exponent==0x7ff fraction==0 325 return (SAL_MATH_FINITE(d) == 0) && 326 (reinterpret_cast< sal_math_Double * >(&d)->inf_parts.fraction_hi == 0) 327 && (reinterpret_cast< sal_math_Double * >(&d)->inf_parts.fraction_lo 328 == 0); 329 } 330 331 /** Test on any QNAN or SNAN. 332 */ 333 inline bool isNan(double d) 334 { 335 // exponent==0x7ff fraction!=0 336 return (SAL_MATH_FINITE(d) == 0) && ( 337 (reinterpret_cast< sal_math_Double * >(&d)->inf_parts.fraction_hi != 0) 338 || (reinterpret_cast< sal_math_Double * >(&d)->inf_parts.fraction_lo 339 != 0) ); 340 } 341 342 /** If the sign bit is set. 343 */ 344 inline bool isSignBitSet(double d) 345 { 346 return reinterpret_cast< sal_math_Double * >(&d)->inf_parts.sign != 0; 347 } 348 349 /** Set to +INF if bNegative==false or -INF if bNegative==true. 350 */ 351 inline void setInf(double * pd, bool bNegative) 352 { 353 union 354 { 355 double sd; 356 sal_math_Double md; 357 }; 358 md.w32_parts.msw = bNegative ? 0xFFF00000 : 0x7FF00000; 359 md.w32_parts.lsw = 0; 360 *pd = sd; 361 } 362 363 /** Set a QNAN. 364 */ 365 inline void setNan(double * pd) 366 { 367 union 368 { 369 double sd; 370 sal_math_Double md; 371 }; 372 md.w32_parts.msw = 0x7FFFFFFF; 373 md.w32_parts.lsw = 0xFFFFFFFF; 374 *pd = sd; 375 } 376 377 /** If a value is a valid argument for sin(), cos(), tan(). 378 379 IEEE 754 specifies that absolute values up to 2^64 (=1.844e19) for the 380 radian must be supported by trigonometric functions. Unfortunately, at 381 least on x86 architectures, the FPU doesn't generate an error pattern for 382 values >2^64 but produces erroneous results instead and sets only the 383 "invalid operation" (IM) flag in the status word :-( Thus the application 384 has to handle it itself. 385 */ 386 inline bool isValidArcArg(double d) 387 { 388 return fabs(d) 389 <= (static_cast< double >(static_cast< unsigned long >(0x80000000)) 390 * static_cast< double >(static_cast< unsigned long >(0x80000000)) 391 * 2); 392 } 393 394 /** Safe sin(), returns NAN if not valid. 395 */ 396 inline double sin(double d) 397 { 398 if ( isValidArcArg( d ) ) 399 return ::sin( d ); 400 setNan( &d ); 401 return d; 402 } 403 404 /** Safe cos(), returns NAN if not valid. 405 */ 406 inline double cos(double d) 407 { 408 if ( isValidArcArg( d ) ) 409 return ::cos( d ); 410 setNan( &d ); 411 return d; 412 } 413 414 /** Safe tan(), returns NAN if not valid. 415 */ 416 inline double tan(double d) 417 { 418 if ( isValidArcArg( d ) ) 419 return ::tan( d ); 420 setNan( &d ); 421 return d; 422 } 423 424 } 425 426 } 427 428 #endif // INCLUDED_RTL_MATH_HXX 429