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