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 */
doubleToString(double fValue,rtl_math_StringFormat eFormat,sal_Int32 nDecPlaces,sal_Char cDecSeparator,sal_Int32 const * pGroups,sal_Char cGroupSeparator,bool bEraseTrailingDecZeros=false)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 */
doubleToString(double fValue,rtl_math_StringFormat eFormat,sal_Int32 nDecPlaces,sal_Char cDecSeparator,bool bEraseTrailingDecZeros=false)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 */
doubleToUString(double fValue,rtl_math_StringFormat eFormat,sal_Int32 nDecPlaces,sal_Unicode cDecSeparator,sal_Int32 const * pGroups,sal_Unicode cGroupSeparator,bool bEraseTrailingDecZeros=false)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 */
doubleToUString(double fValue,rtl_math_StringFormat eFormat,sal_Int32 nDecPlaces,sal_Unicode cDecSeparator,bool bEraseTrailingDecZeros=false)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 */
doubleToUStringBuffer(rtl::OUStringBuffer & rBuffer,double fValue,rtl_math_StringFormat eFormat,sal_Int32 nDecPlaces,sal_Unicode cDecSeparator,sal_Int32 const * pGroups,sal_Unicode cGroupSeparator,bool bEraseTrailingDecZeros=false)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 */
doubleToUStringBuffer(rtl::OUStringBuffer & rBuffer,double fValue,rtl_math_StringFormat eFormat,sal_Int32 nDecPlaces,sal_Unicode cDecSeparator,bool bEraseTrailingDecZeros=false)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 */
stringToDouble(rtl::OString const & rString,sal_Char cDecSeparator,sal_Char cGroupSeparator,rtl_math_ConversionStatus * pStatus,sal_Int32 * pParsedEnd)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 */
stringToDouble(rtl::OUString const & rString,sal_Unicode cDecSeparator,sal_Unicode cGroupSeparator,rtl_math_ConversionStatus * pStatus,sal_Int32 * pParsedEnd)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 */
round(double fValue,int nDecPlaces=0,rtl_math_RoundingMode eMode=rtl_math_RoundingMode_Corrected)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 */
pow10Exp(double fValue,int nExp)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 */
approxValue(double fValue)191 inline double approxValue(double fValue)
192 {
193 return rtl_math_approxValue(fValue);
194 }
195
196 /** A wrapper around rtl_math_expm1.
197 */
expm1(double fValue)198 inline double expm1(double fValue)
199 {
200 return rtl_math_expm1(fValue);
201 }
202
203 /** A wrapper around rtl_math_log1p.
204 */
log1p(double fValue)205 inline double log1p(double fValue)
206 {
207 return rtl_math_log1p(fValue);
208 }
209
210 /** A wrapper around rtl_math_atanh.
211 */
atanh(double fValue)212 inline double atanh(double fValue)
213 {
214 return rtl_math_atanh(fValue);
215 }
216
217 /** A wrapper around rtl_math_erf.
218 */
erf(double fValue)219 inline double erf(double fValue)
220 {
221 return rtl_math_erf(fValue);
222 }
223
224 /** A wrapper around rtl_math_erfc.
225 */
erfc(double fValue)226 inline double erfc(double fValue)
227 {
228 return rtl_math_erfc(fValue);
229 }
230
231 /** A wrapper around rtl_math_asinh.
232 */
asinh(double fValue)233 inline double asinh(double fValue)
234 {
235 return rtl_math_asinh(fValue);
236 }
237
238 /** A wrapper around rtl_math_acosh.
239 */
acosh(double fValue)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 */
approxEqual(double a,double b)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 */
approxAdd(double a,double b)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 */
approxSub(double a,double b)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 */
approxFloor(double a)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 */
approxCeil(double a)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 */
isFinite(double d)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 */
isInf(double d)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 */
isNan(double d)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 */
isSignBitSet(double d)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 */
setInf(double * pd,bool bNegative)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 */
setNan(double * pd)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 */
isValidArcArg(double d)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 */
sin(double d)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 */
cos(double d)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 */
tan(double d)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