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_powr. 190 */ 191 inline double powr(double fValue, int fExp) 192 { 193 return rtl_math_powr(fValue, fExp); 194 } 195 196 /** A wrapper around rtl_math_approxValue. 197 */ 198 inline double approxValue(double fValue) 199 { 200 return rtl_math_approxValue(fValue); 201 } 202 203 /** A wrapper around rtl_math_expm1. 204 */ 205 inline double expm1(double fValue) 206 { 207 return rtl_math_expm1(fValue); 208 } 209 210 /** A wrapper around rtl_math_log1p. 211 */ 212 inline double log1p(double fValue) 213 { 214 return rtl_math_log1p(fValue); 215 } 216 217 /** A wrapper around rtl_math_atanh. 218 */ 219 inline double atanh(double fValue) 220 { 221 return rtl_math_atanh(fValue); 222 } 223 224 /** A wrapper around rtl_math_erf. 225 */ 226 inline double erf(double fValue) 227 { 228 return rtl_math_erf(fValue); 229 } 230 231 /** A wrapper around rtl_math_erfc. 232 */ 233 inline double erfc(double fValue) 234 { 235 return rtl_math_erfc(fValue); 236 } 237 238 /** A wrapper around rtl_math_asinh. 239 */ 240 inline double asinh(double fValue) 241 { 242 return rtl_math_asinh(fValue); 243 } 244 245 /** A wrapper around rtl_math_acosh. 246 */ 247 inline double acosh(double fValue) 248 { 249 return rtl_math_acosh(fValue); 250 } 251 252 253 /** Test equality of two values with an accuracy of the magnitude of the 254 given values scaled by 2^-48 (4 bits roundoff stripped). 255 256 @ATTENTION 257 approxEqual( value!=0.0, 0.0 ) _never_ yields true. 258 */ 259 inline bool approxEqual(double a, double b) 260 { 261 if ( a == b ) 262 return true; 263 double x = a - b; 264 return (x < 0.0 ? -x : x) 265 < ((a < 0.0 ? -a : a) * (1.0 / (16777216.0 * 16777216.0))); 266 } 267 268 /** Add two values. 269 270 If signs differ and the absolute values are equal according to approxEqual() 271 the method returns 0.0 instead of calculating the sum. 272 273 If you wanted to sum up multiple values it would be convenient not to call 274 approxAdd() for each value but instead remember the first value not equal to 275 0.0, add all other values using normal + operator, and with the result and 276 the remembered value call approxAdd(). 277 */ 278 inline double approxAdd(double a, double b) 279 { 280 if ( ((a < 0.0 && b > 0.0) || (b < 0.0 && a > 0.0)) 281 && approxEqual( a, -b ) ) 282 return 0.0; 283 return a + b; 284 } 285 286 /** Substract two values (a-b). 287 288 If signs are identical and the values are equal according to approxEqual() 289 the method returns 0.0 instead of calculating the substraction. 290 */ 291 inline double approxSub(double a, double b) 292 { 293 if ( ((a < 0.0 && b < 0.0) || (a > 0.0 && b > 0.0)) && approxEqual( a, b ) ) 294 return 0.0; 295 return a - b; 296 } 297 298 /** floor() method taking approxValue() into account. 299 300 Use for expected integer values being calculated by double functions. 301 */ 302 inline double approxFloor(double a) 303 { 304 return floor( approxValue( a )); 305 } 306 307 /** ceil() method taking approxValue() into account. 308 309 Use for expected integer values being calculated by double functions. 310 */ 311 inline double approxCeil(double a) 312 { 313 return ceil( approxValue( a )); 314 } 315 316 /** Tests whether a value is neither INF nor NAN. 317 */ 318 inline bool isFinite(double d) 319 { 320 return SAL_MATH_FINITE(d) != 0; 321 } 322 323 /** If a value represents +INF or -INF. 324 325 The sign bit may be queried with isSignBitSet(). 326 327 If isFinite(d)==false and isInf(d)==false then NAN. 328 */ 329 inline bool isInf(double d) 330 { 331 // exponent==0x7ff fraction==0 332 return (SAL_MATH_FINITE(d) == 0) && 333 (reinterpret_cast< sal_math_Double * >(&d)->inf_parts.fraction_hi == 0) 334 && (reinterpret_cast< sal_math_Double * >(&d)->inf_parts.fraction_lo 335 == 0); 336 } 337 338 /** Test on any QNAN or SNAN. 339 */ 340 inline bool isNan(double d) 341 { 342 // exponent==0x7ff fraction!=0 343 return (SAL_MATH_FINITE(d) == 0) && ( 344 (reinterpret_cast< sal_math_Double * >(&d)->inf_parts.fraction_hi != 0) 345 || (reinterpret_cast< sal_math_Double * >(&d)->inf_parts.fraction_lo 346 != 0) ); 347 } 348 349 /** If the sign bit is set. 350 */ 351 inline bool isSignBitSet(double d) 352 { 353 return reinterpret_cast< sal_math_Double * >(&d)->inf_parts.sign != 0; 354 } 355 356 /** Set to +INF if bNegative==false or -INF if bNegative==true. 357 */ 358 inline void setInf(double * pd, bool bNegative) 359 { 360 union 361 { 362 double sd; 363 sal_math_Double md; 364 }; 365 md.w32_parts.msw = bNegative ? 0xFFF00000 : 0x7FF00000; 366 md.w32_parts.lsw = 0; 367 *pd = sd; 368 } 369 370 /** Set a QNAN. 371 */ 372 inline void setNan(double * pd) 373 { 374 union 375 { 376 double sd; 377 sal_math_Double md; 378 }; 379 md.w32_parts.msw = 0x7FFFFFFF; 380 md.w32_parts.lsw = 0xFFFFFFFF; 381 *pd = sd; 382 } 383 384 /** If a value is a valid argument for sin(), cos(), tan(). 385 386 IEEE 754 specifies that absolute values up to 2^64 (=1.844e19) for the 387 radian must be supported by trigonometric functions. Unfortunately, at 388 least on x86 architectures, the FPU doesn't generate an error pattern for 389 values >2^64 but produces erroneous results instead and sets only the 390 "invalid operation" (IM) flag in the status word :-( Thus the application 391 has to handle it itself. 392 */ 393 inline bool isValidArcArg(double d) 394 { 395 return fabs(d) 396 <= (static_cast< double >(static_cast< unsigned long >(0x80000000)) 397 * static_cast< double >(static_cast< unsigned long >(0x80000000)) 398 * 2); 399 } 400 401 /** Safe sin(), returns NAN if not valid. 402 */ 403 inline double sin(double d) 404 { 405 if ( isValidArcArg( d ) ) 406 return ::sin( d ); 407 setNan( &d ); 408 return d; 409 } 410 411 /** Safe cos(), returns NAN if not valid. 412 */ 413 inline double cos(double d) 414 { 415 if ( isValidArcArg( d ) ) 416 return ::cos( d ); 417 setNan( &d ); 418 return d; 419 } 420 421 /** Safe tan(), returns NAN if not valid. 422 */ 423 inline double tan(double d) 424 { 425 if ( isValidArcArg( d ) ) 426 return ::tan( d ); 427 setNan( &d ); 428 return d; 429 } 430 431 } 432 433 } 434 435 #endif // INCLUDED_RTL_MATH_HXX 436