xref: /aoo41x/main/sal/inc/rtl/math.hxx (revision a067bd65)
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